1

My action is

public ActionResult Login(string returnUrl)
{
    ViewBag.returnUrl = returnUrl;
    return View();
}

In the view I defined model @model OnlineShop.Models.ViewModels.LoginModel and when I use helper @Html.EditorFor(m => m.UserName) I get System.NullReferenceException.

Do I really need to pass an instance of my model in the action like return View(new LoginModel()) when I would like to use Html.EditorFor()?

Grigory Zhadko
  • 860
  • 1
  • 12
  • 22
Qwertyluk
  • 88
  • 1
  • 10

3 Answers3

2

Check https://docs.microsoft.com/en-us/aspnet/core/mvc/views/overview?view=aspnetcore-3.1#passing-data-to-views

To provide the model to the view, the controller passes it as a parameter:

public IActionResult Contact()
{
    ViewData["Message"] = "Your contact page.";

    var viewModel = new Address()
    {
        Name = "Microsoft",
        Street = "One Microsoft Way",
        City = "Redmond",
        State = "WA",
        PostalCode = "98052-6399"
    };

    return View(viewModel);
}

Check also the definition of view: https://docs.microsoft.com/en-us/dotnet/api/system.web.mvc.controller.view?view=aspnet-mvc-5.2

You need to use a view with an object to return the data to the view. Be careful as a string alone is considered a view name.

Athanasios Kataras
  • 20,791
  • 3
  • 24
  • 45
2

Yes.

When you use the @model type directive at the top of your view, you are telling the framework it can expect an instance of that type. The HTML helpers (e.g. Html.DisplayFor, Html.EditorFor, etc.) are all based on the type of model that you supply. You can see this if you open your view, and hover your mouse cursor over EditorFor. You'll see something like this:

string IHtmlHelper<OnlineShop.Models.ViewModels.LoginModel>.DisplayNameFor<string>(
    System.Linq.Expressions.Expression<Func<OnlineShop.Models.ViewModels.LoginModel, string>> expression)

Notice that the method is generic and is based on OnlineShop.Models.ViewModels.LoginModel. This is because these methods are expecting you to pass an instance of OnlineShop.Models.ViewModels.LoginModel to your view, as that's what you stated using the @model directive at the top of your view.

No because I know what this exception means but I do not know why I get it in this particular situation. For example for Html.LabelFor it works fine.

The reason it works for LabelFor is because LabelFor is looking at metadata for your model, rather than needing an instance of it. By default, it simply creates a label with the name of the property you pass it. In your case, if you called @Html.LabelFor(m => m.Username) it will create a label HTML element whose text is Username, but it doesn't need an instance of your viewmodel to do that.

EditorFor, on the other hand, is both looking at metadata for your Username property, to create an appropriate input HTML element (e.g. a textbox for a string, or a checkbox for a bool), and also using the value of the Username property in order to populate that editor (e.g. checking the checkbox). That's why you get the exception when calling Html.EditorFor(m => m.Username) when you're not giving it an instance of your model.

John H
  • 13,157
  • 4
  • 33
  • 68
  • @Qwertyluk I've just added a bit to address your comment above. – John H Sep 17 '20 at 17:40
  • Oh okey, thank you very much! – Qwertyluk Sep 17 '20 at 17:41
  • @Qwertyluk `Html.LabelFor` will always work without a model, as long as you specify the `@model` directive in your view to tell the framework what your model type is. At that point, any call to `Html.LabelFor` will examine the model _type_ to determine what to render - it doesn't need an _instance_ of that type. – John H Sep 17 '20 at 17:43
  • I also have the same code on the other machine and it works fine. It seems very strange why it works there. – Qwertyluk Sep 17 '20 at 17:51
1

Short answer: yes, your action must provide an instance of your model the the view.

@model OnlineShop.Models.ViewModels.LoginModel informs the view to expect Model to be of that type and that it will be passed to the view by the controller. LoginModel being a class, it's default value is null.

Babak Naffas
  • 11,532
  • 3
  • 32
  • 48