在MVC4中,如何将文件(图像)上传到属于我的域模型的SQL Server?

Mik*_*rks 5 c# sql-server asp.net asp.net-mvc file-upload

我对MVC比较陌生,而且我从来不必处理将文件(特别是图像)上传到SQL Server数据库的问题.说实话,我不知道我在这里做什么.

以下是我到目前为止的内容 - 这是我的域模型(请注意HttpPostedFileBase我的模型 - 这是我要上传的内容):

public class Profile
{
    [Key]
    public int Id { get; set; }

    [Required(ErrorMessage="Years of service is required")]
    [DisplayName("Years Service:")]
    public int YearsService { get; set; }

    [DataType(DataType.MultilineText)]
    [DisplayName("Notable Achivements:")]
    public string NotableAchivements { get; set; }

    [Required(ErrorMessage = "Technical skills are required")]
    [DataType(DataType.MultilineText)]
    [DisplayName("Technical Skills:")]
    public string TechnicalSkills { get; set; }

    [DisplayName("Upload Image: ")]
    public HttpPostedFileBase Photo { get; set; }

    public string CreatedBy { get; set; }
    public DateTime CreatedDate { get; set; }
    public string ModifiedBy { get; set; }
    public DateTime ModifiedDate { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

这是我的看法:

@using (Html.BeginForm("Create", "Profiles", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
<div class="editor-label">
    @Html.LabelFor(model => model.YearsService)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.YearsService)
    @Html.ValidationMessageFor(model => model.YearsService)
</div>

<div class="editor-label">
    @Html.LabelFor(model => model.NotableAchivements)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.NotableAchivements)
    @Html.ValidationMessageFor(model => model.NotableAchivements)
</div>

<div class="editor-label">
    @Html.LabelFor(model => model.TechnicalSkills)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.TechnicalSkills)
    @Html.ValidationMessageFor(model => model.TechnicalSkills)
</div>

<input type="file" name="photo" />
<input type="submit" name="Submit" id="Submit" value="Upload" />
}
Run Code Online (Sandbox Code Playgroud)

我希望有一些明显的事情我做错了.任何人都可以提供有关如何将简单文件上传到SQL Server数据库的建议吗?

Chr*_*att 8

首先,不要将图像保存到数据库中.网上有无数的"指南",建议在MSSQL中使用字节数组或"图像"类型.数据库不用于二进制数据存储.当然,它们可以容纳二进制存储,但仅仅因为你可以使用AR-15射击自己,并不意味着你应该.

而是将图像存储在它所属的位置:文件系统.然后,仅仅在数据库中引用它的路径.

现在,处理所有这些的最简单方法是使用视图模型.如果您还没有使用视图模型,那么现在是开始的好时机.通常,您不希望将实际的数据库支持的模型直接发送到视图.在表单中,恶意用户可能存在各种令人讨厌的数据篡改,即使在简单的视图中,您通常也会传递超出他们需要的数据.

因此,第一步是为其创建视图模型Profile.将此命名为ProfileViewModel或者通常是常见的ProfileVM.然后,在此模型上,您只会Profile在视图中添加要编辑或以其他方式与之交互的属性.然后,您实际上可以添加不在数据库支持的模型上的其他属性以用于特殊用途的视图函数,例如SelectList要使用的DropDownListFor,因此您实际上可以保持强类型而不是诉诸ViewBag于此类事物.

对于您的图像,您需要两个字段.我通常会使用以下内容:

public string Photo { get; set; }
public HttpPostedFileBase PhotoUpload { get; set; }
Run Code Online (Sandbox Code Playgroud)

在您的编辑/创建视图中,您将仅引用PhotoUpload,这将是您的文件上传字段(尽管您可以Photo用来显示当前设置的图像,如果您愿意).

@Html.TextBoxFor(m => m.PhotoUpload, new { type = "file" })
Run Code Online (Sandbox Code Playgroud)

然后,在控制器操作中处理发布的文件:

if (model.PhotoUpload.ContentLength > 0) {
    // A file was uploaded
    var fileName = Path.GetFileName(model.PhotoUpload.FileName);
    var path = Path.Combine(Server.MapPath(uploadPath), fileName);
    model.PhotoUpload.SaveAs(path);
    model.Photo = uploadPath + fileName;
}
Run Code Online (Sandbox Code Playgroud)

哪里uploadPath应该是您想要存储上传图像的主目录相对路径,例如~/uploads/profile/photos.确保在尝试发布表单之前创建目录,或添加一些逻辑来检查目录是否存在并在必要时创建它(这需要在服务器上获得更高的信任,因此在大多数安全性较高的环境中并不理想一个大问题).

然后,您只需要一些方法将视图模型中的数据映射回数据库支持的模型.您可以手动执行此操作,但使用AutoMapper之类的操作可以让您的生活更轻松.使用automapper(其中model是一个实例ProfileViewModel):

var profile = AutoMapper.Mapper.Map<Profile>(model);
Run Code Online (Sandbox Code Playgroud)

或者,由于使用类似于配置文件的内容,您编辑现有模型比创建新模型更常见:

var profile = db.Profiles.Find(userId);
...
Automapper.Mapper.Map(model, profile);
Run Code Online (Sandbox Code Playgroud)

在您的实际模型上,您将不会拥有该PhotoUpload属性Photo.您Photo在视图模型上设置的路径将映射到模型的同名属性上,因此剩下的就是保存更新的配置文件.

此外,由于您正在谈论上传照片,您可能希望添加一些内容类型检查,以确保用户上传图像而不是像Word文档那样愚蠢的内容.在if (ModelState.IsValid)检查之前,添加:

var validTypes = new[] { "image/jpeg", "image/pjpeg", "image/png", "image/gif" };
if (!validTypes.Contains(model.PhotoUpload.ContentType))
{
    ModelState.AddModelError("PhotoUpload", "Please upload either a JPG, GIF, or PNG image.");
}
Run Code Online (Sandbox Code Playgroud)

根据需要更改mime类型以匹配您的业务案例.