想将一张图片保存到文件夹,并将其URL保存在数据库中

8

我很菜鸟,对于asp.net mvc一窍不通。我在控制器中上传图片遇到了问题,有人能帮忙吗?这个控制器的示例是我从网上找到的,我需要改变什么和代码视图,我想通过“AvatarUrl”保存图片。

模型 > 员工服务

public class EmployeeModel{

    [ScaffoldColumn(false)]
    public int EmployeeID { get; set; }

    [Required(ErrorMessage = "Please Enter Position ID")]
    public int PositionID { get; set; }

    [Required(ErrorMessage = "Please Enter NO PEK")]
    public string NoPEK { get; set; }

    [Required(ErrorMessage = "Please Enter NO KTP")]
    public string NoKTP { get; set; }

    [Required(ErrorMessage = "Please Enter TaxID")]
    public string TaxID { get; set; }

    [Required(ErrorMessage = "Please Enter FirstName")]
    public string FirstName { get; set; }

    [Required(ErrorMessage = "Please Enter LastName")]
    public string LastName { get; set; }

    [Required(ErrorMessage = "Please Enter OrganizationID")]
    public int OrganizationID { get; set; }

    [Required(ErrorMessage = "Please Enter BirthPlace")]
    public string BirthPlace { get; set; }

    [Required(ErrorMessage = "Please Enter BirthDay")]
    public System.DateTime BirthDay { get; set; }

    [Required(ErrorMessage = "Please Enter Gender")]
    public string Gender { get; set; }

    [Required(ErrorMessage = "Please Enter Religion")]
    public string Religion { get; set; }

    [Required(ErrorMessage = "Please Enter TaxAddress")]
    public string TaxAddress { get; set; }

    [Required(ErrorMessage = "Please Enter Home Address")]
    public string HomeAddress { get; set; }

    [Required(ErrorMessage = "Please Enter Current Address")]
    public string CurrentAddress { get; set; }

    [Required(ErrorMessage = "Please Enter Phone Number")]
    public string PhoneNumber { get; set; }

    [Required(ErrorMessage = "Please Enter Email")]
    public string Email { get; set; }

    [Required(ErrorMessage = "Please Enter IsAuditor")]
    public string IsAuditor { get; set; }

    [Required(ErrorMessage = "Please Enter TaxProvince ")]
    public int TaxProvinceID { get; set; }

    [Required(ErrorMessage = "Please Enter Tax City ")]
    public int TaxCityID { get; set; }

    [Required(ErrorMessage = "Please Enter Home Province ")]
    public int HomeProvinceID { get; set; }

    [Required(ErrorMessage = "Please Enter Home City")]
    public int HomeCityID { get; set; }

    [Required(ErrorMessage = "Please Enter Current Province")]
    public int CurrentProvinceID { get; set; }

    [Required(ErrorMessage = "Please Enter Current City")]
    public int CurrentCityID { get; set; }

    [Required(ErrorMessage = "Please Enter Avatar Url")]
    public string AvatarUrl { get; set; }
}

