5

Is it possible to refresh a View Component in an ASP.NET Core 2.1 Razor page?

I discovered that this is possible in ASP.NET MVC using AJAX—see solutions at Viewcomponent alternative for ajax refresh and ViewComponents are not async. But what about ASP.NET Core?

One solution I found is basically to have a controller returning the View Component, and then using AJAX to do the refresh.

This is example is borrowed from ViewComponents are not async

~/HelloWorldViewComponent.cs

public class HelloWorldViewComponent : ViewComponent
{
    public IViewComponentResult Invoke()
    {
        var model = new string[]
        {
            "Hello", "from", "the", "view", "component."  
        };

        return View("Default", model);
    }     
}

~/HomeController.cs (I cannot get this part working in razor pages)

public class HomeController : Controller
{
    public IActionResult GetHelloWorld()
    {
        return ViewComponent("HelloWorld");
    }
}

~/Views/Shared/Components/HelloWorld/Default.cshtml

@model string[]
<ul>
    @foreach(var item in Model)
    {
        <li>@item</li>
    }
</ul>

~/wwwroot/index.html

<body>
<script src="js/jquery.min.js"></script>
<script>
    $.get("home/GetHelloWorld", function(data) {
        $("body").html(data);
    });
</script>
</body>

My problem is that I cannot get a controller working together with Razor Pages, I cannot figure out if that's even possible.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
E. Malmqvist
  • 310
  • 2
  • 11
  • You want to refresh a div with new data? – Muhammad Hannan Jul 06 '18 at 11:06
  • You could do an ajax post/get to the controller which returns a rendered view (as HTML string), put that into a JSON response and in javascript replace a whole div like $("#divid").html(responseJson.HtmlView). – Iztoksson Jul 06 '18 at 12:09
  • @MuhammadHannan, yes, it´s because the VC needs to refresh data. – E. Malmqvist Jul 06 '18 at 12:29
  • @Iztoksson, the problem is that I don´t have a controller since I´m using razor pages, and I could not get it to work with both razor pages and controllers. – E. Malmqvist Jul 06 '18 at 12:31
  • 1
    Your issue may be as basic as simply fetching the wrong URL. Razor Pages build their routes based on the file structure, which means the URL you're attempting to make the AJAX request from is something like `/My/Razor/Page`. Then, you're requesting `home/GetHelloWorld`, which is actually going to be interpreted as `/My/Razor/Page/home/GetHelloWorld`. You need a `/` in front of the URL for your AJAX request (i.e. `/home/GetHelloWorld`). – Chris Pratt Jul 06 '18 at 13:03

2 Answers2

1

TLDR

Open Startup.cs and replace this

app.UseMvc();

with this

app.UseMvcWithDefaultRoute();

Details

The ASP.NET Core Razor Pages template (dotnet new razor) does not come with controller routes because it does not come with controllers. The easiest way to add controller routes is via UseMvcWithDefaultRoute(), which is the equivalent of the following:

app.UseMvc(routes => 
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

With that route installed, the URL ~/Home/GetHelloWorld maps to the HomeController.GetHelloWorld() action.

Here is a GitHub commit that demonstrates your use case in a new ASP.NET Core Razor Pages app.

See Also

https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/routing?view=aspnetcore-2.1

Shaun Luttin
  • 133,272
  • 81
  • 405
  • 467
  • app.UseMvcWithDefaultRoute(); throws exception @net core 3.0.My current solution as follows app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}"); – erhan355 Jan 25 '20 at 03:04
1

To do this within the RazorPage ensure that the handler method follows the convention OGet[MyMethodName] and this should resolve your routing issue

public class HomeController : Controller
{
    public IActionResult OnGetHelloWorld()
    {
        return ViewComponent("HelloWorld");
    }
}

And modify the get request to make use of the handler

<body>
<script src="js/jquery.min.js"></script>
<script>
    $.get(window.location.href.split('?')[0] + "?handler=HelloWorld", function(data) {
        $("body").html(data);
    });
</script>
</body>

Various example are available at https://learn.microsoft.com/en-us/aspnet/core/razor-pages/?view=aspnetcore-3.1&tabs=visual-studio

Paul Hodgson
  • 939
  • 8
  • 15