Unexpected NullReferenceException in View - asp.net-mvc

I have a Razor view that starts like:
#using My.Models
#model MySpecificModel
#{
ViewBag.Title = "My Title";
// NullReferenceException here:
string dateUtc =
(Model == null ? DateTime.UtcNow.ToShortDateString() :
Model.Date.ToShortDateString());
I see no reason for the NullReferenceException in the last line (note: the " = ? :" stuff is on one line in my source code. It is formatted to fit here.)
I then remove the declaration of/assignment to dateUtc and the NullReferenceException moves up to the ViewBag.Title line:
#using My.Models
#model MySpecificModel
#{
ViewBag.Title = "My Title"; // NullReferenceException here:
How can this possibly happen? ViewBag is of course not null.
NOTE 1: This only happens if Model is null.
NOTE 2: MySpecificModel.Date is of type DateTime, so can never be null.

A NullReferenceException on ViewBag.Title can indicate the error is really on a nearby line. In this example the error was thrown on line 1 but the real error was the null Model.Invoice in line 3.
<h2>#ViewBag.Title</h2>
<div class="pull-right">
<button onclick="addInvoice('#Model.Invoice.InvoiceId');">Add Invoice</button>
</div>
Also ASP.NET MVC Razor does not handle nulls in ternary statements like C# does.
//Ternaries can error in Razor if Model is null
string date = (Model == null ? DateTime.Now : Model.Date);
//Change to
string date = null;
if (Model == null)
date = DateTime.Now;
else
date = Model.Date;

You provide an empty default model which does nothing. It will be just so the Model isn't null. It will help to have an IsEmpty property . Better yet, if it can be applied in your case, a model with default values. The important thing is the Model not being null ever

You will get a null exception if you do not pass any model to the view and still have the view bound to a model e.g.:
#model MySpecificModel
When you did not pass such a model to the view from your controller.

Related

Foreach of DropDownList html helper with value from the foreach itself

I'm just inquisitive if this is possible. If so, please help me.
Everything is already set and valid like the:
-Model.info:
public class info{
public string information{get;set;}
}
-ViewBag.Infos:
ViewBag.Infos = new SelectList(new []{"Option1","Option2"});
-I am not finding or encountering an error.
So it goes like this:
#foreach(var nom in Model.info)
{
#Html.DropDownList("Infos",new{#Value = "nom.information"})
}
Is it possible to put the foreach value of nom into each dropdownlist's value?
First error is that you are iterating over Model.info that is an string (is an iteration over every char, the type of nom would be char).
By the other hand, you must define a DropDownList with the ViewBag elements, something like that:
#Html.DropDownList("info", ViewBag.info, null, Model.info)

How to convert decimal field value to currency in mvc

I have an few editorfor in my view like following
#Html.EditorFor(Model => Model.CashBalance)
Now when i enter any value in to that editorfor,the value should change to currency value in textbox change event
For ex:
123 should display as 123.00
14.35 should display as 14.35
I want to do this in generic way so that I don't need to change it every where as my project has many editorfor which takes inputs from user.
As I am using an EditorTemplate for all these textboxes,i want to handle here itself.
My EditorTemplate for this is decimal.cshtml and it looks like the foll
#model decimal?
#{
string value = (Model.HasValue == false || Model.Value == 0) ? "" : string.Format("{0:0.00}", Model.Value);
}
#Html.TextBox(
"",
value,
new { #class="amountRightAlign"}
)
Will there be any textchange event i can write here so that it affects where ever there is decimal datatype?
Thanks in advance?
Html helpers are server side code used to generate the html which is sent to the client. In order to interact with user changes in the browser, you need to use javascript to handle events.
In your case you don't need an EditorTemplate. Instead, just the overload of TextBoxFor() that accepts a format string
#Html.TextBoxFor(m => m.CashBalance, "{0:0.00}", new { #class="decimalnumber" })
Then in the view, or in a separate script file
$('.decimalnumber').change(function () {
var num = new Number($(this).val());
if (isNaN(num)) {
// Its not a valid number
return;
}
$(this).val(num.toFixed(2));
})

