Model in MVC not being assigned values - c#

I'm getting the error, "Object reference not set to an instance of an object." when attempting to assign a value to a model's fields in my MVC project. My model (not strongly typed) is referenced in my view thus:
...Inherits="System.Web.Mvc.ViewPage<Project.Models.MyModel>" %>
Intellisense picks up MyModel's fields when I access it in the view. My model is posted below:
namespace Project.Models
{
public class MyModel
{
public int AddressId { get; set; }
public int AddressTypeId { get; set; }
....
}
}
As you can see, I do a get set on each field and everything is public. But when I debug it, as soon as I hit anything to do with the Model, the compiler complains that "Object reference not set to an instance of an object."
What's missing here?

Make sure you have passed a model to this view from the controller action that rendered it:
public ActionResult SomeAction()
{
MyModel model = ... fetch your model from somewhere
return View(model); // <!-- Notice how the model must be passed to the view
}
Obviously the function that is retrieving your model from wherever you are retrieving it must ensure that the model is not null. Alternatively you could test in the view if the model is not null before accessing it's properties and if it is null render some alternative content.

You will have to initialize your model first
for eg:
public ActionResult YourAction()
{
MyModel model = new MyModel();
return View(model);
}

Related

Is it possible to override Html.RenderAction() in ASP.NET? [duplicate]

I'm using MVC3 razor, and I'm trying to pass an object to a partial view, and it's not working.
This works fine without sending the object model to the partial view:
Html.RenderAction("Index", "ViewName");
Trying this doesn't sent the model object, i'm getting nulls instead (the object has data, and the view expects it):'
Html.RenderAction("Index", "ViewName", objectModel);
Is this even possible using RenderAction?
Thanks!
Edit: I found the error, there was an error with the controller's action that didn't pick up the sent object. Thanks for all your help!
You can actually pass an object to a controller method using Action. This can be done on any avaialble view, for instance I have one in a shared library that gets built to project bin folders that reference my shared project (properties - Copy if newer on the view file, in Visual Studio). It is done like so:
Controller:
public class GroovyController : Controller
{
public ActionResult MyTestView(MyModel m)
{
var viewPath = #"~\bin\CommonViews\MyTestView";
return View(viewPath, m);
}
}
MVC page (using Razor syntax):
#Html.Action("MyTestView", "Groovy", new { m = Model })
or using RenderAction method:
#{ Html.RenderAction("MyTestAction", "MyTestController", new { area = "area", m = Model }); }
Note: in the #Html.Action(), the Model object must be of type MyModel and that 3rd parameter must be set to the controller variable name, of which mine is MyModel m. The m is what you must assign to, so I do m = Model.
say you want to pass foo as model, make it first
public class Foo {
public string Name { get; set; }
public int Age { get; set; }
}
now make an ActionResult
public ActionResult FooBar(Foo _foo){
return PartialView(_foo);
}
call it
#Html.RenderAction("FooBar", "Controller", new { Name = "John", Age=20 });
Usually if I have a model already available it makes more sense to use Html.Partial than trying to render an action.
#Html.Partial("Foo", Model.FooModel)
Where Foo.cshtml is a view file (perhaps in your Shared folder) strongly typed with with #model FooProject.Models.FooModel or whatever your model is called. This can be as complex a model as you need it to be. Model is your page's main model into which you must set FooModel - or just omit this parameter if the Foo view uses the same model as the parent page.
RenderAction is generally better when you have just simple parameters, because you're just simulating a request to a regular action which has routing/query string parameters - and then dumping that response into your page. It works well if you need to put something in a Layout that isn't available in your page's model such as an element in a side bar.

ASP.NET Core MVC - InvalidOperationException: The model item passed into the ViewDataDictionary is of type x

