MVC 5 RouteConfig trouble - asp.net-mvc

I have such action:
[ObjectRequired]
public ActionResult Campaign(int? id, SomeClass object = null)
{
...
}
What i need is to route to this action:
a) with only int parameter (.../Campaign/12345)
b) with no parametes (optionally) (.../Campaign)
MVC error says, that there is no nonparametric constructor (if delete "object" parameter - it's ok). But i cant delete "object" parameter, because i need to check some values and pass value from [ObjectRequired] attribute like this:
filterContext.ActionParameters["object"] = _someObject;
I don't want to use constructions like ViewData. Where's the right way?

I'm not 100% on what I'm about to say but I'll say it as if I am...
You can't pass an object through to a get. You could pass back parameters and use a custom route handler to build the object for you.
You could also hold the object in data and use Entity Framework to get the model.
You could also use TempData, but that's similar to ViewData.
You could also hold it in their Session.

Related

ModelBinding a single parameter within an Action

Due to some refection-fu I want to use the MVC ModelBinders to bind the request to an object with a name and Type that is only known at runtime.
e.g.
public ActionResult BindSomething()
{
Type type = typeof(Some.Type);
string parameterName = "someParameter"; //this corresponds to a particular form input name
var binder = Binders.GetBinder(desiredType, true);
var x = binder.BindModel(this.ControllerContext, ???) //??? should be a ModelBindingContext. Where can I get this from
return View(x);
}
I think I need to get hold of the ModelBindingContext, or create a new, valid one, but how do I do this?
edit: apologies if I wasn't clear enough - I already know about TryUpdateModel, but, as far as I understand it that binds ALL the posted values to properties of the model object you pass in. I just want to get the corresponding object for a single posted parameter.
You can use TryUpdateModel as rouen suggested, you could also implement a custom model binder that can bind the correct type. This approach has the advantage of letting you deal with Interfaces or Abstract models and keeps your binding code out of your actions. It's a little neater but I would only really recommend it if it's going to be reused in other parts of your code.
Use controller method TryUpdateModel
http://msdn.microsoft.com/en-us/library/system.web.mvc.controller.tryupdatemodel.aspx
It will choose appropriate binder according argument type and perform model binding for you.

RedirectToAction not passing all parameters

I have these two methods in the same Controller, the first passing two parameters to the second.
When debugging, the list (model.RequestedProducts) passed is correct (not empty) but on the second method, only idOR is read correctly, List<OCS> RequestedProducts is empty.
[HttpPost]
public ActionResult Index(int idOR, ViewModel model, string add, string remove, string send)
{
//...
return RedirectToAction("Done",
new { idOR = idOR,
RequestedProducts = model.RequestedProducts});
}
public ActionResult Done(int IdOR, List<OCS> RequestedProducts)
{ ...
What am I missing?
Is there maybe a better way to do it? (other than Redirect to Action)
Thank you
When you use RedirectToAction you are returning a message to the client to request a new URL probably something like /controller/action/id. You Routes will define how the URL is formed. I am guessing you have the default route defined and in your case MVC has no way of knowing how to deserialise your RequestedProducts type into a URL and then bind it back into a List type.
Instead you could use the TempData object to pass data between to Action requests.
The TempData property value is stored in session state. Any action method that is called after the TempDataDictionary value is set can get values from the object and then process or display them. The value of TempData persists until it is read or until the session times out.
This MSDN article explains it all.

In ASP.Net MVC, how can you use TryUpdateModel to update from a specific object

I have a controller post action that receives an IList<> as a parameter, and would like to iterate that list and TryUpdateModel for each item in the list. Like
[HttpPost]
public ActionResult SaveList(IList<Stuff> listOfStuff)
{
// Get existing list of Stuff objects
IList<Stuff> currentStuff = db.GetStuffList();
// iterate over list of Stuff
foreach (Stuff stuff in listOfStuff)
{
// I'd like to do something akin to this
TryUpdateModel(currentStuff[correspondingItem_to_stuff], stuff);
}
As you can see, I would like to be able to TryUpdateModel against each item in listOfStuff, but there is no direct way to make that call with the two Stuff objects. What is the best way of accomplishing this?
Thanks
If you want currentStuff to be the same as list of stuff you just have to UpdateModel(currentStuff). UpdateModel is for copying posted http request related values values into an object and not for copying the properties of two objects.
UpdateModel and TryUpdateModel must receive a type of ValueProvider (a FormCollection for example). validate the posted object in your controller or service layer and then let your DB layer handle the add/update by using attach() or applycurrentvalues() (if your using Entity Framework for example)
It looks like this is not supported directly. After some more searching I found a couple of links, the most useful of which was
Passing Controller a FormCollection and an IList
This post has a couple of other useful links in it. I ended up rolling it myself unfortunately, and using TempData as detailed here to recover in the case where saving the form data fails.

ASP.NET MVC - Passing a parameter to my action method?

public ActionResult RenderMyThing(IList<String> strings)
{
return View("RenderMyView");
}
How do I pass in strings?
routes.MapRoute("MyRoute", "RenderMyThing.aspx", new { controller = "My", action = "RenderMyThing" });
Is there a way I could pass in strings here?
Secondly, how does ASP.NET MVC know that action is my action, and controller is my controller. Like I saw this in samples, and it does work, but isn't it just an anonymous object with no type?
This is the provenance of model binding: the framework needs to have some instruction as to how to turn a "request", which comes out of the routing context, query string, forms collection, etc., into the parameters that your action method wants.
The DefaultModelBinder will generate a list if it sees that you have multiple key-value pairs with the same key (and appropriately typed/convertible values) - for the details, Phil wrote a good post about this:
If you need fancier binding requirements, you can implement a custom model binder and explicitly define how route values and the other bits get translated into objects (or collections of objects).

How to pass an unpersisted modified object from view back to controller without a form?

Short: how does modelbinding pass objects from view to controller?
Long:
First, based on the parameters given by the user through a search form, some objects are retrieved from the database.
These objects are given meta data that are visible(but not defining) to the customer (e.g: naming and pricing of the objects differ from region to region).
Later on in the site, the user can click links that should show details of these objects.
Because these meta data are important for displaying, but not defining, I need to get the previously altered object back in the controller.
When I use the default asp.net mvc modelbinding, the .ToString() method is used. This off course doesn't return a relevant string for recreating the complete object.
I would have figured the ISerializable interface would be involved, but this is not so.
How should I go about to get the desired effect? I can't imagine I'm the first one to be faced with this question, so I guess I'm missing something somewhere...
The default model binding takes form parameters by name and matches them up with the properties of the type specified in the argument list. For example, your model has properties "Price" and "Name", then the form would need to contain inputs with ids/names "Price" and "Name" (I suspect it does a case insensitive match). The binder uses reflection to convert the form values associated with these keys into the appropriate type and assigns it to the properties of a newly created object of the type specified by the parameter (again derived by reflection).
You can actually look at (and download) the source for this at http://www.codeplex.com/aspnet, although you'll have to drill down into the MVC source from there. I'd give a link to the DefaultModelBinder source, but the way they are constructed, I believe the link changes as revisions are introduced.
So, to answer your question, you need to have parameters (could be hidden) on your form that correspond to the properties of the object that you want to recreate. When you POST the form (in the view) to the controller, the binder should reconstitute an object of the specified type using the form parameters. If you need to do translation from the values in the form parameter to the object properties, you'll probably need to implement your own custom model binder.
[EDIT] In response to your second post:
Let's say that we want to have a link back to an action that uses a customized object. We can store the customized object in TempData (or the Session if we need it to last more through more than one postback) with a particular key. We can then construct the action link and provide the key of the object as value to the ActionLink in an anonymous class. This will pass back the key as a Request parameter. In our action we can use the key from this parameter to retrieve the object from TempData.
<%= Html.ActionLink( ViewData["CustomObject1",
"Select",
new { TempDataKey = ViewData["CustomObject1_Key"] }
) %>
public ActionResult Select()
{
Entity custObj = null;
string objKey = Request.Params["TempDataKey"];
if (!string.IsNullOrEmpty(objKey))
{
custObj = (Entity)TempData[objKey];
}
... continue processing
}
#tvanfosson
Thanks for your explanation, but what about links? (no forms involved)
Currently the Html.ActionLink(c=>c.Action(parameter), "label") takes objects as parameter. These have to be translated into URL parts. For this, MVC ALWAYS goes to the .ToString() method. I don't want to serialize my object in the ToString method.
Shouldn't I be able to somehow help the framework serialize my object? Say through the ISerialize interface or something?

Resources