ASP.NET MVC Model List in controller - asp.net

I'm using ajax and trying to pass the Model back, which is a generic List < T >. I tried Model.ToList() but I don't think I'm going about this correctly. I think it is already setup but I just need to find the method or property name to get the List that was posted, which might not work since my Model from the controller contains a couple of lists to pass to different partials and one of these partials, I'm trying to update the partial view. I'm basically trying to sort the list. So using an AJAX to call the controller but I need the list to sort and call the partial again. I hope my explanation wasn't too confusing.

If these are just single values you are passing back, such as int, strings, floats, etc. You can just put the array in the action like so:
public ActionResult MyAction (int id, string[] value)
Or you can use something called a FormCollection
public ActionResult MyAction (int id, FormCollection form) {
string[] values = form.GetValues("value");
Or you can use Request.Form (this is not recommended, because the above two are more recommended
public ActionResult MyAction(int id) {
string[] values = Request.Form.GetValues("value");
Hope this helps. I didn't totally understand what your question was, but it seemed to be dealing with how to get an array of posted values.

Related

Too many select lists polluting my controller actions

I have an ASP.Net MVC application and some of the controller actions have about 10 select lists (others have more). Currently my code looks like this:
public ActionResult Edit(int carId)
{
CreateCar model = new CreateCar();
model.Makes = Helper.Makes();
model.Models = Helper.Models();
model.Colors = Helper.Colors();
model.EngineSizes = Helper.EngineSizes();
model.Materials = Helper.Materials();
model.FuelTypes = Helper.FuelTypes();
model.WheelSizes = Helper.WheelSizes();
model.BodyTypes = Helper.BodyTypes();
//more select lists below this
return View(model)
}
In my views i setup select lists like this:
#Html.DropDownListFor(x => x, Model.Makes)
I have code that looks like this in a number of actions and i feel there is a better way of doing this so my actions are not polluted with these select lists.
The only option i can think of to get around this is to actullly call the Helper class in the views e.g.
#Html.DropDownListFor(x => x, Helper.Makes())
Is this approach considered bad practice and are there any other approaches to deal wi this issue?
Generally, yes, it's bad practice to do things like that in your view. The controller is responsible for wiring everything up, so your code should go there. Now, it depends a lot on what your Helper class is doing. If the select lists are just generated via some bit of code, it's probably not that bad for that to happen in the view, but what you don't want to be doing is issuing database queries while the view is being rendered. If your helper is interacting with a database, then keep it in the controller.
That said, what is the real issue here? Sure that's a lot of select lists, but I wouldn't go so far as to say it's "polluting" your action. It's very clear what your doing. The action is responsible for creating the model for your view, and that's what it's doing. Just because there may be a lot of lines in your code, doesn't necessarily mean it's "bad" or "wrong".
However, if you're repeating this in a lot of places, I would recommend factoring it out into a private or protected method on your controller. For example:
public ActionResult Edit(int carId)
{
...
PopulateSelectLists(model);
return View(model);
}
[HttpPost]
public ActionResult Edit(Foo model, int carId)
{
...
PopulateSelectLists(model);
return View(model);
}
private void PopulateSelectLists(Foo model)
{
model.Makes = Helper.Makes();
model.Models = Helper.Models();
model.Colors = Helper.Colors();
model.EngineSizes = Helper.EngineSizes();
model.Materials = Helper.Materials();
model.FuelTypes = Helper.FuelTypes();
model.WheelSizes = Helper.WheelSizes();
model.BodyTypes = Helper.BodyTypes();
//more select lists below this
}
Then, everything is clean and tidy.

ASP.NET MVC 4 C# - Get Sectioned Elements or full URL to Parse

Being kind of a newb to MVC 4 (or really any of the MVC's for ASP.NET) I cant help but feel theres more to the URL helper than what I'm seeing.
Basically I've read the tutorials on populating the attributes in a controllers methods using a query string in the URL.
I dont liek query strings though and prefer a sectioned "folder" like style.
Without much further adu, this is the sample URL:
http://something.com/DataTypes/Search/searchString
this approach is actually pretty safe as there will only ever be single worded searches
I have tried in the DataTypes controller
[HttpGet]
public ActionResult Search(String q)
{
ViewBag.ProvidedQuery = q;
return View();
}
and a few other small variations, right now im just trying to get the string to show up in the view but I dont seem to be getting anything there.
Is there anyway to inject the 3rd string in the url into an attribute?
If not, which URL helper class am I supposed to use to acquire the string data in the URL? Even if I have to parse the whole URL manually so be it, i just need to acquire that 3rd element in the URL as a string
Extremely n00b question im sure, but either im not finding this simple guide somewhere, or im not searching google correctly...
What you're missing is that the default route parameter name is "id". So you want to do this:
[HttpGet]
public ActionResult Search(String id)
{
ViewBag.ProvidedQuery = id;
return View();
}
If you don't want to use the variable name id, then you can modify your Route to look like this:
routes.MapRoute(
name: "Search",
url: "DataTypes/Search/{searchString}",
defaults: new { controller = "DataTypes", action = "Search",
searchString = UrlParameter.Optional });
If you don't want the string to be optional, then you can remove the last field from the defaults object.
you can use RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext)) to get the routedata
String URL to RouteValueDictionary
You need to look at the routing in the Global.asax.cs. For example for your case you could add a route to the routes collection like this:
routes.MapRoute("Search",
"DataTypes/Search/{q}",
new { controller = "DataTypes", action = "Search" }
);
Then the q parameter will automatically get mapped to your action. The default controller mapping is likely mapping it to "id".

ASP.NET MVC a better way to post model ID?

I have a ViewModel I am binding to a view:
ProductViewModel model = Mapper.Map<Product, ProductViewModel>(product);
return View(model);
The view (and viewmodel) is used to edit a Product so ProductViewModel has an ID property that corresponds to the ID in the database.
And to Post the ID back to the Controller I am doing this in my form on the view:
#Html.HiddenFor(x => x.Id)
Even though this works - I was wondering whether there was a better way to Post the ID back to the Controller? Route Values maybe? or is this a fairly standard pattern/approach?
If I have a GET action that includes the id in my route: /Products/Edit/1 then I usually keep it as a route value:
[HttpPost]
public ActionResult Edit(int id, EditProductViewModel model)
This is purely a preference of mine, though. There is no right or wrong way to do it.
The nice thing about this method is you no longer need to pass it in using a Hidden value since it is part of the URL. Actually, if you do pass it in with a Hidden value I believe it will be ignored.
Alternatively, since id is part of the route, you don't even need to have a separate parameter:
[HttpPost]
public ActionResult Edit(EditProductViewModel model)
public class EditProductViewModel
{
public int Id { get; set; }
}
Again, this is purely a preference thing.
I think the answer is, it depends.
Is your entire object being edited and posted back? If so I'd suggested posting back the ID as part of the model:
[HttpPost]
public ActionResult Edit(EditProductViewModel model)
Which I think is a perfectly valid thing to do. However be careful. If the resource being edited is a protected resource, ensure you validate the user has the correct privileges.
If it's a partial edit, perhaps just editing a comment through an Ajax call I'd probably be more tempted to do:
[HttpPost]
public ActionResult Edit(int id, string comment)
As creating a Model in that scenario I would see as overkill ... privilege problem still applies though :)
All that being said, I'm no expert myself :)
Incidentally ... I don't think there's anything wrong with the hidden field, I use it all the time. However it's an ajax call it may not be needed as it would be part of your posting ajax call.

How can i hold the properties of model between the actions(asp.net mvc)

Here's my model:
public class MyModel
{
public int BaseTypeField { set; get; }
public MyType UserTypeField { set; get; }
}
In the first action, i passed a MyModel to the view normally:
public ActionResult Action1()
{
MyModel model = new MyModel();
//do something with model.UserTypeField
return View(model);
}
In Action1View i can easily modify the model.BaseTypeField with HtmlHelper, but I dont wanna modify model.UserTypeField in this view(neither can i store it in HiddenFor).
Then Action1View submit the model to another action:
public ActionResult Action2(MyModel model)
{
//model.UserTypeField is lost here
return View();
}
Here comes the problem: how can i hold/save the model.UserTypeField except for something like Session??
Well, if you don't want to use session state, then your only option is to pass the information to the client and have him pass it back with his request. One way you could do this would be with a cookie. Another might be to use a hidden form field. You would include the field in your response to Action1, and the browser would automatically submit it in the request to Action2 (assuming you're using a form POST to call the action).
You have a number of options to preserve state across controller actions:
Store it in a Hidden input element in the View (though I appreciate that you say you can't, and there are plenty of good reasons why that might be the case).
Store it in Session State.
Store it in your application database (but then, you may as well use Session State).
Store it in a cookie. You can create a HttpCookie and add it to HttpContext.Current.Response.Cookies in Action1 and read it from HttpContext.Current.Request.Cookies in Action2.
If you only have a small amount of data and have no reason to use Session State elsewhere, I'd probably go for the cookie option. But Session State is there for precisely this kind of purpose. Don't be afraid to use it if it's the right thing.
Each action should have a parameter that has only properties for fields which you would like to accept from the request. The rest of the object should be loaded from the data store again. In other words, don't have Action2 take a property that takes in the whole model as it will allow your consumers to inadvertently alter more properties than they should be able to.
This may seem like a lot of work to do on every step, but you will save yourself many headaches by not having to do all of the validation for all the fields which you do not want changed. It is also easy to load the rest of the model from the data store if you wrap it up in a function.
TempData[] is intended to hold items between actions, but it does use the Session. If keys are not marked using Keep, then they are removed once the next Action is executed.
If you wanted to avoid Session fullstop, then you would have to serialize your object and send it to the client in the view (in a hidden form variable for example) and then deserialize it back into Action2.
If you wanted to use TempData (which would be simplest unless you can't use session for some reason), the syntax would just be:
public ActionResult Action1()
{
MyModel model = new MyModel();
//do something with model.UserTypeField
TempData["UserTypeField"] = model.UserTypeField;
return View(model);
}
public ActionResult Action2(MyModel model)
{
model.UserTypeField = TempData["UserTypeField"];
return View();
}

Category is special word in ASP.NET MVC2? So how can I use something else?

I have just realized that, by chance, I implemented a category browse type situation in my project:
// GET: /Category/Browse?Category=Fruit
public ActionResult Browse(string category)
{
...
}
It turns out this is special case and there must be something behind the scenes. My next one I want to implement something like
//GET: /Category/Browse?Color=Blue
public ActionResult Browse(string color)
{
...
}
You get the idea...
Where/how do I register the different url values?
You don't need to register anything. Action parameters are automatically mapped to URL values by the default model binder. You can also map to complex type, list and dictionary parameters.

Resources