Equivalent of Html.RenderAction in ASP.NET Core
Asked Answered
G

3

48

I am trying to switch to ASP.NET Core from my small ASP.NET MVC 4 application.

In my MVC 4 application, I have a Layout file that uses RenderSection as:

@RenderSection("xyz", required: false)

Then, in my Index file, I have:

@section xyz{
        @{Html.RenderAction("abc");}
    }

So, I am calling controller action method abc() from Index. The method abc() passes a model object and returns a partial view with that model. I cannot use RenderPartial as it needs a model to be passed.

Now, in ASP.NET Core, I don't have RenderAction() method.

My question is: How would I invoke a controller action method from my Index file? Is there any other HTML helper for that (although I don't see any)?

.

Gasiform answered 28/12, 2016 at 0:30 Comment(5)
In ASP.NET Core @Html.Action (I know you are talking about RenderAction but I believe that it follows the same concept) has been replace by ViewComponents. Take a look at: #40341886 . Regards.Edithe
Thanks for the link. I am working on implementing ViewComponents to see if that woks with my project.Gasiform
It seems painful. There's no ConfigurationManager as well. A lot of reading to be done for a small application. Can it be termed as 'No backward compatibility with ASP.NET Core'?Gasiform
asp.net core is a rewrite, most but not all concepts were kept. more simple than viewcomponents is to just use a partial view. but if it needs logic or a different model than the main view like what would have been handled by a controller action then ViewComponent is the thing to useNeoprene
Can you please share controller codePikeman
G
42

I was finally able to do it with ViewComponent. So, instead of RenderAction(), I did:

@section xyz{
        @await Component.InvokeAsync("abc")
    }

Where abc is a class as abcViewComponent. The ViewComponent looks like:

public class abcViewComponent : ViewComponent
    {
        private DbContextOptions<MyContext> db = new DbContextOptions<MyContext>();
        public async Task<IViewComponentResult> InvokeAsync()
        {
            MyContext context = new MyContext(db);
            IEnumerable<tableRowClass> mc = await context.tableRows.ToListAsync();
            return View(mc);
        }
    }

Then, I created a view under a new folder 'abc' as Views/Home/Components/abc/Default.cshtml

It is to be noted that the view name is Default.cshtml and that is how it worked. If anyone has any better solution, please let me know.

Thanks for pointing me in the direction of ViewComponent.

Gasiform answered 29/12, 2016 at 4:44 Comment(3)
I know this is really picky, but class names in C# should start with a capital letter so your view component class should be AbcViewComponent and tableRowClass should be TableRowClass as well as context.tableRows should be context.TableRows. Otherwise, glad you got this working.Goa
Thanks. I have the names as you stated i.e. starting with Capital letter in my project. It's just for example here that I mentioned small case. I'll keep that in mind while posting in future.Gasiform
Worth noting that for ASP.NET Core 1.1 and higher, you can invoke a view component via tag helper: <vc:abc /> (learn.microsoft.com/en-us/aspnet/core/mvc/views/view-components)Allophane
M
10

Just for completion of the above question, it is probably safer to pass the name of the ViewComponent class as shown below:

@section xyz{
    @await Component.InvokeAsync(nameof(yournamespace.abc))
}

and although it is common to use "Default" as the resulting view, you can also return the view name if that differs from default:

public class abcViewComponent : ViewComponent
{
    private DbContextOptions<MyContext> db = new DbContextOptions<MyContext>();
    public async Task<IViewComponentResult> InvokeAsync()
    {
        MyContext context = new MyContext(db);
        IEnumerable<tableRowClass> mc = await context.tableRows.ToListAsync();
        return View("YourViewName", mc);
    }
}
Mckeon answered 18/1, 2018 at 13:25 Comment(0)
M
8

There is a workaround, you could use the Url.Action + JQuery to render the content.

The view where you want to render the action will look like this :

<div id="dynamicContentContainer"></div>
<script>   
    $.get('@Url.Action("GetData", "Home")', {id : 1}, function(content){
            $("#dynamicContentContainer").html(content);
        });
</script>

The Home controller :

[HttpGet]
public IActionResult GetData(int id)
{
   return PartialView(id);
}

The view

@model int 
<span>Values from controler :</span> @Model

If you want more control over the request you can read here more information : jQuery.get()

Macario answered 3/8, 2017 at 21:39 Comment(5)
This is not the equivalent of RenderAction, this is an entirely different approach.Salesperson
@PaulKnopf Aside from lacking the [ChildActionOnly] support, what else specifically is different?Sophister
This is one of the crappy things about where mvc is heading these days. <partial name="_PartialView" model="Model.object" /> is fine but <render controller="Controller" action="Action" params=new { id : 'xyz' } /> is not a thingAllomerism
This approach renders the action result after the page is already loaded instead of during the load. Also it does require JS, which might not be a concern for the majority of desktop browsers, but might become challenging on mobiles, especially on a low-speed and/or flaky connections, but also on low-grade phones with exotic browsers.Godard
@SergeyKudriavtsev True, as I said it's just a workaround, but yes, this runs after the page is already loaded.Macario

© 2022 - 2024 — McMap. All rights reserved.