How to control error keys using ModelStateWrapper= - asp.net-mvc

I’m using the a service layer with a ModelStateWrapper as shown here.
What’s he proper way to control the error keys to use when validating in the service layer so they correspond to the input names in my views?
e.g. I have the following ViewModel for a customer:
public class CustomerViewModel
{
public string Name { get; set; }
/*…*/
}
And the following ViewModel for some use case’s View (the user can create two customers on the fly in this use case by entering their names):
public class SomeOtherUseCaseViewModel
{
public CustomerViewModel BuyingCustomer { get; set; }
public CustomerViewModel SellingCustomer { get; set; }
/*… */
}
Which I use in the View like this:
<!-- … -->
<%: Html.EditorFor(model => model.BuyingCustomer.Name) %>
<%: Html.ValidationMessageFor(model => model.BuyingCustomer.Name) %>
<!-- … -->
<%: Html.EditorFor(model => model.SellingCustomer.Name) %>
<%: Html.ValidationMessageFor(model => model.SellingCustomer.Name) %>
In my customer service I’ve the following validation method which gets called when creating the customer (note that this is a different Customer class, this is a domain class):
public bool ValidateCustomer(Customer customer)
{
/* Check if there is another customer with the same name */
if (/*…*/)
{
_validationDictionary.addError(“Name”, “There is another customer with the same name”); //the _validationDictionary holds the ModelStateWrapper
return false;
}
}
Do you see my problem?
Depending on the View, the error should be added with the key “BuyingCustomer.Name” or “SellingCustomer.Name” (or eventually there will be two errors, one with each key) instead of just “Name”; otherwise the framework won’t properly highlight the fields and show the errors.
What is the proper way to solve this situation neatly? I don't want to pass the "error key prefix" to the service layer, because that's a UI concern and not a service layer concern, (right?).

I'd take it later you query the service for any validation errors?
Either query service immediately after validation then reset the errors, or have the method call the return validation errors. If you do either of those you can prefix them with( prefix(this validationDictionaryObject, string pfx) ) an extension method for the dictionary, the api wouldn't be too bad that way. A second extension method (HasErrors()) for the dictionary would do the same as your boolean return
For the problem you are having alone, i tend to eschew querying the service for errors.
It's convenient to have the service collect them all, but then you are adding error state to a service that doesn't really belong, its not that the service is broken, but one model it checked was. If you need to call that service again (like you are doing) it has old state. You have to manage that. Either that or return errors because
after all, its a validation method. Have it return validation results. :)
var errs = service.ValidateCustomer(sellinCustomer);
if (errs.HasErrors()){
errs.Prefix("SellingCustomer");
//add to model state dictionary for view here.
}

Related

MVC view model decoupling

I am at the very first step of MVC.
In my first example I have a Model like so:
public class GuestResponse
{
[Required(ErrorMessage = "Please enter your name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter your email")]
[RegularExpression(".+\\#.+\\..+", ErrorMessage = "Please enter a valid email address")]
public string Email { get; set; }
public string Phone { get; set; }
[Required(ErrorMessage = "Please specify whether you'll attend")]
public bool? WillAttend { get; set; }
}
the Controller:
public class HomeController : Controller
{
public ViewResult Index()
{
ViewData["greeting"] = (DateTime.Now.Hour < 12 ? "Good morning" : "Good afternoon");
return View();
}
[HttpGet]
public ViewResult RsvpForm()
{
return this.View();
}
[HttpPost]
public ViewResult RsvpForm(GuestResponse guestResp)
{
if (ModelState.IsValid)
{
return this.View("Thanks", guestResp);
}
else
{
return this.View();
}
}
}
and a View:
<body>
<div>
<h1>
Thank you,
<%: Model.Name %>.</h1>
<p>
<% if (Model.WillAttend == true)
{ %>
It's great that you're coming. The drinks are already in
the fridge!
<% }
else
{ %>
Sorry to hear you can't make it, but thanks for letting
us know.
<% } %>
</p>
</div>
What seems strange to me, is that the View is thightly coupled with the Model: it uses code like Model.WillAttend ecc... So what happen if in a future time the Model changes? I should have to change all the snippets inside this particular View (but possibly also in many other views...)
Is this tight-coupling or am I missing the point here?
EDIT
In the book the Author points out that this useful mechanism is
Model Binding
Given that the method [public ViewResult RsvpForm(GuestResponse guestResp)] is being
invoked via an HTTP request, and that GuestResponse is a .NET type that is totally unknown to HTTP,
how can an HTTP request possibly supply a GuestResponse instance? The answer is model binding, an
extremely useful feature of ASP.NET MVC whereby incoming data is automatically parsed and used to
populate action method parameters by matching incoming key/value pairs with the names of properties
on the desired .NET type.
This powerful, customizable mechanism eliminates much of the humdrum plumbing associated
with handling HTTP requests, letting you work primarily in terms of strongly typed .NET objects rather
than low-level fiddling with Request.Form[] and Request.QueryString[] dictionaries, as is often
necessary in Web Forms. Because the input controls defined in RsvpForm.aspx render with names
corresponding to the names of properties on GuestResponse, the framework will supply to your action
method a GuestResponse instance already fully populated with whatever data the user entered into the
form.
My two cents: but so, this mechanism give you the advantage of strongly typed classes inside the View (which, however, is really useful thanks to Visual Studio Intellisense feature, otherwise in my opinion also the Request.Form[] syntax would fit the same). On the other hand, you are tightly coupling the View with the Model, so that every tiny change to the Model will result in a cascade of changes on linked Views.
Is this tight coupling or am I missing the point here
Yes it is tight coupling and the point you maybe missing is - this isn't the M in MVC, this is a different type of model called a view model and it's supposed to be tailored for a specific view so it makes sense that it's coupled.
It's generally known as MVVM, a derivation of MVC which introduces the notion of view models to de-couple your actual model from the view.

