ASP.NET MVC5 - Image upload to SQL Server 2008R2 Standard - asp.net-mvc

I am semi-new to ASP.NET MVC, I have used it in the past but not to the extent of what I have been planning to use it for and to learn from for some projects I am working on. I know this question has been asked a lot over the internet and there are many solutions so I will try and keep this as specific as possible regarding uploading images and storing them in a SQL Server database.
I am currently using .NET 4.5 with MVC5 (VS 2013) to do all my coding.
To begin I found a great tutorial that got me up and running with being able to upload images to my SQL Server 2008 database: http://www.mikesdotnetting.com/Article/125/ASP.NET-MVC-Uploading-and-Downloading-Files
Everything works great after I figured out how the functions worked from the site, but the issue I am having is that I have multiple text fields that I want to include data from into the SQL Server database along with including an image upload feature that I created based off the tutorial I found online.
The first part of my code is the Models (BeerList.cs)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
namespace YBPP_Production.Models
{
public class BeerList
{
public int ID { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
[Required(ErrorMessage = "Company is required.")]
public string Company { get; set; }
[Required(ErrorMessage = "Type is required.")]
public string Type { get; set; }
[Required(ErrorMessage = "City is required.")]
public string City { get; set; }
[Required(ErrorMessage = "State is required.")]
public string State { get; set; }
[Required(ErrorMessage = "Country is required")]
public string Country { get; set; }
public string ABV { get; set; }
public string IBU { get; set; }
}
public class Info : DbContext
{
public DbSet<DBName> MoreDB { get; set; }
}
}
The string listed there are the text fields I am trying to pull into my database and I can do that but when I try to mix in the image upload feature either the text will upload or the image will upload depending on how I do the calls.
The Controllers section of my code (BeerListController.cs)
// GET: /BeerList/Create
public ActionResult Create()
{
return View();
}
// POST: /BeerList/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,Name,Company,Type,City,State,Country,ABV,IBU")] BeerList beerlist)
{
if (ModelState.IsValid)
{
db.BeerListDB.Add(beerlist);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(beerlist);
}
public ActionResult FileUpload(HttpPostedFileBase file)
{
//Begin the Image Uploading Process
foreach (string upload in Request.Files)
{
if (!Request.Files[upload].HasFile()) continue;
string mimeType = Request.Files[upload].ContentType;
Stream fileStream = Request.Files[upload].InputStream;
string fileName = Path.GetFileName(Request.Files[upload].FileName);
int fileLength = Request.Files[upload].ContentLength;
byte[] fileData = new byte[fileLength];
fileStream.Read(fileData, 0, fileLength);
const string connect = #"Server=localhost;database=<database-name>;uid=<username-here>;pwd=<there-a-passwordhere>";
using (var conn = new SqlConnection(connect))
{
var qry = "INSERT INTO BeerLists (FileContent, mimeType, FileName) VALUES (#FileContent, #mimeType, #FileName)";
var cmd = new SqlCommand(qry, conn);
cmd.Parameters.AddWithValue("#FileContent", fileData);
cmd.Parameters.AddWithValue("#MimeType", mimeType);
cmd.Parameters.AddWithValue("#FileName", fileName);
conn.Open();
cmd.ExecuteNonQuery();
}
}
return View();
}
The view part of my code (Create.cshtml)
#model YBPP_Production.Models.BeerList
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype="multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>BeerList</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Company, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Company)
#Html.ValidationMessageFor(model => model.Company)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Type, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Type)
#Html.ValidationMessageFor(model => model.Type)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.City, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.State, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.State)
#Html.ValidationMessageFor(model => model.State)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Country, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Country)
#Html.ValidationMessageFor(model => model.Country)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ABV, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ABV)
#Html.ValidationMessageFor(model => model.ABV)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.IBU, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.IBU)
#Html.ValidationMessageFor(model => model.IBU)
</div>
</div>
<div class="form-group">
<p class="control-label col-md-2">Image Upload:</p>
<div class="col-md-10">
<input type="file" id="ImageUpload" name="ImageUpload" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" name="Submit" id="Submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
So what I am looking to hopefully get help with is being able to merge the function of Create and FileUpload into one function so that the form will take both the text in the text-fields and the image that gets uploaded with it. I have read a bunch of other people's posts and code and they all seem to have their own way to doing things but everyone example never includes text-fields or any other form functions just the basic image upload.
Thank you very very much in advance for any direction/suggestions/help to this issue.

You can create model that contains HttpPostedFileBase, then save your entire form with selected file.
Model:
public class BeerListModel
{
public int ID { get; set; }
[Required(ErrorMessage = "Name is required")]
public string Name { get; set; }
[Required]
public HttpPostedFileBase file { get; set; }
}
View:
#using (Html.BeginForm(null, null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
<div class="form-group">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="form-group">
<p class="control-label col-md-2">Image Upload:</p>
<input type="file" id="file" name="file" />
</div>
<div class="form-group">
<input type="submit" name="Submit" id="Submit" value="Create" class="btn btn-default" />
</div>
</div>
}
Controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(BeerListModel model)
{
if (ModelState.IsValid)
{
//your logic
}
return View("Create");
}

#Szakus' answer is the overall direction you want to go with respect to uploading a file, however when you asked, " I am still a bit confused as to what I should put as far as my logic for the Controller" you inadvertently got to the root of your problem.
I would strongly recommend you do some research into separation of concerns. Putting raw SQL code in your controller is not a great idea and will open your application to a host of the other issues.
I know this doesn't really answer your question but having been where you are now I can tell you that the old adage, "an ounce of prevention is worth a pound of cure" will save you major headaches down the road.
If you want to see an example of a really good .net MVC project that you can use as sort of a template in building your skills I would recommend the open source shopping cart nopCommerce.

Related

How to save to database Client IP Address of Visitors Machine in ASP.Net MVC?

am trying to get IP Address of client Machine Request.ServerVariables["HTTP_X_FORWARDED_FOR"]; it's working fine.
Get IP On page load
public ActionResult AddCompany()
{
get_IP();
return View();
}
get_IP code
public void get_IP()
{
string ipAddress = Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ipAddress))
{
ipAddress = Request.ServerVariables["REMOTE_ADDR"];
}
ViewBag.IPAddress = ipAddress;
}
But when user register the form get IP address value also save in the data base..
Cs.html File
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
<h1 class="page-header">Add Company</h1>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.IPAddress)
<div class="form-group">
#Html.LabelFor(model => model.CompanyName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CompanyName)
#Html.ValidationMessageFor(model => model.CompanyName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ShortName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ShortName)
#Html.ValidationMessageFor(model => model.ShortName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Email, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Country, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#*#Html.EditorFor(model => model.Country)*#
#Html.DropDownList("Country", null, "---Select Country----")
#Html.ValidationMessageFor(model => model.Country)
</div>
</div>
<div class="form-group">
<b>State: </b>
<select id="state"></select><br />
</div>
<div>
<b>City: </b>
<select id="city"></select><br />
</div>
<div class="form-group">
#Html.LabelFor(model => model.MobileNo, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.MobileNo)
#Html.ValidationMessageFor(model => model.MobileNo)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</div>
I create one #Html.HiddenFor(model => model.IPAddress) hidden filed value but it's not working ..
On page load IPAddress Value is showing .after i click to save button the Ip value is not saved to the database..
AddCompany
[HttpPost]
public ActionResult AddCompany(Company cmp)
{
using (DataContext entities = new DataContext())
{
entities.Company.Add(cmp);
entities.SaveChanges();
int id = cmp.CompanyID;
Session.Clear();
Response.Redirect("Index");
}
return View(cmp);
}
Any idea How to save client IP Adrress from the database..
Class File
[Table("MySecondMVCDemo")]
public class Company
{
[Key]
public int CompanyID { get; set; }
[Required(ErrorMessage = "Please Enter Company Name")]
[Display(Name = "CompanyName")]
public string CompanyName { get; set; }
[Required(ErrorMessage = "Please Enter Short Name")]
[Display(Name = "ShortName")]
public string ShortName { get; set; }
[Required(ErrorMessage = "Please Enter Email Address")]
[Display(Name = "Email")]
public string Email { get; set; }
[Required(ErrorMessage = "Please Enter Email Address")]
[Display(Name = "Country")]
public string Country { get; set; }
[Required(ErrorMessage = "Please Enter Mobile No")]
[Display(Name = "MobileNo")]
public string MobileNo { get; set; }
public Int32? IPAddress { get; set; }
}
I do not know about HiddenFor because I have not use it before.
How I hid fields before was like this:
#Html.TextBoxFor(model => model.IPAddress, new { #class = "sr-only", #type = "hidden" })
You can add the bootstrap class sr-only to make sure it is hidden.
Make sure you check your browser inspector to see whether the hidden field has a value.
If posted and is still not saving, then try to assign the IpAddress identity to the form field value before saving it like this:
cmp.IPAddress = Request.Form["IPAddress"];
Store IP address as a string instead of Int32
Please use code from here to get IP Address
http://tutorialgenius.blogspot.in/2010/09/aspnet-get-ipv4-address-even-if-user-is.html

