MVC Create page returning exception - asp.net-mvc

I am having problems getting my create function to work right. I am trying to create an Order object, which has a SalesPerson and Customer object in it. My order model looks like
public class Order
{
public int ID { get; set; }
public SalesPerson SalesPerson { get; set; }
public bool PreviousWork { get; set; }
public OrderStatus Status { get; set; }
public Customer Customer { get; set; }
public List<OrderLineItem> LineItems { get; set; }
}
I then created a view model:
public class OrderViewModel
{
private sunburstdb db = new sunburstdb();
public Order originalOrder { get; set; }
public IList<SelectListItem> SalesPeopleList { get; set; }
public IList<SelectListItem> CustomersList { get; set; }
public IList<SelectListItem> OrderStatusList { get; set; }
public OrderViewModel(Order order)
{
originalOrder = order;
}
}
In my controller I have the following:
//
// GET: /Order/Create
public ActionResult Create()
{
Order order = new Order();
OrderViewModel viewModel = new OrderViewModel(order);
//IList<SelectListItem> result = new List<SelectListItem>();
viewModel.SalesPeopleList = new List<SelectListItem>();
foreach (SalesPerson person in db.SalesPeople)
{
var temp = new SelectListItem();
temp.Text = person.FullName;
temp.Value = person.ID.ToString();
viewModel.SalesPeopleList.Add(temp);
}
//viewModel.SalesPeopleList = new SelectList(result);
//result.Clear();
viewModel.CustomersList = new List<SelectListItem>();
foreach (Customer person in db.Customers)
{
var temp = new SelectListItem();
temp.Text = person.FullName;
temp.Value = person.ID.ToString();
viewModel.CustomersList.Add(temp);
}
//viewModel.CustomersList = new SelectList(result);
return View(viewModel);
}
//
// POST: /Order/Create
[HttpPost]
public ActionResult Create(Order order)
{
if (ModelState.IsValid)
{
db.Orders.Add(order);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(order);
}
Finally my view is pretty standard with a couple of fields to populate the data in the order.
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Order</legend>
<div class="editor-label">
#Html.LabelFor(model => model.originalOrder.SalesPerson)
</div>
<div class="editor-field">
#Html.DropDownList("Order.SalesPerson", Model.SalesPeopleList)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.originalOrder.Customer)
</div>
<div class="editor-field">
#Html.DropDownList("Order.Customer", Model.CustomersList);
</div>
<div class="editor-label">
#Html.LabelFor(model => model.originalOrder.PreviousWork)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.originalOrder.PreviousWork)
#Html.ValidationMessageFor(model => model.originalOrder.PreviousWork)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
When I run this and try to create a new order I get the following: The model item passed into the dictionary is of type 'Models.Order', but this dictionary requires a model item of type 'Models.OrderViewModel'. I thought maybe I needed to change the parameter in the create method to public ActionResult Create(OrderViewModel order) however when I do this the error is: No parameterless constructor defined for this object. Can someone provide some help to an MVC Noob about what I am doing wrong?

in the action pass the viewmodel.
The error you get is because you created only a constructor with parameters, but MVC wnat also a parameterless contructor.
Aps.net 4 will create it automatically for you if you don't specify any constructor, but if you define one, then it don't take initiative creating one that maybe you don't want.
Look here. That should explain better than me

So that happens during model binding as for me.
What is the best way to debug such circumstances is to implement model binder which is inherited from default one and set it as default model binder for your object (Order).
Try to provide more information for more specific answer.
You can use the link below as a sample of custom model binder and registration
http://www.markeverard.com/blog/2011/07/18/creating-a-custom-modelbinder-allowing-validation-of-injected-composite-models/
PS: in my opinion it's not the best way to put models into viewmodels.
but there still are implementations that contain commands and services so it's up to you.

Related

Can not pass data from a view to a controller

I started working with MVC and i am currently working on an application. I ran into a small problem when I'm trying to pass some data from a view to a controller action.
This is my model :
public class TicketIndexModel
{
public IEnumerable<Ticket> ticketList { get; set; }
public Ticket newTicket { get; set; }
}
This is my controller action :
public ActionResult AddTicket(Ticket ticket)
{
string user = User.Identity.Name;
TicketDetail ticketDetails = new TicketDetail();
if (ModelState.IsValid)
{
ticket.DateCreated = DateTime.Now;
ticket.Status = "submitted";
ticket.UserName = user;
db.Tickets.Add(ticket);
db.SaveChanges();
//some other stuff
return RedirectToAction("Index");
}
And in the view, first i show all the tickets and after that I have a small form to add a new ticket. This is how the form looks like.
#using (Html.BeginForm("AddTicket","Ticket",FormMethod.Post)) {
<div class="editor-label">
#Html.LabelFor(model => model.newTicket.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.newTicket.Title)
#Html.ValidationMessageFor(model => model.newTicket.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.newTicket.Description)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.newTicket.Description, new { rows= "8",cols="2"})
#Html.ValidationMessageFor(model => model.newTicket.Description)
</div>
<p>
<input type="submit" value="Submit" />
</p>
}
The problem I am facing is when I try to add a new ticket, the ticket parameter is always null, so If(ModelState.Isvalid) <- is always false and so i can not add new tickets to the DB.
Does anyone have any ideas why ?
Later Edit :
My model is now :
public IPagedList<Ticket> ticketList { get; set; }
//[Required(ErrorMessage ="Title required")]
[Display(Name = "Title")]
public string TicketTitle { get; set; }
//[Required(ErrorMessage="Description Required")]
[Display(Name = "Description")]
public string TicketDescription { get; set; }
My method is now :
[HttpPost]
public ActionResult AddTicket(TicketIndexModel newTicket)
{
string user = User.Identity.Name;
Ticket ticket = new Ticket();
if (ModelState.IsValid)
{
ticket.Title = newTicket.TicketTitle;
ticket.Description = newTicket.TicketDescription;
ticket.DateCreated = DateTime.Now;
ticket.Status = "open";
ticket.UserName = user;
db.Tickets.Add(ticket);
db.SaveChanges();
The problem i now have is the following :
If in the model, i comment [Required] i can add a ticket, if not, in the controller, the newTicket in the signature is null every time i submit a new ticket. But, the controller enters the if(ModelState.IsValid) and i get an error at db.SaveChanges(ticket).
I need both server and client side validation. Can you help me ?
Your AddTicket method should look like this
[HttpPost]
public ActionResult AddTicket(TicketIndexModel ticketIndexModel)
Then access newTicket from the object passed into it.

ASP.NET MVC 4 Navigation Virtual Property not populated on Post Action

I have a navigation property (Category) on a Question class for which I am manually creating a DropDownList for in the Create view of Question, and when posting the Create action, the Category navigation property is not populated on the Model, therefore giving me an invalid ModelState.
Here is my model:
public class Category
{
[Key]
[Required]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual List<Question> Questions { get; set; }
}
public class Question
{
[Required]
public int QuestionId { get; set; }
[Required]
public string QuestionText { get; set; }
[Required]
public string Answer { get; set; }
[ForeignKey("CategoryId")]
public virtual Category Category { get; set; }
public int CategoryId { get; set; }
}
Here is my Question controller for both GET and POST actions of Create:
public ActionResult Create(int? id)
{
ViewBag.Categories = Categories.Select(option => new SelectListItem {
Text = option.CategoryName,
Value = option.CategoryId.ToString(),
Selected = (id == option.CategoryId)
});
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Question question)
{
if (ModelState.IsValid)
{
db.Questions.Add(question);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(question);
}
And here is the Create view for Question
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Question</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Category)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Category.CategoryId, (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
</div>
<div class="editor-label">
#Html.LabelFor(model => model.QuestionText)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.QuestionText)
#Html.ValidationMessageFor(model => model.QuestionText)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Answer)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Answer)
#Html.ValidationMessageFor(model => model.Answer)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
I have tried the following variations of generating the dropdownlist on the view:
#Html.DropDownListFor(model => model.Category.CategoryId, (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
#Html.DropDownListFor(model => model.Category, (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
#Html.DropDownList("Category", (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
#Html.DropDownList("CategoryId", (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
When I quickwatch the Question object on the POST action, the Category property is null, but the CategoryId field on the property is set to the selected Category on the view.
I know I could easily add code to manually fetch the Category with EF by using the CategoryId value that I get from the view. I also think I could create a custom binder to do this, but I was hoping that this could be done with data annotations.
Am I missing something?
Is there a better way to generate the dropdownlist for the navigation property?
Is there a way to let MVC know how to populate the navigation property without me having to manually do it?
-- EDIT:
If it makes any difference, I do not need the actual navigation property loaded when creating/saving the Question, I just need the CategoryId to be correctly saved to the Database, which isn't happening.
Thanks
Instead of
#Html.DropDownListFor(model => model.Category.CategoryId, (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
Try
#Html.DropDownListFor(model => model.CategoryId, (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
Edit:
There is no automatic way to populate Navigation property from the id posted from the form. Because, a database query should be issued to get the data and it should not be transparent. It should be done explicitly. Moreover, doing this operation in a custom binder probably probably is not the best way. There is a good explanation in this link : Inject a dependency into a custom model binder and using InRequestScope using Ninject
I know this question is already answered, but it got me thinking.
So I think I found a way of doing this with some conventions.
First, I made the entities inherit from a base class like this:
public abstract class Entity
{
}
public class Question : Entity
{
[Required]
public int QuestionId { get; set; }
[Required]
public string QuestionText { get; set; }
[Required]
public string Answer { get; set; }
public virtual Category Category { get; set; }
}
public class Category : Entity
{
[Key]
[Required]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual List<Question> Questions { get; set; }
}
So, I also changed the Question model to not have an extra property called CategoryId.
For the form all I did was:
#Html.DropDownList("CategoryId", (IEnumerable<SelectListItem>)ViewBag.Categories, "Select a Category")
So here's the second convention, you'd have to have a property field be named with an Id suffix.
Finally, the CustomModelBinder and CustomModelBinderProvider
public class CustomModelBinderProvider : IModelBinderProvider
{
private readonly IKernel _kernel;
public CustomModelBinderProvider(IKernel kernel)
{
_kernel = kernel;
}
public IModelBinder GetBinder(Type modelType)
{
if (!typeof(Entity).IsAssignableFrom(modelType))
return null;
Type modelBinderType = typeof (CustomModelBinder<>)
.MakeGenericType(modelType);
// I registered the CustomModelBinder using Windsor
return _kernel.Resolve(modelBinderType) as IModelBinder;
}
}
public class CustomModelBinder : DefaultModelBinder where T : Entity
{
private readonly QuestionsContext _db;
public CustomModelBinder(QuestionsContext db)
{
_db = db;
}
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var model = base.BindModel(controllerContext, bindingContext) as T;
foreach (var property in typeof(T).GetProperties())
{
if (property.PropertyType.BaseType == typeof(Entity))
{
var result = bindingContext.ValueProvider.GetValue(string.Format("{0}Id", property.Name));
if(result != null)
{
var rawIdValue = result.AttemptedValue;
int id;
if (int.TryParse(rawIdValue, out id))
{
if (id != 0)
{
var value = _db.Set(property.PropertyType).Find(id);
property.SetValue(model, value, null);
}
}
}
}
}
return model;
}
}
The CustomModelBinder will look for properties of type Entity and load the data with the passed Id using EF.
Here I am using Windsor to inject the dependencies, but you could use any other IoC container.
And that's it. You have a way to make that binding automagically.

Why is my ViewModel empty on [HttpPost]? .NET MVC 3

I'm trying my hardest to use ViewModels correctly in my web application, but I'm running into various problems. One of which, is if I set a breakpoint just after I post using a Create action, my viewModel hasn't stored any of my form values. I must be doing something wrong, but I've tried a few things. Including the code below, where I name the form items the same as the viewModel fields to see if that helps.
I'm also wondering what exactly properties in your viewmodel should represent. I've seen people use different things in blog posts and whatnot.
If the view is going to render a select list, I'm under the impression the viewmodel should hold an IEnumerable SelectListItem for this as below. Yet I've seen people use IEnumerable Entity instead, to represent the type the select list represents.
Can anybody shed some light on this for me? I scrapped my entire business logic last night so I could start a fresh and try and do it correctly.
My ViewModel:
public class ServerCreateViewModel
{
public int Id { get; set; }
// CompanyName represents a field in the Company model. I did this to see if
// it would help with model binding. Beforehand it was Companies to represent the type. I've done the same for the rest of them, so I wont comment on this again.
public IEnumerable<SelectListItem> CompanyName { get; set; }
// Represents the Game model.
public IEnumerable<SelectListItem> GameTitle { get; set; }
//Represents the Location model, etc...
public IEnumerable<SelectListItem> City { get; set; }
public IEnumerable<SelectListItem> NumberOfPlayers { get; set; }
public IEnumerable<SelectListItem> CurrencyAbbreviation { get; set; }
}
My Controller action:
public ActionResult Create()
{
var viewModel = new ServerCreateViewModel();
viewModel.CompanyName = new SelectList(_dataService.Companies.All(), "Id", "CompanyName");
viewModel.GameTitle = new SelectList(_dataService.Games.All(), "Id", "GameTitle");
viewModel.City = new SelectList(_dataService.Locations.All(), "Id", "City");
viewModel.NumberOfPlayers = new SelectList(_dataService.ServerPlayers.All(), "Id", "NumberOfPlayers");
return View(viewModel);
}
[HttpPost]
public ActionResult Create(FormCollection collection, ServerCreateViewModel viewModel)
{
try
{ // I put a breakpoint in here to check the viewModel values.
// If I dont pass the viewModel into the constructor, it doesnt exist.
// When I do pass it in, its empty.
return Content("Success");
}
catch
{
return Content("Fail");
}
}
My View:
#model GameserverCompare.ViewModels.Server.ServerCreateViewModel
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Server</legend>
#Html.HiddenFor(m => m.Id)
<div class="editor-label">
#Html.LabelFor(model => model.CompanyName)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => Model.CompanyName, Model.CompanyName)
#Html.ValidationMessageFor(model => model.CompanyName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.GameTitle)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => Model.GameTitle, Model.GameTitle)
#Html.ValidationMessageFor(model => model.GameTitle)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => Model.City, Model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.NumberOfPlayers)
</div>
<div class="editor-field">
#Html.DropDownListFor(m => Model.NumberOfPlayers, Model.NumberOfPlayers)
#Html.ValidationMessageFor(model => model.NumberOfPlayers)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Since you're using SelectList properties in the form model, you will need to have a different model to represent the selected values in those lists:
public class ServerCreatePostbackModel
{
public int Id { get; set; }
// CompanyName represents a field in the Company model.
public string CompanyName { get; set; }
// Represents the Game model.
public string GameTitle { get; set; }
//Represents the Location model, etc...
public string City { get; set; }
public int NumberOfPlayers { get; set; }
public string CurrencyAbbreviation { get; set; }
}
Have your HttpPost action take one of these as its argument.
Oh, and be sure to use HiddenFor for the Id property, so it gets sent back with the other data.

If Scott Allen can make it work ... why can't I? Should be a simple drop down list - MVC3

I have been wrestling with what should be a very simple thing for weeks now. I simply want to create a dropdownlist in asp.net mvc 3 razor html page and I want the data for the dropdownlist to come from a model.
My Model is as follows which is in the Models.Project namespace.
public class Project
{
public Project()
{
CategoryId = 0;
Name = "";
Description = "";
//Categories = new Dictionary<int, string>();
Entities _db = new Entities(); //ef4
CateogoriesList = from c in _db.Categories
orderby c.Name
select c.Name;
}
public int CategoryId { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Project Name")]
public string Name { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[Display(Name = "Project Description")]
public string Description { get; set; }
public IQueryable<string> CateogoriesList;
}
My Controller action is as follows
public ActionResult Create()
{
Models.Project.Project proj = new Models.Project.Project();
return View(proj);
}
My Razor view has the following relevant code ...
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#model Models.Project.Project
#using (Html.BeginForm())
{
#Html.ValidationSummary(true);
<fieldset>
<legend>Submit Your Request</legend>
<div class="editor-label">#Html.LabelFor( Model => Model.CateogoriesList )</div>
<div class="editor-field">
#Html.DropDownList("Category", new SelectList( Model.CateogoriesList ) )
</div>
</fieldset>
<p><input type="submit" value="Send for RFP" /></p>
}
The problem is that I get the following error ...
Compiler Error Message: CS0135: 'Model' conflicts with the declaration 'System.Web.Mvc.WebViewPage<TModel>.Model'
I saw the following clip make it work with the ViewBag ... and I don't understand why it won't work when I include the list in the model.
http://www.pluralsight-training.net/microsoft/players/PSODPlayer.aspx?author=scott-allen&name=mvc3-building-data-i&mode=live&clip=0&course=aspdotnet-mvc3-intro
I have also seen that there are a lot of people that seem to have trouble with this simple task but in my googling ... I haven't come across anyone with the same error in trying to create a drop down list.
I would appreciate any suggestions that you or anyone may have. The only thing that I've come up with is that the SelectList constructor takes a parameter of type System.Collections.IEnumerable and what I'm trying to pass it is System.Collections.Generic.IEnumerable ... or something close to it ... and I don't know how to cast it appropriately ... though I don't think I should have to ... if it works with a viewbag as the means of transportation why doesn't it work with the model as the means of transportation?
Thanks,
EDIT:======================
The problem was to do with the type of object the selectList constructor would accept. For some reason it wouldn't accept a generic IQueryable but when I cast the result from the entity framework using the cast extension method toArray it suddenly worked.
So my model becomes ...
public class Project
{
public Project()
{
Riebro.RiebroEntities _db = new Riebro.RiebroEntities();
CategoriesList = (from c in _db.Categories
orderby c.Name
select c.Name).ToArray<string>();
}
[Display(Name = "Choose a category")]
public string[] CategoriesList;
}
note the .ToArray on the end of the query and then suddenly
#Html.DropDownList("Category", new SelectList(Model.CategoriesList))
works. Though I am going to point out the Model keyword here seems to be required.
In your view you use:
#model Models.Project.Project
whereas in your controller action you pass:
public ActionResult Create()
{
Riebro.Models.Project.Project proj = new Riebro.Models.Project.Project();
return View(proj);
}
Notice the difference? Models.Project.Project vs Riebro.Models.Project.Project. You don't seem to be using the same type on your controller as on your view.
Also notice that it is bad practice to use namespace names that contain the name of a class.
Another remark is about using the Model keyword in lambda expressions:
#Html.LabelFor(Model => Model.CateogoriesList)
You shouldn't use this keyword. Replace Model with something else.
See your code, what's that? that's the reason cause the error.
<div class="editor-label">#Html.LabelFor( Model => Model.CateogoriesList )</div>
correct one
<div class="editor-label">#Html.LabelFor( Model => Model.CategoryId )</div>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true);
<fieldset>
<legend>Submit Your Request</legend>
<div class="editor-label">#Html.LabelFor(x=>x.CategoryId )</div>
<div class="editor-field">
#Html.DropDownList("Category", new SelectList(Model.CateogoriesList) )
</div>
</fieldset>
<p><input type="submit" value="Send for RFP" /></p>
}
Here is my simulation of your entity. I just add another CategoriesList2 which use to simulate the IQueryable object, but it's still working.
public class Project {
public Project() {
CategoryId = 0;
Name = "";
Description = "";
//Categories = new Dictionary<int, string>();
//Entities _db = new Entities(); //ef4
//CateogoriesList = from c in _db.Categories
// orderby c.Name
// select c.Name;
//IQueryable<string> categoriesList = (new string[] { }).AsQueryable();
CateogoriesList = new string[] { "abc", "def", "hij", "klm" };
CategoriesList2 = (new string[] { "abc", "def", "hij", "klm" }).AsQueryable();
}
public int CategoryId { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Project Name")]
public string Name { get; set; }
[Required]
[DataType(DataType.MultilineText)]
[Display(Name = "Project Description")]
public string Description { get; set; }
public string[] CateogoriesList;
public IQueryable<string> CategoriesList2;
}
Here is the view by using the IQueryable categories list
#model MvcApplication3.Models.Project
#using (Html.BeginForm())
{
#Html.ValidationSummary(true);
<fieldset>
<legend>Submit Your Request</legend>
<div class="editor-label">#Html.LabelFor(x=>x.CategoryId )</div>
<div class="editor-field">
#Html.DropDownList("Category", new SelectList(Model.CategoriesList2) )
</div>
</fieldset>
<p><input type="submit" value="Send for RFP" /></p>
}
You are using the reserved keyword Model in your lambda expression
<div class="editor-label">#Html.LabelFor( Model => Model.CateogoriesList )</div>
try this
<div class="editor-label">#Html.LabelFor( m=> m.CateogoriesList )</div>

ASP.NET MVC DropDownFor Validation (Value cannot be null. Parameter name: source)

I am still struggling with learning ASP.NET MVC. All my form entries are required so I would like to do validation on them. For brevity I have paired my model down to Description (textbox) and Paradigm (dropdown). I am including Entry.cs, Paradigm.cs and EntryViewModel.cs Model classes and the Display.cshtml View.
[Bind(Exclude = "EntryId")]
public class Entry
{
[ScaffoldColumn(false)]
public int EntryId { get; set; }
[Required(ErrorMessage = "You must include a description.")]
public string Description { get; set; }
[Display(Name = "Type")]
[Required(ErrorMessage = "You must select a type.")]
public int ParadigmId { get; set; }
public virtual Paradigm Paradigm { get; set; }
}
public class Paradigm
{
[ScaffoldColumn(false)]
public int ParadigmId { get; set; }
[Required]
public string Name { get; set; }
public List<Entry> Entries { get; set; }
}
public class EntryViewModel
{
public Entry Entry { get; set; }
public IEnumerable<Entry> Entries { get; set; }
}
#model Pylon.Models.EntryViewModel
#{
ViewBag.Title = "Display";
}
<hr />
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Entry</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Entry.Description)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Entry.Description)
#Html.ValidationMessageFor(model => model.Entry.Description)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Entry.ParadigmId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Entry.ParadigmId, ((IEnumerable<Pylon.Models.Paradigm>)ViewBag.PossibleParadigms).Select(option => new SelectListItem {
Text = (option == null ? "None" : option.Name),
Value = option.ParadigmId.ToString(),
Selected = (Model != null) && (option.ParadigmId == Model.Entry.ParadigmId)
}))
<img src="../../Content/Images/add_icon.gif" />
#Html.ValidationMessageFor(model => model.Entry.ParadigmId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
If I submit the form without entering a description I would like validation to kick in and say "You must include a description." However instead I receive an ArgumentNullException on the DropDownFor line. http://www.wvha.org/temp/ArgumentNullException.png
What should I be doing? As an aside any decent books that cover ASP.NET MVC 3/Razor. I can follow along the basic tuts, but I go astray when I need to deviate to more advance features.
public class EntriesController : Controller
{
private readonly PylonContext _context = new PylonContext();
public ActionResult Display()
{
// DropDown
ViewBag.PossibleParadigms = _context.Paradigms;
var viewModel = new EntryViewModel {Entries = _context.Entries.ToList()};
return View(viewModel);
}
[HttpPost]
public ActionResult Display(EntryViewModel viewModel)
{
if (ModelState.IsValid)
{
_context.Entries.Add(viewModel.Entry);
_context.SaveChanges();
return RedirectToAction("Display");
}
return View(viewModel);
}
}
It's quite difficult to say without seeing your controller code, but looks like your ViewBag.PossibleParadigms might be null.
Does your insert/update controller action look something like this?
if (ModelState.IsValid) {
///...
} else {
return View(model);
}
If so, you need to put the PossibleParadigms back into the ViewBag (so to speak) before you return back to the view.
If you can post the relevant controller action code, it would be easier to know for sure.

Resources