Guzzyman
Guzzyman

Reputation: 561

Uploading and saving file in ASP.NET MVC4

I have a file field which is to be used to upload images and at the same time save the file path in the database. I followed this sample tutorial and adapted my code. Below is my model

using System;
using System.Web;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BOL
{
    public class TeamValidation
    {
        [Key]
        public int teamID { get; set; }

        [Required(ErrorMessage = "Please Enter Your Team Name")]
        [Display(Name = "Team Name")]
        public string teamName { get; set; }      

        [DisplayName("Team Picture")]
        [Required(ErrorMessage = "Please Upload Team Picture")]
        [ValidateFile]
        public HttpPostedFileBase teamPicture { get; set; }
        //public string teamPicture { get; set; }

        [Required]
        [Display(Name = "Description")]
        public string description { get; set; }

        //[AllowHtml]
        [Required(ErrorMessage = "Please Enter Team Content")]        
        [Display(Name = "Content")]
        [MaxLength(200)]
        public string content { get; set; }
    }

    //Customized data annotation validator for uploading file
    public class ValidateFileAttribute : ValidationAttribute
    {
        public override bool IsValid(object value)
        {
             int MaxContentLength = 1024 * 1024 * 3; //3 MB
             string[] AllowedFileExtensions = new string[] { ".jpg", ".gif", ".png" };

             var file = value as HttpPostedFileBase;

             if (file == null)
                return false;
             else if (!AllowedFileExtensions.Contains(file.FileName.Substring(file.FileName.LastIndexOf('.'))))
             {
                 ErrorMessage = "Please upload Your Photo of type: " + string.Join(", ", AllowedFileExtensions);
                 return false;
             }
             else if (file.ContentLength > MaxContentLength)
             {
                 ErrorMessage = "Your Photo is too large, maximum allowed size is : " + (MaxContentLength / 1024).ToString() + "MB";
                 return false;
             }
             else
                return true;
        }
    }

    [MetadataType(typeof(TeamValidation))]
    public partial class team
    {
        [Key]
        public int teamID { get; set; }

        public string teamName { get; set; }

        public string teamPicture { get; set; }

        public string description { get; set; }

        public string content { get; set; } 
    }
}

and here is the controller

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using BOL;

namespace TeamBuildingCompetition.Areas.Admin.Controllers
{
    public class TeamController : BaseAdminController
    {
        // GET: Admin/Team
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult teamView()
        {
            var teamList = objBs.teamBs.GetALL();
            return View(teamList);
        }

        [HttpPost]
        public ActionResult Create(team objTeam)
        {

            try
            {
                if (ModelState.IsValid)
                {
                    var fileName = Path.GetFileName(objTeam.teamPicture.FileName);
                    var path = Path.Combine(Server.MapPath("~/Content/Upload"), fileName);
                    objTeam.teamPicture.SaveAs(path);

                    TempData["Msg"] = "Created Successfully!";
                    objBs.teamBs.Insert(objTeam);
                    return RedirectToAction("Index");
                }
                else
                {
                    return View("Index");
                }
            }
            catch (Exception e1)
            {
                TempData["Msg"] = "Create Failed! :" + e1.Message;
                return RedirectToAction("Index");
            }
        }

    }
}

I have the errors in the snip below so I'm not able to run the file. Below is the squiggly line of error from the controller:

enter image description here

and also squiggly line in the model as shown below:

enter image description here

On hovering over the Squiggly lines, I had this error

For the TeamValidation.cs The Error is Generate Class for HttpPostedFileBase

While the error on the TeamController for the squiggly line .FileName is 'string' does not contain a defination for 'FileName' and no extension method 'FileName' accepting a first arguement of type 'string'

Upvotes: 0

Views: 1049

Answers (2)

user3559349
user3559349

Reputation:

Your problem is the use a partial classes and the [MetadataType] attribute on class team. Your data model has property string teamPicture and your metadata class has a conflicting property HttpPostedFileBase teamPicture. Your controller method has parameter team objTeam so objTeam.teamPicture.FileName throws an error because teamPicture is typeof string. To solve this, remove the [MetadataType] attribute from your data model, and use a view model to represent what you want to edit in the view

Data model (in namespace BOL)

public class team
{
    [Key]
    public int teamID { get; set; }
    public string teamName { get; set; }
    public string teamPicture { get; set; }
    public string description { get; set; }
    public string content { get; set; } 
}

Then create a new folder in your project for the view model (say ViewModels). Note the teamID should not be required since the view is for creating a new team

public class TeamVM
{
    [Required(ErrorMessage = "Please Enter Your Team Name")]
    [Display(Name = "Team Name")]
    public string TeamName { get; set; }      
    [DisplayName("Team Picture")]
    [Required(ErrorMessage = "Please Upload Team Picture")]
    [ValidateFile]
    public HttpPostedFileBase TeamPicture { get; set; }
    [Required]
    [Display(Name = "Description")]
    public string Description { get; set; }
    [Required(ErrorMessage = "Please Enter Team Content")]        
    [Display(Name = "Content")]
    [MaxLength(200)]
    public string Content { get; set; }
}

Your GET method should initialize and return an instance of TeamVM

[HttpGet]
public ActionResult Create()
{
  TeamVM model = new TeamVM();
  return View(model);
}

and the view will be @model yourAssembly.TeamVM

Then the POST method will be

[HttpPost]
public ActionResult Create(TeamVM model)
{
  ....
  var fileName = Path.GetFileName(model.TeamPicture.FileName);
  var path = Path.Combine(Server.MapPath("~/Content/Upload"), fileName);
  model.TeamPicture.SaveAs(path);
  // map the view model to a new instance of the data model
  team objTeam = new team
  {
    teamName = model.TeamName,
    teamPicture = path,
    description = model.Description,
    content = model.Content
  };
  // save and redirect
  objBs.teamBs.Insert(objTeam);
  ....
}

Upvotes: 2

Bartosz Czerwonka
Bartosz Czerwonka

Reputation: 1651

You use MetadataTypeAttribute and in documentation is:

You then define the metadata type as a normal class, except that you declare simple properties for each of the members to which you want to apply validation attributes.

Example from documentation:

[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
  ... Existing members defined here, but without attributes or annotations ...
}

Then your class team should be like this:

  [MetadataType(typeof(TeamValidation))]
public partial class team
    {
        [Key]
        public int teamID { get; set; }
        public string teamName { get; set; }     
        public HttpPostedFileBase teamPicture { get; set; }
        public string description { get; set; }
        public string content { get; set; }
    }

Upvotes: 1

Related Questions