Why .cshtml file don't see #model in .cshtml.cs file and i get Null References exception? - asp.net-core-mvc

I've created an ASP.NET Core 6 MVC project, and I want to see "Test" when i request it but I'm getting NullReferenceException. But when I create the Razor pages application and try the same thing on that project, I don't get any errors.
I run app on Ubuntu 22.04, I use .NET Core 6.0 Framework.
namespace MyApp.Namespace
{
public class TestModel : PageModel
{
public string? Message { get; set; }
public void OnGet()
{
Message = "Test";
}
}
}
View:
#model MyApp.Namespace.TestModel
<dir>#Model.Message</dir>
Exception:
NullReferenceException: Object reference not set to an instance of an object.
AspNetCoreGeneratedDocument.Views_Home_Test.ExecuteAsync() in Test.cshtml
#Model.Message
I tried to change namespaces and add a #page directive in Razor page. Nothing has changed.

According to the code above you should make the following declaration in the Razor view file:
#page
#using MyApp.Namespace
#model TestModel
<dir>#Model.Message</dir>
Detailed instructions on how to create a Razor Pages and #page, #model declarations you can find in the Microsoft documentation here: Razor Pages

MVC needs to pass model between View and controller. When you want to show values from backend, you need to return view with models.
create a model to pass data:
public class TestModel
{
public string? Message { get; set; }
}
set the default value in http get action:
public IActionResult Index()
{
TestModel test = new TestModel();
test.Message = "Test";
//return view with model
return View(test);
}
View
#model TestModel
<h1>#Model.Message</h1>
Now you can show Test in your view:

Related

Can't populate ViewModel

MVC3 project.
I have several classes: Account, Address, Phone etc. which I set up in a view model
namespace ViewModels
{
public class AccountVM
{
public Account Account { get; set; }
public Address Address { get; set; }
public Phone Phone { get; set; } }
In the controller GET action I just call the view
public ActionResult Create()
{ return View(); }
In the View I pass the View Model
#model AccountVM
I then use #Html.EditorFor's to populate all the fields and successfully pass it to the POST Action and create the records in the db. So all that code is working.
#Html.EditorFor(z => z.Account.Number)
The problem arises when I try and pre-populate some of the properties. I do the following in the GET action.
public ActionResult Create()
{ var viewModel = new AccountVM();
viewModel.Account.Number = 1000000;
return View(viewModel); }
The code passes Intellisense but when I run I get the "NullReferenceException was unhandled by user code - Object reference not set to an instance of an object" error.
I get the same error if I try and populate using code in the View.
#{ Model.Account.Number = 1000000; }
I need to be able to programatically populate properties in both the controller and the View. I've read several SO posts on how to populate a view model in the controller and modeled my code on them but for some reason my code is not working. What am I'm doing wrong here? How should I go about it in both the Controller and the View? I get that the objects are null when created but can't figure out how to get around that.
Thanks
You've instantiated the VM, but not its Account property... try this:
public ActionResult Create()
{
var viewModel = new AccountVM();
viewModel.Account = new Account();
viewModel.Account.Number = 1000000;
return View(viewModel);
}
The same goes for the view:
#{
if (Model.Account == null) {
Model.Account = new Account();
}
Model.Account.Number = 1000000;
}
Though there are few times that this probably belongs in the view. It looks like something that should be set in the controller instead.

Model not updated from view to controller

I'm trying to do that:
Create a Model, add it on a session and send it to the view.
Change Model fields on my view
Get the Model from session updated on my controller
The problem is that my model is never updated when I'm changing values on textboxes, I'm sure that I'm missing something with razor,
View:
#model MvcTestApp.Models.Car
<div class="b1">
<div class="b2">#Html.EditorFor(e => e.KM)</div>
<div class="b2">#Html.EditorFor(e => e.RegistrationNumber)</div>
</div>
#Html.ActionLink("Car", "sendCar")
Controller:
On SendCar, I would like to get the model updated.
namespace MvcTestApp.Controllers
{
public class CarController : Controller
{
public ActionResult Show()
{
var model = new MvcTestApp.Models.Car()
{
RegistrationNumber ="12345",
KM = "12345"
};
Session["temp"] = model;
return View("Show",Session["temp"]);
}
public ActionResult sendCar()
{
return View("Show", Session["temp"]);
}
}
}
Model:
namespace MvcTestApp.Models
{
public class Car
{
[DataType(DataType.Text)]
public string KM { get; set;}
[DataType(DataType.Text)]
public string RegistrationNumber { get; set;}
}
}
You need to make your sendCar controller to update the model. Currently, all the changes you do will only persist locally until you navigate away from the page. You need to post the changed model back to the server.
Take a look at the "Handling edits" part of this example to see how it can be done:
Asp.net tutorials
The way to do this is by wrapping your model details in a form with a submit function. Then in your sendCar method take in a Car object and the model binding will take care of setting everything on the new object.
If you're wanting to persist this (I assume this is just for testing purposes?) then perhaps make your car that you're returning in your show method a class variable.
You should read a beginner tutorial about ASP.NET MVC, which will explain you how to send data from a form to a controller, as it seems you are absolutely not aware of how to do this.
You are not missing 'something', you are missing all about sending data from forms to controllers.

Best way to bind the constant values into view (MVC3)

