asp.net mvc4 controller allow null complex object - asp.net-mvc

If I have this:
public ActionResult BuscarClientes(SomeClass c)
{ ... code ...}
And I access the url to this action without any parameter (so I don't give any elements to my model), I still get a newly created object. But, I'm wanting to get a NULL object instead if no arguments are given.
This is because I'm using this method as a search action method, and the first time the get is done I don't want to perform any validation and just return the view. After that, the post will be a GET method (its a search I need to make it a get request) with all the values in the query string.
How can I force the model binder to give me a null object if no parameters are given in the query string? Because as it is now, i get a new instance of SomeClass with all its properties set to null. Instead of just a null object.

Try specifying default value to the parameter
public ActionResult BuscarClientes(SomeClass c = null)
{ ... code ...}

Related

MVC Populate dropdownlistfor in CREATE view from another model

So I basically have the same issue as this post: ASP.NET MVC - How to populate dropdownlist with another model?
The solution works... technically.. as long as the model is populated. However, I'm working with a CREATE view where the controller's action simply returns a blank "View()" obviously because it's creating something so you don't have any data yet.... yet I obviously still want the dropdownlist to populate from a model which gets it's data from the DB. If I try to run this code on a view with an empty model I get "Object reference not set to object" when it tries to grab the property that returns the list.
I tried instantiating a new, blank model in the Create action with the USING statement and set only PropertyTypeList property with a new instance of the Type model, and passed it to the view and it sort of worked... the view showed up with the dropdown of the other Type model populated, but it pre-filled in a bunch of the int/date types with 0's and 1/1/1900's because I have non-nullable fields. This is the closest I've gotten so far to simply letting the user create a new record with a pre-populated dropdown from ome of the fields that comes from a model.
I could just create a new Type model in the Create Action and assign it to the Viewbag or Tempdata, which I've done in the past, but this idea just makes me feel DIRTY. Viewbag disappears if the person refreshes the page so they get an error and is totally unprofessional. And I don't use Tempdata much because it relies on session state which gets very problematic if a user has my form open in mulitple tabs which could easily happen.
I feel like the solution from this post is SO close. It works fine when you're working with the EDIT action because you're passing a full model. But does anyone know how to get a dropdownlist to populate like this with an empty model? I tried something like adding an extra class to my secondary Type model
namespace blablanamespace {
public partial class PropertyType {
.. bla bla bla propertytype ID and name here
}
public class ViewModel
{
private readonly List<PropertyType> _keytypes;
public IEnumerable<SelectListItem> PropTypeItems
{
get { return new SelectList(_keytypes, "TypeID", "TypeID"); }
}
}
}
and
#Html.DropDownListFor(model => model.TypeID, new SelectList(new blablanamespace.Models.ViewModel().PropTypeItems))
but then I just get this error:
Value cannot be null. Parameter name: items
If I change the ViewModel class to instantiate a new list of types like so
public class ViewModel
{
public class ViewModel
{
private readonly List<PropertyType> _keytypes = new List<PropertyType>;
public IEnumerable<SelectListItem> PropTypeItems
{
get { return new SelectList(_keytypes, "TypeID", "TypeID"); }
}
}
I don't get the error this time, but I just get a blank form(yay) with a blank dropdownlist(boo!!). I figured this latter method would work since when I want to populate a new fresh list in the controller I basically do the same thing
List<ApplicationKeyType> _keytypes = new List<ApplicationKeyType>();
That behavior doesn't appear to be the same in the model.

Why does my viewmodel name have to be 'model'?

I've been working with MVC for quite a while. I made a form to submit my data using an entity model and as per requirement had to add tags too so I updated the view and the actionmethod to use a viewmodel instead. Like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PostwTagsVM post)
{
}
Surprisingly, the model was null.I couldn't find out why but then decided to rename the object as below:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(PostwTagsVM model)
{
}
Surprisingly, I get the data in the model now.
I know I can work like this but if i really needed to name by model object something else other than 'model'. Whats happening here?
It does not have to be named model.
If in the first case, your model is null, its because your PostwTagsVM model contains a property named post.
The parameter can be named whatever you want, except that it cannot be the same name as one of the properties in your model.
The reason is that your form would be sending back a name/value pair that is (say) post=someValue. The DefaultModelBinder looks for a matching name, sets the value of the property named Post to someValue, but then also finds a parameter named post and tries to set that to someValue, which fails (because you cannot do PostwTagsVM post = "someValue";), and the model becomes null.

How do I define a controller action that doesn't require a querystring?

The following action does not require a querystring, but it does require the Id to be passed in the URL.
public ViewResult Details(int id)
{
Domain domain = db.Domains.Find(id);
return View(domain);
}
How do I change this so the name can be passed in the URL instead of the Id?
When I change that to the following, it produces an error "Sequence contains no elements" regardless of how I attempt to execute it.
public ViewResult Details(String name)
{
Domain domain = db.Domains.Where(d => d.Name == name).First();
return View(domain);
}
Any help is greatly appreciated.
"Sequence contains no elements" error is because your LINQ query is not returning any results for this where clause but you are trying to Apply the First() function on the result set (which is not available for your where condition in this case).
Use the First() function when you are sure that there is Atleast one element available in the resultset you are applying this function on. If there are no elements as the result of your LINQ expression, Applying First will throw the above error.
For the URL to have the name parameter instead of the integer id, just change the parameter type to string. Keep the variable name as id itself. because that is what the MVC Routing will use to help you write those pretty URLS.
So now your URL can be like
../SomeController/Details/someName
Where someName is going to be the parameter value of your Details action method.
I would use the FirstOrDefault and do a checking to see whether an element is available for the LINQ expression.FirstOrDefault will returns the first element of a sequence, or a default value if the sequence contains no elements.
public ViewResult Details(String id)
{
Domain domain = db.Domains.Where(d => d.Name == id).FirstOrDefault();
if(domain!=null)
return View(domain);
else
return View("NotFound") //Lets return the Not found View
}

How does the ASP.NET MVC UpdateModel() method work?

I'm working on my first .NET MVC application and using the NerdDinner tutorial as a reference point. One point that is intriguing me at the moment is the UpdateModel() method. (I don't like using things I don't really understand.)
Taken from the NerdDinner tutorial -
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(int id, FormCollection formValues) {
Dinner dinner = dinnerRepository.GetDinner(id);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = dinner.DinnerID });
}
My main question is how does the UpdateModel() get access to the formValues passed in the Edit method? Why is the collection not passed in explicitly as a parameter to the method?
UpdateModel() is a Controller helper method that attempts to bind a bunch of different input data sources (HTTP POST data coming from a View, QueryString values, Session variables/Cookies, etc.) to the explicit model object you indicate as a parameter. Essentially, it is only for model binding.
If you express the input parameters for your Action as a strongly-typed model (like a View Model), you've already taken all of the steps that are done behind the scenes when UpdateModel() is called. If you retrieve an object from the DataContext and edit its properties, SaveChanges() is all you need to push the updates back to the database (in this case, Save()).
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
dinner.Description = incoming.Description;
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
However, there is a use-case for using UpdateModel() with a strongly-typed model: when you are passing in a strongly-typed model and want its values to directly replace those of an entity from the database (provided they are all named and typed the same). In this case, you would retrieve the object, use UpdateModel() on it, and its model binding operation will pull in any similarly-named and typed properties from the strongly-typed object to the retrieved object. In other words, it will perform reflection for you.
So, like your example, if you want all properties to update without specifying which to update, and your strongly-typed model and database model have similarly-named properties, you would still want to use UpdateModel() to take advantage of the reflection.
Example:
//
// POST: /Dinners/Edit/2
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(DinnerViewModel incoming) {
var dinner = dinnerRepository.GetDinner(incoming.DinnerID);
UpdateModel(dinner);
dinnerRepository.Save();
return RedirectToAction("Details", new { id = incoming.DinnerID });
}
The only advantage here (over using a FormCollection object) is that you'd have access to all other properties of the strongly-typed object (as shown by incoming.DinnerID).
Conclusion: if you're translating a strongly-typed object to a derived object, it's probably easiest to use UpdateModel(). However, it's largely unnecessary if you are simply updating a few properties of the derived object. Also, be aware that use of the Entity Framework (instead of something like Linq to SQL) makes all of this moot, as it can relate strongly-typed objects and derived objects with its own methods.
It does inspect all the HttpRequest inputs such as Form, QueryString, Cookies and Server variables. I think in this order.
Instead of passing Model object as a parameter to "Post()" action method, we are creating an instance of an Model object within the "Post()" function, and updating it using "UpdateModel()" function. "UpdateModel()" function inspects all the HttpRequest inputs such as posted Form data, QueryString, Cookies and Server variables and populate the employee object.
e.g.
[HttpPost]
[ActionName("Create")]
public ActionResult Create_Post()
{
EmployeeBusinessLayer employeeBusinessLayer =
new EmployeeBusinessLayer();
Employee employee = new Employee();
UpdateModel(employee);
employeeBusinessLayer.AddEmmployee(employee);
return RedirectToAction("Index");
}

