ASP.NET Core Render View to String

Written by ppolyzos

Software engineer based in Athens, Greece


  1. Hasan Yousef

    This is really great, I’m new to c# / .NET CORE and Razor.
    I liked this so much, but could not know how to display the model data in the view, can you add simple Invite.cshtml file.


  2. Hasan Yousef

    I tried to run it with minimum dependencies, so got the:
    var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);

    returns a NULL

    the dependencies I limited myself to, are:

    “Microsoft.AspNetCore.Server.Kestrel”: “1.0.1”,
    “Microsoft.AspNetCore.Mvc”: “1.0.1”

    what is the missing one?


    1. ppolyzos

      I guess you are missing “Microsoft.AspNetCore.Mvc.Razor” package.
      You can install it through NuGet:
      Install-Package Microsoft.AspNetCore.Mvc.Razor

  3. Damian

    Thanks! Works fine for me too, except that it does not render views containing @Html.Partial. it then only returns an empty string.

    As in your example, I also intend to use the function for E-Mails, so I try to include Header/Footer with
    @Html.Partial(“Header”) and

    Header.cshtml and Footer.cshtml are in the same Folder as the main view.

    Any idea how to solve this?

    1. Damian

      Arrr, got it.
      @Html.Partial(“Header.cshtml”) (Notice the .cshtml) and it’s working – altough Visual Studio states that it cannot resolve the View then.

      1. ppolyzos

        I think that cshtml is not necessary. Have you tried to declare the path using ~ as prefix. Like for example: @Html.Partial("~/folder/Header").
        Thank you for your help! I really appreciate it.

  4. Djordje

    Hi, this is one great example for me.
    I implement similar thing in my project, just without async call. Like this:

    Howverer, when executing line view.RenderAsync(viewContext).GetAwaiter().GetResult();
    I get exception:
    “The model item passed into the ViewDataDictionary is of type ‘Newtonsoft.Json.Linq.JObject’, but this ViewDataDictionary instance requires a model item of type ‘System.String’.”

    I’m pretty sure that I passing JObject to ViewDataDictionary (can see in Model property) and also have @model JObject statement in my razor view.

    When I worked on “Microsoft.AspNetCore.Mvc.Razor”: “1.0.0” (all other depedencies also was 1.0.0) all was fine, however when I move all to 1.1.0 issues began.
    Maybe you have any idea what can be wrong here?

    1. ppolyzos

      Well I created a sample app to see if it works with .net core 1.1 and didn’t face any problem.
      The project.json file I used is the following:

      And here is the code for my controller, based on your example:

      And the Invite.cshtml view:

      Could you please check if the model you are passing is a JObject object?

  5. jmal73

    Great Post!

    But I’m having 2 issues.

    1. Is the same issue as @Damian on @Html.Partial(“xx.cshtml”). It requires the .cshtml extension to work with this code (works fine without the .cshtml when called through a controller/view).

    2. Having issues with all TagHelpers on the view and Partial Views… It errors out on those lines when calling this method, but the views work fine when called normally though a controller.
    for instance it stops on this:
    @Model.InventoryClass.InvClass with the error ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
    Parameter name: index

    1. jmal73

      The post stripped out my TagHelper html! Here it is again enclosed in [] instead of .
      [a asp-controller=”Store” asp-action=”Category” asp-route-cat1Id=”@Model.InvClassID”>@Model.InventoryClass.InvClass</a]

    2. jmal73

      I was able to get TagHelpers working by what was posted here as well multiple other places and merging them all together… I had to inject IHttpContextAccessor and get the actual HttpContext and get the RouteData of the request. The code that injectsIServiceProvider _serviceProvider and {RequestServices = _serviceProvider} seemed to be empty, so I removed it???

      I still have to append .cshtml in any Partial Views (i.e. @Html.Partial("_Accessories.cshtml", model) ).

      Below is the code I’m using:

      In Startup.cs

      In IViewRenderService.cs

      In ViewRenderService.cs

  6. San

    Will this work for converting partial views to string as well? I need to render a partial view _Notify.cshtml in the Shared folder. But the following code :
    string viewHtml = _viewRender.Render(“_Notification.cshtml”);
    gives an error that it cannot find the view.

    1. ppolyzos

      Yes, this will work. Use the RenderToStringAsync method from IViewRenderService as described above and it will work.
      If you have a Partial view _Invite.cshtml in folder Views\Email simply call:

    1. ppolyzos

      Yes, you need to specify the parent folder. By default, it only checks in Views folder.
      All other folders do not have any special meaning.

      So in your case you use: Shared/_Invite.

    1. ppolyzos

      I am not sure you can pass ViewBag as an argument in this case.
      You can pass a dictionary with a string key and an object value, and have the same result.

  7. Des-Angelo Pennant

    Recieving a index was out of range error when:

    await viewResult.View.RenderAsync(viewContext);
    is called.

    Unable to see why. Help please.

      1. Des-Angelo Pennant

        The view is found here:

        var viewResult = _razorViewEngine.GetView(viewName, viewName, false);

        the viewResult came back with success but when it reaches:

        await viewResult.View.RenderAsync(viewContext);

        an exception is thrown saying index is out of range. so I am thinking that if the view was found the path is correct.

        1. Des-Angelo Pennant

          I was wondering if it because it is a view model. This is my view code:

          This is the Model:

  8. Md. Rashidul Hasan Masum

    Shows following error

    RuntimeBinderException: ‘Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor’ does not contain a definition for ‘ControllerTypeInfo’
    CallSite.Target(Closure , CallSite , object )

    AggregateException: One or more errors occurred. (‘Microsoft.AspNetCore.Mvc.Abstractions.ActionDescriptor’ does not contain a definition for ‘ControllerTypeInfo’)

  9. Rob

    I’m experiencing a caching issue – if I update the view and refresh browser it does not update. During debugging I can see that the string response from the ViewRenderService.RenderToStringAsync call does not change. The only way to clear the cache is stop/start debugger.

    1. ppolyzos

      RazorViewEngine caches the view once loaded and then you need to perform a re-build to fetch the new and changed view. You can change this behavior by implementing your own view engine.
      I ‘ll let you know, when I find an easy way to purge cache on view change.

  10. Hector

    What if the view I am trying to render got a parameter. Because I keep getting an error saying that the view doesn’t exist.

    For example: “Products/Details/552”

    Where the number at the end is a unique id for the product.

    1. ppolyzos

      I think this is not possible, as it won’t find the actual view is stored. Instead, you can try await _viewRenderService.RenderToStringAsync("Products/Details", viewModel), where your viewModel has the id parameter.

  11. Jeppe Rask

    Thanks for the snippet. I was getting the “ArgumentOutOfRangeException: Index was out of range”, mentioned above – turned out to be an anchor-tag on the form:

    Like jmal73 suggested, adding the the routedata to the viewContext helped, but I also had to change how i retrieved the httpContext, like so:
    var http = _serviceProvider.GetService();
    var httpContext = http.HttpContext;
    Now it looks like this:


    I’m new to Core (actually using .Net Core 2 here). In Startup.cs

    I’m getting the error:
    The type ‘ProjectName.Services.ViewRenderService’ cannot be used as type parameter ‘TImplementation’ in the generic type or method ‘ServiceCollectionServiceExtensions.AddScoped(IServiceCollection)’. There is no implicit reference conversion from ‘ProjectName.Services.ViewRenderService’ to ‘ProjectName.Services.IViewRenderService’.

    1. ppolyzos

      You can have a look at the following article to learn more about Dependency Injection in ASP.NET Core.
      Now, regarding your error, in your application’s Startup class, in ConfigureServices method and after services.AddMvc() you need to register your services in services container.
      So you need to add:

      Scoped lifetime means that services are created once per request.

      In addition make sure that ViewRenderService class implements IViewRenderService interface.

  13. Harun


    I keep getting an error that says :

    InvalidOperationException: The partial view ‘_partialView’ was not found. The following locations were searched:


    await Html.RenderPartialAsync(“~/Views/folder/_partialView”, new viewModel {viewModel = model});

    I have tried several different solutions with no success.. How can i fix this ??

  14. Cedric

    Hi there,

    I have implemented this in a .NET Core 2.0 web application and it works great when I run it locally, however when deployed on Azure (App Service) it stops working with an InvalidOperationException: Couldn’t find view ‘ConfirmAddressEmailTemplate’ and I can’t figure out why.
    You guys got any idea what could be wrong here?

    1. Cedric

      It turns out it works only when the views are located in the Views folder, if I put them in another folder outside of the default Views folder it does not work. Strange. Maybe a security thing on Azure?

      1. lizm

        Cedric, you need to set MvcRazorCompileOnPublish to false.
        In your csproj file:

  15. alex

    Thank you so much! This is really great help! Managed to get this to work with ASP.NET Core 2.0 MVC. Also, some of the comments here are very very useful – big thank you to everybody!

Leave a Comment

Your email address will not be published. Required fields are marked *