I'm getting the apparently classic exception:
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'PieShop.ViewModels.HomeViewModel', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable`1[PieShop.Models.Pie]'
when trying to render a page in ASP.NET Core MVC.
I've seen a lot of answers for this question, but all seem to be the result of an obvious datatype mismatch between what's passed into the view from the controller and what's declared in the view itself. In my case, they match perfectly. Here's my controller:
public class HomeController : Controller
{
private readonly IPieRepository pieRepository;
public HomeController(IPieRepository pieRepository)
{
this.pieRepository = pieRepository;
}
public IActionResult Index()
{
var pies = pieRepository.GetAllPies();
var vm = new HomeViewModel()
{
SomeData = "haiod",
Title = "Welcome to the Pie Shop"
};
return View(vm);
}
}
Here's the view model:
public class HomeViewModel
{
public string Title { get; set; }
public string SomeData { get; set; }
}
And here's the view (which is called Views/Home/Index.cshtml:
#model PieShop.ViewModels.HomeViewModel
<h1>#Model.SomeData</h1>
The model passed into the view from the controller and what the view is declaring as its model are clearly the exact same type. What gives?
Turns out I had declared a type for the model in the shared _Layout.cshtml because I copy/pasted it during some refactoring:
#model IEnumerable<PieShop.Models.Pie>
So... just a copypasta error :facepalm:

view model in partial view is null on post method [duplicate]

I have a ViewModel that has a complex object as one of its members. The complex object has 4 properties (all strings). I'm trying to create a re-usable partial view where I can pass in the complex object and have it generate the html with html helpers for its properties. That's all working great. However, when I submit the form, the model binder isn't mapping the values back to the ViewModel's member so I don't get anything back on the server side. How can I read the values a user types into the html helpers for the complex object.
ViewModel
public class MyViewModel
{
public string SomeProperty { get; set; }
public MyComplexModel ComplexModel { get; set; }
}
MyComplexModel
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
....
}
Controller
public class MyController : Controller
{
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
model.ComplexModel = new MyComplexModel();
model.ComplexModel.id = 15;
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model here never has my nested model populated in the partial view
return View(model);
}
}
View
#using(Html.BeginForm("Index", "MyController", FormMethod.Post))
{
....
#Html.Partial("MyPartialView", Model.ComplexModel)
}
Partial View
#model my.path.to.namespace.MyComplexModel
#Html.TextBoxFor(m => m.Name)
...
how can I bind this data on form submission so that the parent model contains the data entered on the web form from the partial view?
thanks
EDIT: I've figured out that I need to prepend "ComplexModel." to all of my control's names in the partial view (textboxes) so that it maps to the nested object, but I can't pass the ViewModel type to the partial view to get that extra layer because it needs to be generic to accept several ViewModel types. I could just rewrite the name attribute with javascript, but that seems overly ghetto to me. How else can I do this?
EDIT 2: I can statically set the name attribute with new { Name="ComplexModel.Name" } so I think I'm in business unless someone has a better method?
You can pass the prefix to the partial using
#Html.Partial("MyPartialView", Model.ComplexModel,
new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }})
which will perpend the prefix to you controls name attribute so that <input name="Name" ../> will become <input name="ComplexModel.Name" ../> and correctly bind to typeof MyViewModel on post back
Edit
To make it a little easier, you can encapsulate this in a html helper
public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
string name = ExpressionHelper.GetExpressionText(expression);
object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
var viewData = new ViewDataDictionary(helper.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo
{
HtmlFieldPrefix = string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix) ?
name : $"{helper.ViewData.TemplateInfo.HtmlFieldPrefix}.{name}"
}
};
return helper.Partial(partialViewName, model, viewData);
}
and use it as
#Html.PartialFor(m => m.ComplexModel, "MyPartialView")
If you use tag helpers, the partial tag helper accepts a for attribute, which does what you expect.
<partial name="MyPartialView" for="ComplexModel" />
Using the for attribute, rather than the typical model attribute, will cause all of the form fields within the partial to be named with the ComplexModel. prefix.
You can try passing the ViewModel to the partial.
#model my.path.to.namespace.MyViewModel
#Html.TextBoxFor(m => m.ComplexModel.Name)
Edit
You can create a base model and push the complex model in there and pass the based model to the partial.
public class MyViewModel :BaseModel
{
public string SomeProperty { get; set; }
}
public class MyViewModel2 :BaseModel
{
public string SomeProperty2 { get; set; }
}
public class BaseModel
{
public MyComplexModel ComplexModel { get; set; }
}
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
...
}
Then your partial will be like below :
#model my.path.to.namespace.BaseModel
#Html.TextBoxFor(m => m.ComplexModel.Name)
If this is not an acceptable solution, you may have to think in terms of overriding the model binder. You can read about that here.
I came across the same situation and with the help of such informative posts changed my partial code to have prefix on generated in input elements generated by partial view
I have used Html.partial helper giving partialview name and object of ModelType and an instance of ViewDataDictionary object with Html Field Prefix to constructor of Html.partial.
This results in GET request of "xyz url" of "Main view" and rendering partial view inside it with input elements generated with prefix e.g. earlier Name="Title" now becomes Name="MySubType.Title" in respective HTML element and same for rest of the form input elements.
The problem occurred when POST request is made to "xyz url", expecting the Form which is filled in gets saved in to my database. But the MVC Modelbinder didn't bind my POSTed model data with form values filled in and also ModelState is also lost. The model in viewdata was also coming to null.
Finally I tried to update model data in Posted form using TryUppdateModel method which takes model instance and html prefix which was passed earlier to partial view,and can see now model is bound with values and model state is also present.
Please let me know if this approach is fine or bit diversified!

MVC HttpPost strongly typed Model null

View Model looks like this:
public class AsmenysInfoViewModel2
{
public asmenys_info Asmenys_info { get; set; }
public List<miestai> Miestai { get; set; }
public string Test { get; set; }
}
And there are two actions. Get and Post.
public ActionResult Index(long? id)
{
var model = new AsmenysInfoViewModel2();
model.Test = "Test";
model.Asmenys_info = BllFactory.DalFactory.AsmenysInfoDal.GetById(id.Value);
return View(model);
}
[HttpPost]
public ActionResult Index(AsmenysInfoViewModel2 asmenys_info)
{
var model = asmenys_info;
return View(model);
}
And my view looks like this:
#model MODELS.AsmenysInfoViewModel2
#{
ViewBag.Title = "Index";
}
#using (Html.BeginForm("Index", "AsmenysInfo", FormMethod.Post))
{
#Html.ValidationSummary()
#Html.TextBoxFor(m => m.Asmenys_info.adresas)
<input type="submit" value="Išsaugoti" />
}
Doesn't matter if I use EditorFor or TextBoxFor - result is same. My model property "Asmenys_info" on posting is always null. If my class AsmenysInfoViewModel2 would not contain asmenys_info type property and would contain only "string, int etc" (no strongly typed) - it would work.
My question is :
How to post View Model which has strongly typed property which on posting would not be null?
Your model has a property named Asmenys_info and the parameter in your POST method is also named asmenys_info. Internally the DefaultModelBinder reads the values of the form data which includes a value for Asmenys_info and attempts to set property Asmenys_info to that value but it fails because there is no conversion from a string to a complex object.
Change the name of the parameter to anything other than a name of a property in your model and it will bind fine, for example
[HttpPost]
public ActionResult Index(AsmenysInfoViewModel2 model)
Change the below line with another object name
public ActionResult Index(AsmenysInfoViewModel2 asmenys_info)
in above method use any other name of object instead of asmenys_info.
because while mvc framework map your model with object there is confution in asmenys_info and Asmenys_info property of AsmenysInfoViewModel2 class.

Passing a model property to a partial view

I'm having trouble passing the correct data to a partial view, and I'm not sure why it is failing.
Say I have models
public class SubModel {
public string Wobble {get; set;}
}
public class MyModel {
public SubModel Wibble {get; set;}
}
and views
MyView.cshtml
#model MyModel
#Html.Partial("SomePartial", Model.Wibble)
and
SomePartial.cshtml
#model SubModel
<h1>Victory!</h1>
this fails with The model item passed into the dictionary is of type 'MyModel', but this dictionary requires a model item of type 'MySubModel'
When I change MyView.cshtml to
#model MyModel
#Html.Partial("SomePartial", Model.Wibble, new ViewDataDictionary<MySubModel>(Model.Wibble))
It works as expected.
Why do I need to explicitly pass a ViewDataDictionary? Why can't I just pass the model?
Note: I'm using a library that does things that make me go hrm? a lot of the time. If the above behaviour is not expected, it might be this libraries fault.
This happens when the model you pass to the partial view is null. Don't pass null to a partial view, or it will get confused about its type.
Did you try passing the submodel with Model.Wibble instead of MyModel.Wibble? The associated model is accessible in a view with Model, not the model's name.

Categories

Resources