控制器 > 员工控制器

    [HttpPost]
    public ActionResult Create(EventModel eventmodel, HttpPostedFileBase file)
    {
        if (ModelState.IsValid)
        {
            var filename = Path.GetFileName(file.FileName);
            var path = Path.Combine(Server.MapPath("~/Uploads/Photo/"), filename);
            file.SaveAs(path);
            tyre.Url = filename;

            _db.EventModels.AddObject(eventmodel);
            _db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(eventmodel);
    }

在“_db.EventModels.AddObject(eventmodel);”这一行之前,您可以执行以下操作“eventmodel.AvatarUrl = "~/Uploads/Photo/" + filename;”。 - Ehsan Sajjad
3个回答

20

上传文件,将其存储在本地文件系统中,并保存到数据库是常见的模式。以下是我的建议。

1.不要使用已上传的文件名作为您的文件名。

这是常见的做法:

var filename = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Uploads/Photo/"), filename);
file.SaveAs(path);
不要这样做。有几个原因:
a)文件名可能会冲突。 b)远程文件名可能与本地文件系统不兼容。 c)有人可能会尝试使用恶意文件名,这样做可能会破坏您的服务器。
相反,生成自己的文件名(也许使用GUID,GUID.NewGuid().ToString()),并将原始文件名存储在数据库中。
2. 不要将所有文件都存储在一个单独的文件夹中
在某个时刻,您的文件夹将包含太多文件,以致于操作系统无法快速处理。
通过某些有用的方式对文件进行分区,比如用户ID。这还有助于在用户之间隔离文件。
3. 不要在数据库中存储文件的完整路径
在某个时候,您可能会移动文件(也许到不同的驱动器),并且您所有存储的文件位置将被破坏。
4. 不要在数据库中存储图像URL
与#3相同。如果您的Web应用程序更改,并且您想要更改图像URL,则数据库中存储的URL是不正确的。您必须扫描和更新所有数据库记录。
5. 不要在数据库中存储冗余路径信息
虽然在数据库存储的URL中包含“Uploads/Photo/”可能很诱人,但它也有很多问题:
a)这是冗余数据。对于每个文件,您都使用了额外的、不必要的数据空间。 b)如果您的应用程序更改并且URL应更改,则您存储的URL现在已经损坏。
相反,在从数据库中读取值后,在URL之前添加“Uploads/Photo/”。
    [HttpPost]
    public ActionResult Create(EventModel eventmodel, HttpPostedFileBase file)
    {
        if (ModelState.IsValid)
        {
            var originalFilename = Path.GetFileName(file.FileName);
            string fileId = Guid.NewGuid().ToString().Replace("-", "");
            string userId = GetUserId(); // Function to get user id based on your schema

            var path = Path.Combine(Server.MapPath("~/Uploads/Photo/"), userId, fileId);
            file.SaveAs(path);

            eventModel.ImageId = fileId;
            eventmodel.OriginalFilename = originalFilename;

            _db.EventModels.AddObject(eventmodel);
            _db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(eventmodel);
    }

然而,我会谨慎地使用您的数据模型作为MVC操作模型。


0

你应该将你的 AvatarUrl 改为:

public HttpPostedFileBase AvatarUrl { get; set; }

在您的视图中,您可以创建一个类似于以下的表单。添加您将接受输入的字段,并为您的头像使用文件输入。当表单被提交回控制器时,MVC 将尝试将输入绑定到参数。
@using(Html.BeginForm("Create", FormMethod.Post, new { enctype = "multipart/form-data" }) {
    <fieldset>
        @Html.LabelFor(m => m.FirstName)
        @Html.EditorFor(m => m.FirstName)
    </fieldset>
    <!--    
    REST OF YOUR INPUT FIELDS HERE
    -->
    <fieldset>
        @Html.LabelFor(m => m.Avatar)
        @Html.EditorFor(m => m.Avatar)
    </fieldset>
    <input type="submit" value="Submit" />
})

你的控制器方法应该更新为:

[HttpPost]
public ActionResult Create(EmployeeModel model)
{
    if (ModelState.IsValid)
    {
        // Create avatar on server
        var filename = Path.GetFileName(model.AvatarUrl.FileName);
        var path = Path.Combine(Server.MapPath("~/Uploads/Photo/"), filename);
        file.SaveAs(path);
        // Add avatar reference to model and save
        model.AvatarUrl = string.Concat("Uploads/Photo/", filename);
        _db.EventModels.AddObject(model);
        _db.SaveChanges();

        return RedirectToAction("Index");
    }
    return View(model);
}

如果你还有疑问,请告诉我,我可以提供更详细的解释。
此外,这里有一篇与你正在尝试做的事情相关的优秀/详细的文章 http://cpratt.co/file-uploads-in-asp-net-mvc-with-view-models/

0
如果您在使用.NET 6,则可以执行以下操作:
在 Model 中 -
public string? imageFileName { get; set; }

在ViewModel中 -
public IFormFile? image { get; set; }

在cshtml文件(用户输入表单)中 -
@model yourViewModel
<input asp-for="image">

在控制器/服务中 -
private readonly IHostEnvironment _hostingEnvironment;
private readonly string _path = "";

Constructor(IHostEnvironment hostingEnvironment){
    _hostingEnvironment = hostingEnvironment;
    _path = Path.Combine(_hostingEnvironment.ContentRootPath, "wwwroot", "Images");    
}

//your method that receives the image {
    string fileName = null;
    if (image != null) //type of image is IFormFile
    {
        Guid guid = Guid.NewGuid();
        fileName = $"{guid}.{image.FileName.Split('.').Last()}";
        await SaveInLocalFolder(image, fileName);
    }
//}

private async Task<bool> SaveInLocalFolder(IFormFile file, string fileName)
{
    if (!Directory.Exists(_path))
    {
        Directory.CreateDirectory(_path);
    }
    using (var fileStream = new FileStream(Path.Combine(_path, fileName), FileMode.Create))
    {
        await file.CopyToAsync(fileStream);
    }
    return true;
}

并且从 cshtml 文件中像这样访问图像 -

<img src="/Images/guid_generated_filename"/>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接