ASP.NET MVC 5 Scaffolding not creating elements for enum property

This is probably a newbie question, as I'm quite new to ASP.NET MVC 5. When I tell Visual Studio to add a View based on my ViewModel class, it completely skips properties defined like public EnumName? PropertyName { get; set; } and does not create any #Html.EditorFor calls for it.
However, if I manually add the call #Html.EditorFor(model => model.PropertyName, new { htmlAttributes = new { #class = "form-control" } }) I get exactly what I expect -- a dropdown which is empty by default. Should scaffolding not do this by itself?
My understanding is that this is supposed to be supported in the current version of ASP.NET MVC. Am I wrong about that, or am I missing something? Help or advice is greatly appreciated.
Thanks in advance!
These are the ASP.NET products installed:
ASP.NET and Web Tools 12.4.51016.0
ASP.NET Web Frameworks and Tools 2012.2 4.1.21001.0
ASP.NET Web Frameworks and Tools 2013 5.2.21010.0
Edit for sample code:
Here is a small section of the view model. There are 170 different properties, almost all of them nullable-Enum type.
public partial class MedicalHistoryViewModel
{
public YesNo? Cancer { get; set; }
public MedicalHistoryDiagnosed? CancerDiagnosed { get; set; }
public YesNoUnsure? CancerIndustrialInOrigin { get; set; }
public YesNo? Diabetes { get; set; }
public MedicalHistoryDiagnosed? DiabetesDiagnosed { get; set; }
public YesNoUnsure? DiabetesIndustrialInOrigin { get; set; }
public YesNo? HeartDisease { get; set; }
//...
[Display(Name = #"Do you attribute the sleep disturbance to pain, anxiety and/or depression, or to other factors?")]
[DataType(DataType.MultilineText)]
public string SleepDisturbanceAttributedToComments { get; set; }
[Display(Name = #"Other (please specify)")]
[DataType(DataType.MultilineText)]
public string ParentsGrandparentsMedicalHistoryComments { get; set; }
}
Here is the complete output I get from Scaffolding. As you can see, it has completely ignored all enum properties.
#model QmeSurveyApp.ViewModels.MedicalHistoryViewModel
#{
ViewBag.Title = "EditMedicalHistory"; }
<h2>EditMedicalHistory</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MedicalHistoryViewModel</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.SleepDisturbanceAttributedToComments, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SleepDisturbanceAttributedToComments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SleepDisturbanceAttributedToComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SiblingsCousinsMedicalHistoryComments, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SiblingsCousinsMedicalHistoryComments, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.SiblingsCousinsMedicalHistoryComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ParentsGrandparentsMedicalHistoryComments, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ParentsGrandparentsMedicalHistoryComments, new { htmlAttributes
= new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ParentsGrandparentsMedicalHistoryComments, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div> }
<div>
#Html.ActionLink("Back to List", "Index") </div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval") }
But, if I add this block manually, I get exactly what I want: a drop-down which is empty by default, with my full pick list as the choices.
<div class="form-group">
#Html.LabelFor(model => model.Cancer, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Cancer, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Cancer, "", new { #class = "text-danger" })
</div>
</div>
You don't mention it, but I'm guessing you're not using Entity Framework.
I had a similar situation in an MVC project I was working in without EF. I had a POCO with a property that was an enum, and it was being completely skipped by the scaffolding engine. I even tried overriding the T4 templates with my own CodeTemplates and that's when I noticed the ModelMetadata.Properties collection didn't even contain my enum property.
I finally got it to work just by adding an empty Code First Entity Data model to the project. Doing that adds the Data context class textbox to the Add View scaffold item, and the resulting scaffolded view now includes my enum properties. This seems like a bug to me.

What could be causing for ASP.NET MVC form to not properly submit/deserialize?

This looks like it should be working, yet the form submits with model not properly deserialized. Using latest ASP.NET MVC from nuget. .NET 4.5
A very standard user-registration View/Controller.
View:
#model Alertera.Portal.Web.Models.RegisterViewModel
#{
ViewBag.Title = "Register";
}
<h2>#ViewBag.Title.</h2>
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#*#Html.ValidationSummary()*#
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.FirstName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.FirstName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.LastName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.LastName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Password, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.Password, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.ConfirmPassword, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.PasswordFor(m => m.ConfirmPassword, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
Controller:
// POST: /Account/Register
[AcceptVerbs(HttpVerbs.Post)]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new User
{
UserName = model.UserName,
FirstName = model.FirstName,
LastName = model.LastName
};
user.SetEmail(model.Email);
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
_bus.Publish(new UserCreated(user));
await SignInAsync(user, isPersistent: false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
All of the posts are coming in with model being empty or forgery token not present (depends if I enable or disable verficiation). I'm simply stumped and don't know where to look.
** EDIT **
If I disable antiforgery, ModelState is invalid, all of the fields in the model are empty and error messages state that fields are required.
I'm using Autofac with MVC extensions and Model binder is registered like so:
builder.RegisterModelBinders(Assembly.GetExecutingAssembly());
builder.RegisterModelBinderProvider();
Autofac is working in general, as controller is instantiated properly and is injected with propery dependencies.
Edit 2:
Created a custom binder by inheriting from the DefaultModelBinder, per suggestion, so that I could see the transformation. It looks like the bindingContenxt's model is null
The view model itself is here:
public class RegisterViewModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string FirstName { get; set; }
}
After a full day of trubleshooting, updating all of the nuget packages, making sure that web.config's are all tight and contain proper assembly redirects, routes are neat, and even repair of .NET framework and other time consuming and irrelevant activities, I've finally figured this out:
A few weeks prior, we've introduced an Autofac binding that would capture serialized HttpContext along with other relevant data for when the logging framework would need it. (Imagine being able to log request information alongside a full exception stack inside a business object without polluting business logic with session/logging data.)
Unfortunately, as a part of the binding creation, the HttpContext was being serialized by Json.net and not at the time of the logging of the event, but at the time of the binding.
Apparently, when Json.net seralizes HttpContext, it actually reads the streams inside it for the first time, causing the submitted form data to be read, so that when Controller is instantiated and data for it is posted, the streams have already been read and Request.Form colection is empty.
Simple fix to only create a delegate to serialize HttpContext appears to have fixed the issue

Store View form in existing database

Forgive the newbie ASP.NET MVC question. I am used to tutorials where Code First is used with the Entity Framework. Here, this is not the case. I have a form that I want the user to fill out. When it has been filled out, I want to use EF to write the values to an existing database. I can't figure out how to "trap" the values in the view so I can write my EF code. I used a model and I redirected the BeginForm to an "Edit" action method but I don't know how to get my filled in class. Here is the HomeController methods:
[HttpGet]
public ActionResult Trial()
{
UserAccount account = new UserAccount();
return View(account);
}
public ActionResult Edit()
{
}
Here is the model class:
public class UserAccount
{
public int AccountID { get; set; }
public string AccountName { get; set; }
public string RegistrationCode { get; set; }
public DateTime Created { get; set; }
}
}
Here is the View the wizard generated. When I hit the "Create" button, I want to go to the "Edit" action menu or someplace I can use EF to write to the existing database table. How do I do this?
#model AlphaFrontEndService.Models.UserAccount
#{
ViewBag.Title = "Trial";
}
<h2>Trial</h2>
#using (Html.BeginForm("Edit", "Home"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>UserAccount</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.AccountID, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.AccountID)
#Html.ValidationMessageFor(model => model.AccountID)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.AccountName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.AccountName)
#Html.ValidationMessageFor(model => model.AccountName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.RegistrationCode, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.RegistrationCode)
#Html.ValidationMessageFor(model => model.RegistrationCode)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Created, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Created)
#Html.ValidationMessageFor(model => model.Created)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
You need a POST action for Trial method like below:
[HttpPost]
public ActionResult Trial(UserAccount model)
{
if (ModelState.IsValid)
{
//Store the form data into your database
}
return View(model);
}
Then in your view, add a submit button element inside the form, also instead of Edit, you just need to use Trial for the postback.
#using (Html.BeginForm("Trial", "Home")) {
//
<input type="submit" value="Submit"/>
}
Note: You don't need to create other Edit action method if you don't have some other reasons.
If you don't know how to save the data to your database, below is an example:
Create your DbContext class
public class MyDbContext : DbContext
{
public MyDbContext()
: base("name=YourDbConnection")
{
}
public DbSet<UserAccount> UserAccounts { get; set; }
}
Then the action method will looks like:
public class HomeController : Controller
{
//
[HttpPost]
public ActionResult Trial(UserAccount model)
{
if (ModelState.IsValid)
{
using (var db = new MyDbContext())
{
db.UserAccounts.Add(model);
db.SaveChanges();
return RedirectToAction("Index");
}
}
return View(model);
}
}

