8

I very newbie in asp.net mvc . here I had a problem in the controller image upload anyone can give help ?? This example controller I get from the internet , what should I change and code viewnya like, here I want to save the image through " AvatarUrl "

Model > EmployeeServices

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; }
}

Controller > EmployeesController

    [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);
    }
D.M
  • 429
  • 1
  • 5
  • 24
Burhanumubim
  • 93
  • 1
  • 1
  • 7
  • you can do :``eventmodel.AvatarUrl = "~/Uploads/Photo/"+filename;`` before the line ``_db.EventModels.AddObject(eventmodel);`` – Ehsan Sajjad Aug 24 '15 at 09:37

3 Answers3

20

Uploading a file, storing in the local file-system, and saving to a database is a common pattern. These are my recommendations.

1. Do not use the uploaded filename as your filename.

This is common:

var filename = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/Uploads/Photo/"), filename);
file.SaveAs(path);

Don't do it. There are a few reasons:

a) Filenames may conflict. b) Remote filenames may be incompatible with your local file-system. c) Someone may try a malicious filename and doing this may break your server.

Instead, generate your own filename (perhaps using a GUID, GUID.NewGuid().ToString()) and store the original filename in your database.

2. Don't store all files in a single folder

At some point, your folder will contain too many files for the OS to process quickly.

Partition the files by something useful, like the user ID. This also helps to segregate the files between users.

3. Don't store the full path to the file in the database

At some point, you may move the files (perhaps to a different drive) and all your stored file locations will be broken.

4. Don't store the image URL in the database

Same as #3. If your web app changes and you want to change the image URLs, then you have incorrect URLs stored in the database. You'll have to scan and update all your database records.

5. Don't store redundant path information in the database

While it may be tempting to include "Uploads/Photo/" in the stored URL in the database, it has many problems too:

a) It's redundant data. For every file, you're using extra, unnecessary, data space. b) If your app changes and the URL should change, your stored URLs are now broken.

Instead, prepend "Uploads/Photo/" to the URL after you read the value from the database.

Update:

Here is some sample code:

    [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);
    }

However, I would be wary about using your data model as the MVC action model.

Matt Houser
  • 33,983
  • 6
  • 70
  • 88
0

You should change your AvatarUrl to:

public HttpPostedFileBase AvatarUrl { get; set; }

In your view, you can create a form similar to the following. Add the fields you will accept input for and use a file input for your avatar. When the form is posted back to the controller, MVC will attempt to bind the inputs to the parameters.

@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" />
})

Your controller method should be updated to:

[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);
}

If you're still stuck let me know and I can go into more detail.

There's also an excellent/detailed write up related to what you're trying to do here http://cpratt.co/file-uploads-in-asp-net-mvc-with-view-models/

timothyclifford
  • 6,799
  • 7
  • 57
  • 85
0

If you are using .NET 6, you can do the following:

In Model -

public string? imageFileName { get; set; }

In ViewModel -

public IFormFile? image { get; set; }

In cshtml file (user input form) -

@model yourViewModel
<input asp-for="image">

In controller/Services -

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;
}

And from cshtml file access the image like this -

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