Using a ModelBinder to get an object by an ID

I have multiple controller actions that takes an id
public ActionResult Get(int? id) {
...
}
public ActionResult Delete(int id) {
...
}
public JsonResult GetJson(int? id) {
...
}
I'm thinking its best practice to use a ModelBinder (SomeObjectFromIDModelBinder) on each action, so the obtaining of the object is separated from the controller, and keeps the action methods smaller.
The reason I don't want it to be called SomeObjectModelBinder is because I also have a need to recreate Models from JSON, so have a SomeObjectFromJsonModelBinder which handles recreating the 'SomeObject' from a JSON string.
I'm thinking this is a suitable usage of ModelBinders (naming convention), but just wanted clarification. Thoughts?
You don't need to do anything to get the ID. THe MVC handler will look for simple values of the same name as the method parameters in the Form data, the Query String, and the Route.
So you could have a route /{controller}/{action}/{id} with defaults of action="Get", id=1.
then the id could be specified in the URL as either /Home/Get/3 or /Home/Delete?id=6.
Alternately, you could have a textbox with an id of "id" and a submit button in a form that posts to "/Home/Get".
ModelBinders are intended to allow you to have action methods that are classes by creating the instance and populating the properies from the Form data, Query string, or Route data.
I've decided that it is acceptable to do what I was asking, and having multiple ModelBinders that will bind different data to a Model.

Resources