How do I pass a ViewModel to an Edit Action in ASP.NET MVC 5

I'm learning about using ViewModels to pass information from the view to the controller and vice versa. I have my create action, view, and viewmodel working perfectly but I'm having trouble with the edit one. I get the error:
The model item passed into the dictionary is of type 'CatVM.Models.Cat', but this dictionary requires a model item of type 'CatVM.Models.EditCatViewModel'.
Here is my code:
Controller Method
// GET: /Cats/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Cat cat = unitOfWork.CatRepository.GetByID(id);
if (cat == null)
{
return HttpNotFound();
}
return View(cat);
}
View
#model CatVM.Models.EditCatViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Cat</h4>
<hr />
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.Name, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Color, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Color)
#Html.ValidationMessageFor(model => model.Color)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.FurLength, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.FurLength)
#Html.ValidationMessageFor(model => model.FurLength)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Size, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Size)
#Html.ValidationMessageFor(model => model.Size)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
EditCatViewModel
public class EditCatViewModel
{
public int ID { get; set; }
[Required]
[StringLength(50)]
public string Name { get; set; }
[Required]
[StringLength(50)]
public string Color { get; set; }
[Required]
[StringLength(50)]
[Display(Name = "Fur Type")]
public string FurLength { get; set; }
[StringLength(50)]
public string Size { get; set; }
}
}
That's because the item you receive from CatRepository.GetByID(id); is of type Cat, not EditCatViewModel.
You can bypass this by constructing a new viewmodel from this object:
Cat cat = unitOfWork.CatRepository.GetByID(id);
var viewModel = new EditCatViewModel {
Name = cat.Name,
Color = cat.Color,
FurLength = cat.FurLength,
Size = cat.Size
};
return View(viewModel);
Alternatively you could construct implicit or explicit casting methods or use a mapping tool like AutoMapper.
Your return view should be of type CatVM.Models.EditCatViewModel now your returning a Cat
return View(cat);
transform your model in a view model and pass this object back to the view

Resources