I have a constants values such as "Required","Optional", and "Hidden". I want this to bind in the dropdownlist. So far on what I've done is the below code, this is coded in the view. What is the best way to bind the constant values to the dropdownlist? I want to implement this in the controller and call it in the view.
#{
var dropdownList = new List<KeyValuePair<int, string>> { new KeyValuePair<int, string>(0, "Required"), new KeyValuePair<int, string>(1, "Optional"), new KeyValuePair<int, string>(2, "Hidden") };
var selectList = new SelectList(dropdownList, "key", "value", 0);
}
Bind the selectList in the Dropdownlist
#Html.DropDownListFor(model => model.EM_ReqTitle, selectList)
Judging by the property EM_RegTitle I'm guessing that the model you're using is auto-generated from a database in some way. Maybe Entity Framework? If this is the case, then you should be able to create a partial class in the same namespace as your ORM/Entity Framework entities and add extra properties. Something like:
public partial class MyModel
{
public SelectList MyConstantValues { get; set; }
}
You can then pass your SelectList with the rest of the model.
There are usually hangups from using ORM/EF entities through every layer in your MVC app and although it looks easy in code examples online, I would recommend creating your own View Model classes and using something like AutoMapper to fill these views. This way you're only passing the data that the views need and you avoid passing the DB row, which could contain other sensitive information that you do not want the user to view or change.
You can also move the logic to generate your static value Select Lists into your domain model, or into a service class to help keep reduce the amount of code and clutter in the controllers.
Hope this helps you in some way!
Example...
Your View Model (put this in your "Model" dir):
public class MyViewModel
{
public SelectList RegTitleSelectList { get; set; }
public int RegTitle { get; set; }
}
Your Controller (goes in the "Controllers" dir):
public class SimpleController : Controller
{
MyViewModel model = new MyViewModel();
model.RegTitle = myEfModelLoadedFromTheDb.EM_RegTitle;
model.RegTitleSelectList = // Code goes here to populate the select list.
return View(model);
}
Now right click the SimpleController class name in your editor and select "Add View...".
Create a new view, tick strongly typed and select your MyViewModel class as the model class.
Now edit the view and do something similar to what you were doing earlier in your code. You'll notice there should now be a #model line at the top of your view. This indicates that your view is a strongly typed view and uses the MyViewModel model.
If you get stuck, there are plenty of examples online to getting to basics with MVC and Strongly Typed Views.
You would prefer view model and populate it with data in controller.
class MyViewModel
{
public string ReqTitle { get; set; }
public SelectList SelectListItems { get; set; }
}
Then you can use:
#Html.DropDownListFor(model => model.EM_ReqTitle, model.SelectListItems)

MVC3 Razor Editor/Display templates and generics

There were a few questions regarding mvc templates and generics however there seems to be none related to what I'm looking for. Consider the following models:
namespace MyNamespace
{
public class ModelBase { /* Not important for example */ }
public class MyModel : ModelBase
{
public string Name { get; set; }
}
public class MyViewModel
{
public IEnumerable<ModelBase> Data { get; set; }
}
}
And a controller:
public class HomeController : Controller
{
public ActionResult Index
{
return View(new MyViewModel { Data = new List<MyModel>() })
}
}
A Razor view Views/Home/Index.cshtml would look like:
#model MyNamespace.MyViewModel
#Html.EditorFor(m => m.Data)
Nothing special there. If I want a display or editor template for that I can create a file under Views/Shared/EditorTemplate or under Views/Home/EditorTemplates called MyModel.cshtml and it finds it correctly.
What if I want to do something different for each implementation of ModelBase when showing a list? Mvc view finder will find List'1.cshtml template correctly in any of above paths. However what I need to do is do a template for List`1[MyModel].cshtml
I can't seem to get the correct file naming. What I've tried so far (relative to this example naming):
List`1[MyModel].cshtml
List`1[[MyModel]].cshtml
List`1[MyNamespace.MyModel].cshtml
List`1[[MyNamespace.MyModel]].cshtml
If possible I want to avoid writing a custom view finder. The only alternative I can think of for now if I can't get above stuff to work is to just have List`1.cshtml call a partial with naming deduced from List.
A very late response, useful if someone else bump in this very same question (as I did a few moments ago trying to remember how to do this)
You can use the UIHintAttribute to define the name of the editor
public class MyViewModel
{
[UIHint("MyModel")]
public IEnumerable<ModelBase> Data { get; set; }
}
I haven't checked this code but I would create different Views for each subtype and do something dumb like:
return View(MyModel.GetType().Name, new MyViewModel { Data = new List<MyModel>() })
So that your View matches the name of your type.
You could do this in the main view:
#model MyViewModel
#Html.EditorFor(x => x.Data)
and then have:
~/Views/Shared/EditorTemplates/MyModel.cshtml:
#model MyModel
...
~/Views/Shared/EditorTemplates/MyOtherModel.cshtml (where obviously MyOtherModel derives from ModelBase):
#model MyOtherModel
...
and so on ... ASP.NET MVC will take care of looping through the Data property and pick the correct template based on the runtime type of each element of this collection.

ASP.NET MVC 3 _Layout.cshtml Controller

Can anyone help me with the subject? I'm using Razor view engine and I need to pass some data to _Layout. How can I do it?
As usual you start by creating a view model representing the data:
public class MyViewModel
{
public string SomeData { get; set; }
}
then a controller which will fetch the data from somewhere:
public class MyDataController: Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
SomeData = "some data"
};
return PartialView(model);
}
}
then a corresponding view (~/Views/MyData/Index.cshtml) to represent the data:
#{
Layout = null;
}
<h2>#Model.SomeData</h2>
and finally inside your _Layout.cshtml include this data somewhere:
#Html.Action("index", "mydata")
You could use the ViewBag to pass data.
In your controller:
ViewBag.LayoutModel = myData;
Access in you layout:
#ViewBag.LayoutModel
It is a dynamic object, so you can use any property name you want.
The ViewBag method is the easiest. However if you need advanced and typed features, you can also try taking that part to a partial view (the part that'll render the dependent section) with a common controller (if the value can be calculated on it's own and doesn't need input from other controllers), and call RenderPartial on it from _Layout.
If you'd like I can give you some more info about it...

Resources