Why controller no works only in Html.PartialAsync?

0

Now I have a controller:

public async Task<IActionResult> Location()
        {
            Models.LocationModel Location = null;
            //some logic
            return View(Location);
        }

And here is the View:

@model Vishdo.Models.LocationModel
<div>
    <h5>@Model.City</h5>
    <span>@Model.Name</span>
    <span>@Model.Phone</span>
</div>

When I access the View by the URL(https://localhost:44372/home/location) directly, all works well.

Now I add it into the _Layout.cshtml like this:

@Html.PartialAsync("/Views/Home/Location.cshtml")

After it ran, it reports an error on the View Location.cshtml:

System.NullReferenceException
  HResult=0x80004003
  Message=Object reference not set to an instance of an object.
  Source=Sample.Views
  StackTrace:
   at AspNetCore.Views_Home_Location.<ExecuteAsync>d__0.MoveNext() in E:\Project\Sample\Views\Home\Location.cshtml:line 3

I added a breakpoint in the Location controller and found it never works. So the Model always is null and reports this error.

In addition, I add this into the _Layout.cshtml for this feature is needed by all the pages and the _Layout.cshml has not a controller so I have to do it like this.

What's wrong with my code? How can I solve it? Thank you.

asp.net-core
.net-core
asked on Stack Overflow Nov 19, 2020 by Melon NG

2 Answers

2

I added a breakpoint in the Location controller and found it never works. So the Model always is null and reports this error.

It's the expected behavior, @Html.PartialAsync() will not trigger the controller action, it directly search the partival view under the view folder.

In addition, you can achieve it with ViewComponent. I made a demo like below:

1.Create a folder named ViewComponents in your project, and create a class named LocationViewComponent

enter image description here

public class LocationViewComponent : ViewComponent
{
    public IViewComponentResult Invoke()
    {
        var Location = new LocationModel()
        {
            City = "AAA",
            Name = "BBB",
            Phone = "CCC"
        };
        return View(Location);
    }
} 

2.The default view name for a view component is Default.cshtml, add it to the Shared folder like below:

enter image description here

Default.cshtml

@model LocationModel

<div>
    <h5>@Model.City</h5>
    <span>@Model.Name</span>
    <span>@Model.Phone</span>
</div>

3.Call the ViewComponent in the layout:

<div class="container">
    <main role="main" class="pb-3">
        @RenderBody()
        @await Component.InvokeAsync("Location")
    </main>
</div>

Result:

enter image description here

For more details, you can refer to the document

answered on Stack Overflow Nov 19, 2020 by mj1313
2

Since @Html.PartialAsync() will not trigger the controller action so you've multiple options here to solve your problem.

1- you should get the Location model from any service and pass it to @Html.PartialAsync() like below:

@inject LocationService locationService
@{
    var locationModel = locationService.GetLocation();
}

and then pass this locationModel to @Html.PartialAsync()

@Html.PartialAsync("/Views/Home/Location.cshtml", locationModel );

2- Use ViewComponent as described above.

3- Use @Html.Action() by implementing this as a HtmlHelper extension. Refer this here
answered on Stack Overflow Nov 19, 2020 by Munesh Kumar

User contributions licensed under CC BY-SA 3.0