Aspx to Razor Select List MVC5

I have converted my MVC3 application to MVC5, I had to change all views to razor. Having a challenge with a select list:
In ASPX view that works I am using the following:
<select id="Profession" name="Profession" style="width: 235px; background-color: #FFFFCC;">
<% List<string> allProfessions = ViewBag.AllProfessions;
string selectedProfession;
if (Model != null && !String.IsNullOrEmpty(Model.Profession))
selectedProfession = Model.Profession;
else
selectedProfession = allProfessions[0];
foreach (var aProfession in allProfessions)
{
string selectedTextMark = aProfession == selectedProfession ? " selected=\"selected\"" : String.Empty;
Response.Write(string.Format("<option value=\"{0}\" {1}>{2}</option>", aProfession, selectedTextMark, aProfession));
}%>
</select>
In Razor I am using:
<select id="Profession" name="Profession" style="width: 235px; background-color: #FFFFCC;">
#{List<string> allProfessions = ViewBag.AllProfessions;
string selectedProfession;}
#{if (Model != null && !String.IsNullOrEmpty(Model.Profession))
{selectedProfession = Model.Profession;}
else {selectedProfession = allProfessions[0];}
}
#foreach (var aProfession in allProfessions)
{
string selectedTextMark = aProfession == selectedProfession ?
"selected=\"selected\"" : String.Empty;
Response.Write(string.Format("<option value=\"{0}\" {1}>{2}</option>",
aProfession, selectedTextMark, aProfession));
}
</select>
The list shows up at the top of the page, I can't figure out where is the problem. Would appreciate your assistance.
Don't create your dropdown manually like that. Just use:
#Html.DropDownListFor(m => m.Profession, ViewBag.AllProfessions, new { style = "..." })
UPDATE
I tried your solution but got this error: Extension method cannot by dynamically dispatched
And, that's why I despise ViewBag. I apologize, as my answer was a little generic. Html.DropDownList requires the list of options parameter to be an IEnumerable<SelectListItem>. Since ViewBag is a dynamic, the types of its members cannot be ascertained, so you must cast explicitly:
(IEnumerable<SelectListItem>)ViewBag.AllProfessions
However, your AllProfessions is a simple array, so that cast won't work when the value gets inserted at run-time, but that can be easily fixed by casting it to a List<string> and then converting the items with a Select:
((List<string>)ViewBag.AllProfessions).Select(m => new SelectListItem { Value = m, Text = m })
There again, you see why dynamics are not that great, as that syntax is rather awful. The way you should be handling this type of stuff is to use your model or, preferably, view model to do what it should do: hold domain logic. Add a property to hold your list of profession choices:
public IEnumerable<SelectListItem> ProfessionChoices { get; set; }
And then, in your controller action, populate this list before rendering the view:
var model = new YourViewModel();
...
model.ProfessionChoices = repository.GetAllProfessions().Select(m => new SelectListItem { Value = m.Name, Text = m.Name });
return View(model);
repository.GetAllProfessions() is shorthand for whatever you're using as the source of your list of professions, and the Name property is shorthand for how you get at the text value of the profession: you'll need to change that appropriately to match your scenario.
Then in your view, you just need to do:
#Html.DropDownListFor(m => m.Profession, Model.ProfessionChoices)
Given that you don't have this infrastructure already set up, it may seem like a lot to do just for a drop down list, and that's a reasonable thing to think. However, working in this way will keep your view lean, make maintenance tons easier, and best of all, keep everything strongly-typed so that if there's an issue, you find out at compile-time instead of run-time.
I believe it's happening because of the Response.Write. Try this:
#Html.Raw(string.Format("<option value=\"{0}\" {1}>{2}</option>", aProfession,
selectedTextMark, aProfession))

