views:

1480

answers:

2

I have a View class (OrderView.aspx) which shows the details of an order (Account Name, Order Date) as well as a list of order lines via the Repeater control. Each order line is represented by a User Control View (OrderLineView.ascx) which shows the details of the order line (Item Name, Quantity, Price). I have a model object called Order which I use as the data source for all of this, which I pass as the model object for the view.

Each OrderLineView user control has a Save and a Delete button. I have the Save button posting the contents of a form within the OrderLine control to a Save method on the Controller and then RedirectToAction back to the same Order page (this refreshes the whole page, nothing AJAXy about it). I have the Delete button linking to a method on the Controller that tries to delete, and then RedirectToAction back to the same Order page. If the delete fails, however, I want a little error message to show up next to the delete button when the page renders again(remember, there is a delete button for every order line on the page, so I only want the message next to the one I clicked). My questions:

1 - How do I pass this data from my Controller method to the specific User Control? Should I somehow add it in to the model? Seems like a bad idea (since it really isn't part of the model).

2 - Should I have a OrderLineController for the OrderLine operations as well as a OrderController for Order operations? I just want to know if best practice is to have a separate Controller for every view.

3 - I have seen how some people might call RedirectToAction with an anonymous type value like this:

RedirectToAction("ViewOrder", new { Id = 1234, Message = "blabla"});

but this makes the Message value show up in the URL string. I am OK with that, but would prefer that it doesn't show if possible.

4 - Also, for accessing properties of the Model from within the view, I find myself doing this all of the time:

foo(((someModelType) this.ViewData.Model).SomeProperty);

I don't like this for a number of reasons, one of which is the fact that I don't want my view to be coupled with the type of my model (which is why I am using ViewPage instead of ViewPage). I would much prefer to be able to have a call like this:

foo(ModelEval("SomeProperty"));

Is there such a thing? I have written my own, but would like it if I didn't have to.

+1  A: 

Since your OrderLine has a unique ID you can use that to construct a key to be placed in the ModelState errors container.

public ActionResult Delete(int? Id)
{
    ModelState.AddModelError("OrderLine" + Id.Value, "Error deleting OrderLine# " + Id.Value);

    ...    
}

and then use the ValidatinoMessage helper. This will check the ModelState to see if an error exists and if it does it will display the message. Otherwise it's blank.

<%= Html.ValidationMessage ("OrderLine" + Id)%>

In the next release of MVC Model will become a top level property so the following

foo(((someModelType) this.ViewData.Model).SomeProperty);

can be written as

foo(Model.SomeProperty);

Model objects should already be typed unless you're using public object as a property?

Todd Smith
+3  A: 

1

Check out ModelState.

ViewData.ModelState.AddModelError("something.Name", "Please enter a valid Name");

ModelState is actually a dictionary, so you could identify the errors on a per-control basis. I don't know if this is a best practice, but it would probably work. Try something along the lines of

ViewData.ModelState.AddModelError("something#3.Name", "Please enter a valid Name");

and in your view, you could put

<%= Html.ValidationMessage(string.format({"something{0}.Name", YourUniqueId))%>

4

You can strongly type your view, so you don't need that cast, but if you're concerned about tightly coupling, this may put you off. But having the strong type there is no more tightly coupled than having a magic string point to that property of the model anyway. The former just gives you type safety and the glory that is intellisense.

Rob Rodi