ASP.NET MVC 4 - Complex Types and Model Binding/Rendering

I've seen a number of similar questions to this, but none seem to have an answer that gets me any further than I am already.
I have a ViewModel that contains some complex types that represent certain stock UI controls and have some validation logic attached. I need to get these to render to a page based on an EditorTemplate/DisplayTemplate and also need the properties to bind properly on submission of the form so that the developer can use the view model within their controllers etc.
Simple example of this is
public class TestViewModel
{
public HierarchyField MyField {get; set; }
}
At it's simplest, I need the developer to be able to create an editor for this view model with a simple
#Html.EditorForModel()
And for any editable parts of the HierarchyField, fields to be set up within a custom EditorTemplate for that type.
I've gotten as far as allowing this to render, by using a custom MetaDataProvider and overriding IsComplexType which, although not something I'm entirely comfortable with, does do the job. Details of that solution are here (http://blogs.msdn.com/b/stuartleeks/archive/2010/04/01/collections-and-asp-net-mvc-templated-helpers-part-3.aspx?Redirected=true)
I'm now stuck trying to get the model binding to update the property on submission of the form and to call a method on the HierarchyField class to perform a little custom validation and update the ModelState based on the result of that call.
I first created a subclass of DefaultModelBinder that had logic within the BindProperty override to check whether the property being bound was of this type. All good so far. Problem comes when I want to call the instance method that takes the intended value and attempts validation of that value. The BindProperty method gives me an instance of PropertyDescriptor which allows me to find the metadata about my property, and a BindingContext with a ValueProvider that allows me to read the value, however, there's not an instance of my complex type returned from:
bindingContext.ValueProvider.GetValue(propertyDescriptor.Name + ".Value")
Where propertyDescriptor.Name + ".Value" equates to the fact that in my EditorTemplate I have the following:
#Html.TextBoxFor(model => model.Value)
Instead of the type, because I've obviously only got a reference to the Value property in the fields that are posted back, I get a String[]. I'm assuming, to get this to work, I will need to register a ValueProvider of some sort for HierarchyField, but ideally I'm looking for something a little more generic, as I have a number of these types to set up, all of which subclass a common abstract type (which all have a property called 'Value' which returns a string representation of their value).
If I'm honest, this whole process seems so painful that I feel like I'm missing something really simple to do this. Unfortunately, I do need this to be generic as there are dozens of these fields, and I do need this model, or something similar for the fields to handle their validation as much of this cannot be done with DataAnnotation validation attributes. I cannot create custom code that's tied to a specific view model and I'd prefer to minimise code that's tied to a specific field, prefering something that applies to the base class (FieldBase) and any of its subclasses.
Happy to post additional code if anyone needs to see it.
I've been using complex types and custom rendering in a few projects without any problems. Maybe I've misunderstood your question but I thought I can post a simplified working example (MVC4) and maybe it'll help you on the way.
In my example the complex type is defined as:
[ComplexType]
public class AccessType
{
public bool ReadAccess { get; set; }
public bool EditAccess { get; set; }
}
The model is defined as:
public class UserAccess
{
[Key]
public Int32 UserId { get; set; }
public AccessType AccessType { get; set; }
}
I've created the following display template in Views\Shared\DisplayTemplates named AccessType.cshtml to handle the rendering of the complex type when it's being displayed.
#model [path to complex type].AccessType
#Html.LabelFor(m => m.EditAccess,"Read access")
#Html.DisplayFor(m => m.ReadAccess)
#Html.LabelFor(m => m.EditAccess, "Edit access")
#Html.DisplayFor(m => m.EditAccess)
I've created the following edit template in Views\Shared\EditorTemplates named AccessType.cshtml to handle the rendering of the complex type when it's being edited.
#model [path to complex type].AccessType
#Html.LabelFor(m => m.ReadAccess,"Read access")
#Html.CheckBoxFor(m => m.ReadAccess)
#Html.LabelFor(m => m.EditAccess, "Edit access")
#Html.CheckBoxFor(m => m.EditAccess)
To the view files for the model using this complex type I've made the following changes:
To the _CreateOrEdit.cshtml file I've added this line to render the complex type part:
#Html.EditorFor(m => m.AccessType)
...to Delete.cshtml and Details.cshtml I've added:
#Html.DisplayFor(m => m.AccessType)
...and to Index.cshtml I've added:
#Html.DisplayFor(_ => item.AccessType)
That was all I needed to render and to use the complex type.
If your problem is more complex then please add some more code to illustrate.

MVC Validation Fundamentals (with Entity Framework)

MVC Validation Fundamentals (with Entity Framework)
Scenario:
I have a model class as below (autogenerated via Entity Framework EF.x DbContext Generator).
(There is no view model at the moment).
public partial class Activity
{
public int Id { get; set; }
public byte Progress { get; set; }
public decimal ValueInContractCurrency { get; set; }
public System.DateTime ForecastStart { get; set; }
public System.DateTime ForecastEnd { get; set; }
public int DepartmentId { get; set; }
public int OwnerId { get; set; }
public int StageId { get; set; }
public int StatusId { get; set; }
public virtual Department Department { get; set; }
public virtual Owner Owner { get; set; }
public virtual Stage Stage { get; set; }
public virtual Status Status { get; set; }
}
When I submit a blank form on the strongly-typed view, I get these validation messages:
The Progress field is required.
The ValueInContractCurrency field is required.
The ForecastStart field is required.
The ForecastEnd field is required.
i.e. all the fields in the db table.
If I fill these in, and submit again, then the controller gets called. The controller then returns back to the view page due to IsValid being false.
The screen is then redisplayed with these validation messages:
The StageId field is required.
The DepartmentId field is required.
The StatusId field is required.
The OwnerId field is required.
i.e. all the foreign key fields in the db table (these are also all select boxes).
If I fill these in, the form then submits succesfully and is saved to the db.
Questions:
Where is the validation coming from, given that I have not used any [Required] attributes? Is this something to do with entity framework?
Why is the form not validating everything right away client-side, what's different about foreign keys (or select boxes) that they are only checked by IsValid() even though they are empty and therefore clearly invalid?
How do you make everything get validated in one step (for empty fields), so the user does not have to submit the form twice and all validation messages are shown at once? Do you have to turn off client side validation?
(I tried adding [Required] attributes to the foreign key fields, but that didn't seem to make any difference (presumably they only affect IsValid). I also tried calling Html.EnableClientValidation() but that didn't make any difference either).
4..Lastly, I've seen people using [MetadataType[MetadataType(typeof(...)]] for validation. Why would you do that if you have a viewmodel, or is it only if you don't?
Obviously I'm missing some fundamentals here, so in addition if anyone knows of a detailed tutorial on how exactly the MVC validation process works step-by-step including javascript/controller calls, rather than just another essay on attributes, then I could do with a link to that too :c)
More info for Mystere Man:
Solution setup as follows:
.NET4
MVC3
EF5
EF5.x Db Context Generator
"Add Code Generation Item" used on edmx design surface to associate EF.x Db Context Generator files (.tt files)
Controller looks like this:
// GET: /Activities/Create
public ActionResult Create()
{
ViewBag.DepartmentId = new SelectList(db.Departments, "Id", "Name");
ViewBag.OwnerId = new SelectList(db.Owners, "Id", "ShortName");
ViewBag.ContractId = new SelectList(db.Contracts, "Id", "Number");
ViewBag.StageId = new SelectList(new List<string>());
ViewBag.StatusId = new SelectList(db.Status.Where(s => s.IsDefaultForNewActivity == true), "Id", "Name");
return View();
}
// POST: /Activities/Create
[HttpPost]
public ActionResult Create(Activity activity)
{
if (ModelState.IsValid)
{
db.Activities.Add(activity);
db.SaveChanges();
return RedirectToAction("Index");
}
ViewBag.DepartmentId = new SelectList(db.Departments, "Id", "Name");
ViewBag.OwnerId = new SelectList(db.Owners, "Id", "ShortName");
ViewBag.ContractId = new SelectList(db.Contracts, "Id", "Number");
ViewBag.StageId = new SelectList(db.Stages, "Id", "Number");
ViewBag.StatusId = new SelectList(db.Status, "Id", "Name");
return View(activity);
}
View is like this:
<!-- this refers to the EF.x DB Context class shown at the top of this post -->
#model RDMS.Activity
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Activity</legend>
<div class="editor-label">
#Html.LabelFor(model => model.StageId, "Stage")
</div>
<div class="editor-field">
#Html.DropDownList("StageId", String.Empty)
#Html.ValidationMessageFor(model => model.StageId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Progress)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Progress)
#Html.ValidationMessageFor(model => model.Progress)
</div>
<!-- ETC...-->
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
The reason why you get required validation is because the properties are value types (ie they can't be null). Since they can't be null, the framework requires you fill in values for them (otherwise it would have to throw some weird exception).
This problem manifests itself in several ways. I've seen this over and over and over here on Slashdot. I am not sure why so many people fall into this problem, but it's pretty common. Usually this results in a strange exception referring to no default constructor being thrown, but for some reason that did not happen here.
The problem stems from your use of ViewBag and naming the items in ViewBag the same as your model properties. When the page is submitted, the model binder gets confused by similarly named items.
Change these to add List at the end:
ViewBag.DepartmentList = new SelectList(db.Departments, "Id", "Name");
ViewBag.OwnerList = new SelectList(db.Owners, "Id", "ShortName");
ViewBag.ContractList = new SelectList(db.Contracts, "Id", "Number");
ViewBag.StageList = new SelectList(new List<string>());
ViewBag.StatusList = new SelectList(db.Status
.Where(s => s.IsDefaultForNewActivity == true), "Id", "Name");
And change your view to use the strongly typed versions of DropDownListFor:
#Html.DropDownList(x => x.StageId, ViewBag.StageList, string.Empty)
... and so on
One other item of note. In the example above, I hope you're not using some kind of global data context or worse, a singleton. That would be disastrous and could cause data corruption.
If db is just a member of your controller that you new up in the constructor, that's ok, though not ideal. A better approach is to either create a new context in each action method, wrapped by a using statement (then the connection gets closed and destroyed right away) or implement IDisposable on the controller and call Dispose explicitly.
An even better approach is not doing any of this in your controller, but rather in a business layer, but that can wait until you're further along.
Where is the validation coming from, given that I have not used any [Required] attributes? Is this something to do with entity framework?
There is a default validation provider in MVC (not EF), checking two things :
the type of the provided value (a string in an int property) => (not sure, but something like) yyy is not valid for field xxx
a "check null" attribute for Value types (it will complain if you let an empty field corresponding to an int property, and would accept an empty field for an int? property). => The xxx field is required
This second behaviour can be desactivated in global.asax (the property name is rather clear) :
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes = false;
With client side validation enabled, these validations, and the one related to DataAnnotations (Required, StringLength...) will raise Validation errors on client side, before going to the Controller. It avoids a roundtrip on the server, so it's not useless. But of course, you can't rely on client validation only.
Why is the form not validating everything right away client-side, what's different about foreign keys (or select boxes) that they are only
checked by IsValid() even though they are empty and therefore clearly
invalid?
Hmmm, I must admit I ain't got a satisfying answer... So I let this one for a more competent one. They are taken as error in the ModelState.IsValid, because when the ClientSide Validation passed, you then go to ModelBinding (Model binding looks at your POSTed values, looks at the arguments of the corresponding HttpPost method (ActionResult Create for you), and try to bind the POSTed values with these arguments. In your case, the binding sees a Activity activity argument. And he doesn't get anything for StageId (for example) in your POSTed fields. As StageId is not nullable, he puts that as an error in the ModelState dictionary => ModelState is not valid anymore.
But I don't know why it's not catched by Client side validation, even with a Required attribute.
How do you make everything get validated in one step (for empty
fields), so the user does not have to submit the form twice and all
validation messages are shown at once? Do you have to turn off client
side validation?
Well, you'd have to turn off client validation, as you can't trust client validation only. But client validation, as said, is fine to avoid a useless roundtrip to the server.
Lastly, I've seen people using
[MetadataType(typeof(...)]] for validation. Why would you
do that if you have a viewmodel, or is it only if you don't?
It's only if you ain't got a ViewModel, but work on your Model class. It's only usefull when you work with Model First or Database First, as your entity classes are generated (with T4) each time your edmx changes. Then, if you put custom data annotations on your class, you would have to put it back manually after each class (file) generation, which would be stupid. So the [MetadataType(typeof()]] is a way to add annotations on a class, even if the "base class files" are re-generated.
Hope this helps a bit.
By the way, if you're interested in validation, take a look on FluentValidation.
This is a very nice... fluent validation (would you have guessed ?) library.
If the field is not nullable, EF think that it is required.
Cause foreign keys is not nullable, so navigation properties is required too.
To get all validation at once you need to use ViewModel that is transformed in entity mode in controller after validation.
More about attribute validation in mvc, you can read here.

MVC 3 Model Binding without Key

I have a question about ASP.NET MVC3 model binding. If I have a class I'm trying to use as a model, but I don't want the key put on the page, the model doesn't bind on a POST. Here is an example:
//Data Model
public class MyModel
{
[Key]
public string MyKey {get;set;} //Perhaps this is an ssn that I don't want on the form.
public string MyValueToGet {get;set;} //This is the value I want the user to enter.
}
//Conroller code.
public ViewResult Index()
{
MyModel model = new MyModel{ MyKey = "SecretInfo", MyValueToGet = "" };
return View(new model);
}
public ActionResult Edit(MyModel model)
{
repository.SaveChanges(model)
}
//View code.
#using(Html.BeginForm("Edit", "Home", FormMethod.Post))
{
Enter a value: #Html.EditorFor(m => m.MyValueToGet)
<input type="submit" value="Salve" />
}
So my problem is that model is null when the Edit method is called upon form submission. I can fix this by putting MyKey somewhere on the page (perhaps as a hidden field), but that is unacceptable if it is some sort of sensitive data. Is there a way to solve this problem? I am new to MVC, so I appreciate any help.
Create another unique but otherwise meaningless identifier like an (auto increment int) and use that to bind.
in other words modify your model to something like:
public class MyModel
{
[Key]
public int ID {get; set;}
public string MyKey {get;set;} //Now this can be sensitive, it doesn't matter because you no longer rely on it.
public string MyValueToGet {get;set;} //This is the value I want the user to enter.
}
EDIT
I believe your best choice would be to change the MyModel object, as it's design is flawed. The primary key in the majority of cases (and I think this is one of them) should be a simple auto incrementing integer, meaningless apart from it's role as the table's key.
While Luke's suggestion to use Session is a viable option and a solution that would work, I would personally do something similar to what I'll explain here, as it would seem to me to be more of the 'mvc way' of doing things.
Data model:
Either change your current model to something like what I suggest above, or, if that is not feasible for whatever reason (breaking dependancies or FK relationships), create a new table that can be used as a join, or proxy, if you will:
public class Proxy
{
public int ProxyId {get;set;}
public MyModel MyModel {get; set;}
}
Obviously, you'd have to do some work to populate this table, but you would then be able to use it to fetch records from MyModel without accessing the MyKey property directly.
It's not considered good practice to use your data models directly in your views, so you want to create a view model as well
public class MyModelViewModel
{
public int ModelId {get; set;}
public string ModelValueToGet {get; set;}
}
Notice we don't even need the key containing sensitive data in the view model.
Then type your view to the viewModel, not the data model, and include a hidden field for the ModelId
#using(Html.BeginForm("Edit", "Home", FormMethod.Post))
{
Enter a value: #Html.EditorFor(m => m.ModelValueToGet)
#Html.HiddenFor(m => m.ModelId)
<input type="submit" value="Save" />
}
Now in your controller you have your get method
public ViewResult Index()
{
//fetch the users record from the database
//if you're using the Proxy table, you'll want to write a LINQ query here
//instantiate a viewModel and populate it's properties using the fetched record
//remember, the viewModel.ModelId should be set to MyModel.ID or Proxy.ProxyId
//render the view
}
And the post method
public ViewResult Edit (MyModelViewModel viewModel)
{
//fetch the users record from the database using viewModel.ModelId
//If you're using the proxy table, you'll need to use that LINQ query again here
//update the record you fetched with the new data the user just entered
//you have complete control here of what gets updated and what stays the same
//pass the updated record to the repository to save the changes.
//redirect the user to be on their merry way
}
I think that's about as well as I can lay it out. Hope it makes sense.
An alternative is to encrypt the id before sending it to the client. Check this post for more information on how to accomplish this.
Asp MVC 3: Modifiy Values Sent to View

Returning data with viewmodel in POST request

I have a view model like such:
public class MyViewModel
{
public string Name { get; set; }
public List<Purchases> Purchases { get; set; }
}
This viewmodel is sent to a view that allows the user to edit the name property. The Purchases property is used only to create a dropdown box for it:
<%: Html.DropDownListFor(t => t.Name, new SelectList(Model.Purchases, "Value", "Text")) %></p>
This works fine.
However, when I perform server-side validation and then return to the View, I'm getting an object null reference error because the Purchases property is now set to null. I'm guessing this is because when the form is submitted because the Purchases property isn't bound to any editable control, it isn't being passed back with the viewmodel.
How can I prevent this happening? I want to send back the List to be send back with the Post request always.
You don't need to send back the list. If validation fails then simply rebuild the view model from scratch. One of the main selling points of MVC is how well it works in a stateless environment. Web Forms used ViewState to do this kind of thing, I don't think you want to replicate this kind of functionality though.
I like to have two overloaded Action methods for this (both with the same name but different method signatures). One with an [HttpGet()] attribute and the other with an [HttpPost()]. If your model is found to be invalid on the POST then simply return the "GET" method (NOTE: you'll need to to pass in any parameters required to rebuild the view).
When I say return, I mean:
return MyGetAction();
and not a Redirect to the GET action.
If the model is valid then you could/should perform a RedirectToAction() to a GET Action (this means if the user hits the refresh button it won't submit the form again, this is called the Post/Redirect/Get (PRG) pattern)
You'd have to create a hidden input for each of the elements in the list in addition to the select list. Having said, that I think caching the results of the query on the server is a better way to handle repopulating the list if you don't want to perform the query again. There's no sense in sending the data back across the wire if the server can just hang on to it. Personally, I wouldn't even bother with the caching unless it proved to be a performance bottleneck. Just populate the model selection list from the DB.
<% for (int i = 0; i < Model.Purchases.Length; ++i) { %>
<%: Html.Hidden( string.Format( "Purchases[{0}]", i ), Model.Purchases[i] ) %>
<% } %>
Lee Gunn is spot on. To make the answer a little more concrete, it is very common to re-build non-scalar values in the event ModelState is not valid. This can be done by simply returning the [HttpGet] version in your Controller. However, you could simply re-build the purchases collection manually. It's up to you.
[HttpGet]
public ActionResult MyView(string name)
{
//get entity and build up a view model
var entity = _myDb.GetEntity(name);
MyViewModel vm = AutoMapper.Map<Entity, MyViewModel>(entity);
return vm;
}
[HttpPost]
public ActionResult MyView(MyViewModel vm)
{
If(!ModelState.IsValid)
{
//here is one way of doing it
return MyView("");
//OR
vm.Purchases = GetSomePurchasesBro();
return View(vm);
}
//continue on persisting and doing the Post Redirect Get
}
P.S.
Calling
return MyView("");
can be replaced with
return MyView(vm.Name);
Both will do the same thing (provided you're using the Html Helper Extensions, i.e. Html.TextBoxFor(x=>x.Name))
Defaut model binding looks in the ModelState for attemptedValues when rendering Html. This is described here by Steve Sanderson.

Resources