Html.Raw() in ASP.NET MVC Razor view

#{int count = 0;}
#foreach (var item in Model.Resources)
{
#(count <= 3 ? Html.Raw("<div class=\"resource-row\">").ToString() : Html.Raw(""))
// some code
#(count <= 3 ? Html.Raw("</div>").ToString() : Html.Raw(""))
#(count++)
}
This code part does not compile, with the following error
Error 18 Type of conditional expression cannot be determined because there is no implicit conversion between 'string' and 'System.Web.IHtmlString' d:\Projects\IRC2011_HG\IRC2011\Views\Home\_AllResources.cshtml 21 24 IRC2011
What I must I do?
Html.Raw() returns IHtmlString, not the ordinary string. So, you cannot write them in opposite sides of : operator. Remove that .ToString() calling
#{int count = 0;}
#foreach (var item in Model.Resources)
{
#(count <= 3 ? Html.Raw("<div class=\"resource-row\">"): Html.Raw(""))
// some code
#(count <= 3 ? Html.Raw("</div>") : Html.Raw(""))
#(count++)
}
By the way, returning IHtmlString is the way MVC recognizes html content and does not encode it. Even if it hasn't caused compiler errors, calling ToString() would destroy meaning of Html.Raw()
The accepted answer is correct, but I prefer:
#{int count = 0;}
#foreach (var item in Model.Resources)
{
#Html.Raw(count <= 3 ? "<div class=\"resource-row\">" : "")
// some code
#Html.Raw(count <= 3 ? "</div>" : "")
#(count++)
}
I hope this inspires someone, even though I'm late to the party.
You shouldn't be calling .ToString().
As the error message clearly states, you're writing a conditional in which one half is an IHtmlString and the other half is a string.
That doesn't make sense, since the compiler doesn't know what type the entire expression should be.
There is never a reason to call Html.Raw(...).ToString().
Html.Raw returns an HtmlString instance that wraps the original string.
The Razor page output knows not to escape HtmlString instances.
However, calling HtmlString.ToString() just returns the original string value again; it doesn't accomplish anything.

What is wrong with my ASP.NET MVC SelectList?

I'm trying to use a SelectList one of my views, and its just not populating correctly. It gets the proper number of entries (4), but they all read System.Web.Mvc.SelectListItem. I fired up the debugger on the code, and saw some strangeness going on. I must be doing something wrong, but I don't quite see what.
Code from the ViewModel:
public SelectList DeviceTypes {get; private set;}
....
var device_types = DataTableHelpers.DeviceTypes();
IEnumerable<SelectListItem> sl = device_types.Select(
dt => new SelectListItem { Selected = (dt.DeviceType == 1),
Text = dt.Description,
Value = dt.DeviceType.ToString() }).ToList();
DeviceTypes = new SelectList(sl);
And code from the View:
<%= Html.DropDownList("Type",Model.DeviceTypes) %>
So, when I look at this in the debugger, the sl IEnumerable is getting built correctly. I can see all 4 elements in there, with the proper Text and Value property values. Once I call the SelectList constructor however, if I expand the IEnumerable that it contains, I see that it has 4 entries, but all the data in them has been lost. The Text is set to System.Web.Mvc.SelectListItem, and the value is null.
Ive tried changing the ToList() call to a ToArray(), as well as removing it entirely. That didn't change the behaviour.
What am I doing wrong here?
EDIT: Scratch my first answer.
You should be passing the IEnumerable list if items to the View, not trying to construct a Html item in the controller.
Code for controller:
public IEnumberable<YourModel> DeviceTypes {get; internal set;}
....
DeviceTypes = DataTableHelpers.DeviceTypes();
Code for View:
<%= Html.DropDownList("Type", from dt in Model.DeviceTypes
select new SelectListItem
{
Text = dt.Description,
Value = dt.DeviceType.ToString(),
Selected = dt.DeviceType == 1
}) %>

Resources