This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
#model MvcDemo.Models.MovieDB
<fieldset>
<legend>MovieDB</legend>
<div class="display-label">Title</div>
<div class="display-field">
#Html.DisplayFor(model => model.Title)
</div>
<div class="display-label">Director</div>
<div class="display-field">
#Html.DisplayFor(model => model.Director)
</div>
<div class="display-label">Date</div>
<div class="display-field">
#Html.DisplayFor(model => model.Date)
</div>
</fieldset>
<p>
#Html.ActionLink("Edit", "Edit", new { id=Model.ID })
#Html.ActionLink("Back to List", "Index")
</p>
When I am executing this , an error message is coming which is as follows ...
System.NullReferenceException: Object reference not set to an instance of an object.
The error is occuring at the 2nd last line i.e.#Html.ActionLink("Edit", "Edit", new { id=Model.ID })
In your action method, just before you return the ActionResult have a look at the model and confirm that the ID property is populated - I think you'll find it isn't.
If your action method is a HTTP Post, does the view that has been submitted contain a control for the ID field? If not, try using a "Hidden" input field - the HiddenFor(...) method will help you out with it...
Related
Hi I am trying to code a simple blog with using ASP.NET MVC 5 Framework. I have done CRUD operations of Posts. I mean I can add new articles and manage them. When I wanted to add comments to articles, I stuck. Comments will be added to Details pages of articles. So I should add Create comment page to Details page.
I used Code First model and I have two models. Articles and Comments. I decided to use partial views to enter comments. But result is an error:
The model item passed into the dictionary is of type 'System.Data.Entity.DynamicProxies.Article but this dictionary requires a model item of type 'Blog.Models.Comment'. Comments can not be added. I created 2 PartialViews, one of them is _CreateComments PartialView and other one is _Index PartialView
Details View:
#model Blog.Models.Article
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>Article</h4>
<hr />
<dl class="dl-horizontal">
<dt>
#Html.DisplayNameFor(model => model.Title)
</dt>
<dd>
#Html.DisplayFor(model => model.Title)
</dd>
<dt>
#Html.DisplayNameFor(model => model.Author)
</dt>
<dd>
#Html.DisplayFor(model => model.Author)
</dd>
<dt>
#Html.DisplayNameFor(model => model.Date)
</dt>
<dd>
#Html.DisplayFor(model => model.Date)
</dd>
<dt>
#Html.DisplayNameFor(model => model.ArticleContent)
</dt>
<dd>
#Html.DisplayFor(model => model.ArticleContent)
</dd>
</dl>
</div>
<div class="jumbotron">
#Html.Partial("~/Views/Comments/_CreateComments.cshtml", new Blog.Models.Comment())
#Html.Partial("~/Views/Comments/_Index.cshtml", new List<Blog.Models.Comment> { new Blog.Models.Comment() })
</div>
_CreateComment PartialView
#model Blog.Models.Comment
#using (Html.BeginForm("Create"))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Comment</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Date, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Date, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Date, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CommentContent, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CommentContent, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CommentContent, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
_Index PartialView
#model IEnumerable
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Date)
</th>
<th>
#Html.DisplayNameFor(model => model.CommentContent)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.CommentContent)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.CommentId }) |
#Html.ActionLink("Details", "Details", new { id=item.CommentId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.CommentId })
</td>
</tr>
}
</table>
You have to use a ViewModel for that purpose. In POST, it will get the needed information. And in GET you will send the needed information.
For example: in GET you will send the article and needed areas. But in POST you will get the comment and commenter's name and date etc.
There are numerous issues with your code.
#using (Html.BeginForm()) means it will post back to the
Details() method (assuming that's the action which generated the
view), so it would need to be #using (Html.BeginForm("Create"))
The controls your generating will have name attributes such as
name="Item2.Date" which have no relationship to your Comment
class (Comment does not have a property named Item which is a
complex object with a property named Date)
The default value of a DateTime property is 1.1.0001 00:00:00
meaning that you have not initialized the value (e.g. Date =
DateTime.Today;) but its not clear why you would need the user to
enter a date anyway - surely that would be set to today's date in
the controller immediately before you save the comment.
You have not indicated what scripts
#Scripts.Render("~/bundles/jqueryval") is generating, but assuming
you using the jQueryUI datepicker, you will need at least
jquery-{version}.js and jquery-ui-{version}.js (plus jquery.validate.js and jquery.validate.unobtrusive.js for validation)
You have a table in your form which will not display anything other
that the initial values of a new Comment (and exactly the same as
is being displayed in the textboxes) so it seems a bit pointless
Note also your view does not display any existing comments for an article which seems unusual.
There a numerous ways so solve this including ajax so the user could stay on the same page and continue to add more comments, but based on what appears to be your current UI, then the model in Details view should be just Article and use a partial to render a form for a new Comment
Controller
public ActionResult Details(int? id)
{
....
Articles article = db.Articles.Find(id);
....
return View(article);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Comment model)
{
if (ModelState.IsValid)
{
model.Date = DateTime.Today; // set date before saving
db.Comments.Add(model);
db.SaveChanges();
return RedirectToAction("Index");
}
....
}
View
#model yourAssembly.Article
// Render properties of Article
....
// Add form for creating a new comment
#Html.Partial("_Comment", new yourAssembly.Comment)
// Add required scripts including jquery ui
and the partial view (_Comment.cshtml)
#model yourAssembly.Comment
#using (Html.BeginForm("Create"))
{
#Html.LabelFor(m => m.Content, new { #class = "control-label col-md-2" })
#Html.TextBoxFor(m=> .m.Content, new { #class = "form-control" } })
#Html.ValidationMessageFor(m=> m.Content, new { #class = "text-danger" })
<input type="submit" value="Create" class="btn btn-default" />
}
Side notes:
Do not use Tupple in your views, especially for a view that
involves editing since it generates name attributes which have no
relationship to your model. Always use view models.
You do not generate a control for the CommentId property so there
is no point including it in you [Bind] attribute (and in fact
means someone could post back a value and result in your code
throwing an exception.
Using <dl>, <dt> and <dd> tags are not appropriate in your
view (they are for A description list, with terms and
descriptions). Use <div> and <span> elements.
I need to create a wizard in MVC 4 and most of the part I have done, now what is bothering me is that my project requires that the values which I have inserted in the first step of the wizard should display like label in the next step. How to achieve that, can anyone help me with this?? It would be great if I'll get a fast response.
Thank you in advance!!
This is how I am writing the front end code of the application
<div class="wizard-step">
<h3>Step 3: Check Eligibility</h3>
<div class="editor-label" style="width: 25%">
#Html.LabelFor(model => model.AccountNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.AccountNumber)
</div>
<div class="editor-label" style="width: 25%">
#Html.LabelFor(model => model.MeterId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MeterId)
</div>
<div class="editor-label" style="width: 25%">
#Html.LabelFor(model => model.Program)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Program)
</div>
<div class="editor-label" style="width: 25%">
#Html.LabelFor(model => model.PeakLoad)
</div>
<div class="editor-field MB12">
#Html.CheckBoxFor(model => model.PeakLoad)
</div>
<div class="editor-label" style="width: 25%">
#Html.LabelFor(model => model.WifiBroadband)
</div>
<div class="editor-field MB12">
#Html.CheckBoxFor(model => model.WifiBroadband)
</div>
</div>
And the controller code is also there
[HttpGet]
public ActionResult EnrollUser()
{
EnrollmentEntity model = new EnrollmentEntity();
BindAggregatorList(model);
BindCBLMethod(model);
BindDeviceManuList(model);
BindDeviceModelList(model);
BindDeviceTypeList(model);
BindProgramList(model);
return View(model);
}
[HttpPost]
public ActionResult EnrollUser(EnrollmentEntity model)
{
return View(model);
}
If you're trying to keep things atomic, you can save the data from each step in a session object and then save everything together once the user has completed the wizard. You could also POST the data from the current and previous steps to the next step of the wizard.
Another option would be to save the partial to your database following each step of the wizard.
Update
Given the new constraints, and assuming you support only modern browsers (IE8+ and just about all versions of Firefox and Chrome that are in use), you could store the data using local storage. See Using the Web Storage API.
First of all thank you guys for showing your interest in my problem and trying to resolve it. It is the other thing that any of the answer didn't helped me out or might be the question was not explained properly. But now I got the answer and I am posting it so that it may help to other.
My problem was that I had to show the values that I have inserted in the first screen as Non editable in the second screen and for that I have just used the #Model.Username at the place I wanted to display it. And yes for the server side validation like the I have posted back the data after each screen and returned the same model.
I have an extremely simple Controller + View
public ActionResult Edit(string username)
{
return View(ComponentFactory.GetAdapter<IUserListAdapter>().Get(username));
}
and
#model BAP.Models.UserList
#using GrmanIT.Utils.Web
#using BAP.Models
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Globale Benutzer</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserId)
#Html.ValidationMessageFor(model => model.UserId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Model.UserName
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Bundesland)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Bundesland, new SelectList((IEnumerable<BAP.Models.Bundesland>)ViewData["BundeslandList"], "Value", "Text"))
</div>
<div>
<input type="submit" value="#LocalizationHelper.LocalizedLiteral("Save").ToString()" />
</div>
</fieldset>
}
<div>
#Html.ActionLink(LocalizationHelper.LocalizedLiteral("BackToList").ToString(), "Index")
</div>
#Model.UserName
this is by far the simplest controller and view we have in our MVC4 application, BUT - it does something weird:
I get the TextBox, which is created with #Html.EditorFor(model => model.UserName) prefilled with the UserId of the model instead of the UserName
I debugged it and it and there as always the correct value in UserName and UserId. You can also see, that I added #Model.UserName twice within the View to see if it get also correctly rendered, and yes, it prints the UserName and not the ID.
I've also checked references to the UserName-property and didn't find any, which would modify it. My question is - do you have any idea, where the code could be modified or how could if find it out?
It happens only on this one controller on this one action (out of ~25 controllers and ~200 actions)
Thank you
Ok, it was AGAIN the ModelState - as you can see in the code above - the parameter to the function is called "username" but it's actually the userId. And since there is already the parameter username, it is stored in the ModelState and when I call
#Html.EditorFor(model => model.UserName)
it takes the value from the ModelState (where actually the UserId is stored under the name of the action-parameter)
So the solution would be, either to call ModelState.Clear() or rather, rename the parameter to represent the actual value.
When I use the following code, I get a friendly error message (as friendly as YSCD's get) telling me I shouldn't use '#', yet when I don't use it, my form declaration renders as literal Razor code, not as the intended HTML elements. What am I doing wrong?
#if (Model.Step == Trocrates.Web.Models.PasswordResetModel.PasswordResetSteps.StartRequest)
{
#using (Html.BeginForm()) { Html.ValidationSummary(true);
<fieldset style="border: 0px;">
<div class="editor-label">
#Html.LabelFor(model => model.UserName);
</div>
<div class="editor-field">
Html.EditorFor(model => model.UserName) Html.ValidationMessageFor(model => model.UserName)'
<input type="submit" value="Log In" />
#Html.ActionLink("Send", "BeginResetPassword", "Account")
</div>
</fieldset>
}
}
Sorry readers, it was originally that less visible open brace glyph on the same line as BeginForm that caused confusion. When I close that things fell back into place.
Did you try removing the # symbol on the using statement? Since you're already in code mode because of the if block the # symbol doesn't mean anything there. That's the only thing off hand that looks out of place to me.
I have an Asp.Net MVC 3 application with a database "Consultants", accessed by EF. Now, the Consultant table in the db has a one-to-many relationship to several other tables for CV type information (work experience, etc). So a user should be able to fill in their name etc once, but should be able to add a number of "work experiences", and so on.
But these foreign key tables are complex objects in the model, and when creating the Create View I only get the simple properties as editor fields. How do I go about designing the View or Views so that the complex objects can be filled in as well? I picture a View in my mind where the simple properties are simple fields, and then some sort of control where you can click "add work experience", and as many as needed would be added. But how would I do that and still utilize the model binding? In fact, I don't know how to go about it at all. (BTW, Program and Language stand for things like software experience in general, and natural language competence, not programming languages, in case you're wondering about the relationships there).
Any ideas greatly appreciated!
Here's the Create View created by the add View command by default:
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Consultant</legend>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Description)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Description)
#Html.ValidationMessageFor(model => model.Description)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
And here's the EF database diagram:
Update:
According to suggestion, I tried Steven Sanderson's blog solution, but I can't get it to work properly. I added this in the main view:
<div id="editorRows">
#foreach (var item in Model.Programs)
{
Html.RenderPartial("ProgramEditorRow", item);
}
</div>
<input type="button" value="Add program" id="addItem" />
I also added the javascript:
<script type="text/javascript">
var url = '#Url.Action("BlankEditorRow", "Consultant")';
$(document).ready(function () {
$("#addItem").click(function () {
$.ajax({
url: url,
cache: false,
success: function (html) {
alert(html);
$("#editorRows").append(html); }
});
return false;
});
});
</script>
A partial view:
#model Consultants.Models.Program
#using Consultants.Helpers
<div class="editorRow">
#*#using (Html.BeginCollectionItem("programs"))
{*#
#Html.TextBoxFor(model => model.Name)
#*}*#
</div>
And action methods in the controller:
public ActionResult Create()
{
Consultant consultant = new Consultant();
return View(consultant);
}
public ActionResult BlankEditorRow()
{
return PartialView("ProgramEditorRow", new Program());
}
Note that I commented out the Html.BeginCollectionItem part in the partial view, because I can't get that to work. It only gives me the hidden field Steven Sanderson talks about, but not the actual textbox. So I tried commenting that part out and just had a textbox. Well, that gets me the textbox, but I can't get to that info in the post method. I use the Consultant object as return parameter, but the Programs property contains no Program. Perhaps this has to do with the fact that I cannot get the BeginCollectionItem helper to work, but in any case I don't understand how to do that, or how to get to the Program supposedly added in the view. With a simple object I would add the new object in the post method by something like _repository.AddToConsultants(consultant), and when I save to EF it gets its id. But how do I do the same thing with the program object and save it to the database via EF?
Phil Haack has written a great blog post which explains how to model bind to a list. It's specific to MVC2, but I'm not sure if version 3 has improved on this.
Model Binding To A List.
In a scenario where the user is allowed to add an arbitrary number of items, you'll probably want to create new input fields using JavaScript. Steven Sanderson shows here how to achieve that:
Editing a variable length list, ASP.NET MVC 2-style.
Those resources should get you all the way there.
You may take a look at the following blog post about writing custom object templates. Also don't use EF models in your views. Design view models that are classes specifically tailored to the needs of a given view and have your controller map between the EF models and the view models that should be passed to the view. AutoMapper is a good tool that could simplify this mapping.