MVC how to check for NULL in model.property - asp.net-mvc

In a razor-view, how can I check the existence of a property in a model?
if (Model._myProp != null) <--- error .RuntimeBinder.RuntimeBinderException if Model does not contain _myProp
{
...do something
}

You do not want to check that one of the model's properties has the value null you want to check the type for it is having a property or not and ofcourse you solution will not work that way but #Satpal's wont work too.
Use stronly typed views and separate different properties into interfaces and use them with partial views.

Related

MVC.ViewBag is wrong?

I'm using
ViewBag.Something = session.Query<Something>().ToList();
To pass information from class Something to View and use it in selectList
#Html.DropDownListFor(model => model.model, new
SelectList(ViewBag.Something, "Id", "name"), "--Smthing--")
Is that bad? and how can i change it to be better?
The practice is not at all bad but it is recommonded to have a List property in our mode it self. in your case something like
public ActinResult YourActionMethod()
{
YourModelObject.Something = session.Query<Something>().ToList();
// And return your view after further code statements
return View(YourModelObject);
}
Infact instead of the original list object you cancreate a SelectList object where you can easily bind key and value and send it to view. By this way you can add all your business and build your model at once place and can populate it from the location you want to. Later View will just use that model rather than applying some more intelligence to it. It helps alot as all your values resides under same object rather than some in Model and some in ViewBag.
Secondly this practice is also fine if you don't have this list at more than one place and you are not reusing this model in any views. Also if you want to access this property outside your view e.g. in Layout or in some parent view which is consuming your view.
You can take a look at following post which explains how to bind a list to your model.
Setting default selected value of selectlist inside an editor template
I prefer to add all my properties to the model of the view, but the ViewBag can be useful to add things that don't quite fit in the model. It can also be useful when binding to elements in the layout since it doesn't have access to the view's model.

Entity Framework Database First Property Validation

I'm using EF database first and with MVC.
I'm wanting to add some validation on a property to compare its old value to its new one and report a validation error to the MVC ModelState if there is a problem.
This would be easy enough using code first and validating using 'set' on the property. However I can't do this using database first because its auto generated.
I've looked at using IValidatableObject and the validate() method however by then the value has already been changed on the property so I can't see the old one anymore to compare to.
Short of creating a method to pass the new value into first to check it, I can't think of another way.
Any suggestions?
Thanks
If you want to compare a new value to an old value then you are going to have to grab the values from the database first (before updating) and compare them:
[HttpPost]
public ActionResult Update(MyObject myObject)
{
var oldObject = db.Objects.FirstOrDefault(o => o.Id == myObject.Id);
//Compare oldObject.Value to myObject.Value
}
You could still use IValidatebleObject and pass in the objects that you need to keep that logic outside the controller.
Its not the ideal and this has started illustrating some of the weaknesses in Model and DB first but here's how I ended up doing it.
I decided to change the property in my model so that set was private and then create a separate method in the partial class to set the value. The validation is then all done in that method.
Thanks for your help anyway

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.

ASP.NET MVC, strongly typed views, partial view parameters glitch

If i got view which inherits from:
System.Web.Mvc.ViewPage<Foo>
Where Foo has a property Bar with a type string
And view wants to render strongly typed partial view which inherits from:
System.Web.Mvc.ViewUserControl<string>
like this:
Html.RenderPartial("_Bar", Model.Bar);%>
Then why it will throw this:
The model item passed into the dictionary is of type 'Foo'
but this dictionary requires a model item of type 'System.String'.
when bar is not initialized?
More specific: why it passes Foo, where it should pass null?
As #Dennis points out, if the model value is null, it will use the existing model from the view. The reason for this is to support the ability to call a partial view using a signature that contains only the partial view name and have it reuse the existing model. Internally, all of the RenderPartial helpers defer to a single RenderPartialInternal method. The way you get that method to reuse the existing model is to pass in a null value for the model (which the signature that takes only a view name does). When you pass a null value to the signature containing both a view name and a model object, you are essentially replicating the behavior of the method that takes only the view name.
This should fix your issue:
<% Html.RenderPartial( "_Bar", Model.Bar ?? string.Empty ) %>
Look at ASP.NET MVC source (HtmlHelper.cs -> RenderPartialInternal method -> line 258):
...
if (model == null) {
if (viewData == null) {
newViewData = new ViewDataDictionary(ViewData);
}
...
this is exactly your case. ASP.NET MVC uses the ViewData from your ViewContext
UPDATED:
Try this instead:
<% Html.RenderPartial("_Bar", Model.Bar ?? "Default" ); %>
If you pass null as the model to RenderPartial, then it will look at the original model, which is why the error says foo.
You'll need to make sure that bar is initialized to be an empty string instead of null.
Edit: #Arnis, look at the source code. It doesn't lie. You are passing null to the overload of RenderPartial. You are not passing Foo. Internally, the system uses the Model from your page's ViewContext (which is Foo) when you pass a null Bar to RenderPartial.
Though this has been answered, I ran across this and decided I wanted to solve this issue for my project instead of working around it with 'new ViewDataDictionary()'.
I created a set of extension methods:
https://github.com/q42jaap/PartialMagic.Mvc/blob/master/PartialMagic.Mvc/PartialExtensions.cs
I also added some methods that don't call the partial if the model is null, this will save a lot of if statements.
I created them for Razor, but a couple of them should also work with aspx style views (the ones that use HelperResult probably aren't compatible).
The extension methods look like this:
#* calls the partial with Model = null *#
#Html.PartialOrNull("PartialName", null)
#* does not call the partial if the model is null *#
#Html.PartialOrDiscard("PartialName", null)
There are also methods for IEnumerable models and the discard ones can also be called with a Razor lambda that allow you to wrap the partial result with some html.
Feel free to use them if you like.

How to check null value in MVC view?

I am using MVC with LINQ-to-SQL class.
as foreign key can be null, i have one record having f.k. null and others are having values.
now i am displaying it in view by Index view.
In index view i am resolving f.k. by writing code like
<%= Html.Encode(item.UserModified.UserName) %>
Now i have a problem in view that "object reference is not set".
And this is because of we are having null value in one of the f.k. field!
so can i write code in view to check whether Associated object pointing to null or nothing?
You can write any code you want in the view if necessary, so you could do:
<%= Html.Encode(item.UserModified.UserName ?? string.Empty) %>
You could also make a HtmlHelper extension to do this:
public string SafeEncode(this HtmlHelper helper, string valueToEncode)
{
return helper.Encode(valueToEncode ?? string.Empty);
}
You could then simply do:
<%= Html.SafeEncode(item.UserModified.UserName) %>
Of course if it's UserModified that's null and not UserName then you'll need some different logic.
With C#, you can use the conditional operator:
<%= Html.Encode(item.UserModified == null ? "" : item.UserModified.UserName) %>
However, it might be a better choice to move the UserName property to be a direct child of item, or to put it in ViewData.
First consider whether in your model an instance of User is valid without Name. If no then you should put a guard clause in the constructor.
Secondly, too many and duplicated null checks is a code smell. You should use the refactoring Replace Conditional with Polymorphism. You can create a Null object according to the Null Object Pattern.
This will make sure that you do not have to check for Null everywhere.

Resources