Return View as String in .NET Core











up vote
24
down vote

favorite
11












I found some article how to return view to string in ASP.NET, but could not covert any to be able to run it with .NET Core



public static string RenderViewToString(this Controller controller, string viewName, object model)
{
var context = controller.ControllerContext;
if (string.IsNullOrEmpty(viewName))
viewName = context.RouteData.GetRequiredString("action");

var viewData = new ViewDataDictionary(model);

using (var sw = new StringWriter())
{
var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
viewResult.View.Render(viewContext, sw);

return sw.GetStringBuilder().ToString();
}
}


which assumed to be able to call from a Controller using:



var strView = this.RenderViewToString("YourViewName", yourModel);


When I try to run the above into .NET Core I get lots of compilation errors.



I tried to convert it to work with .NET Core, but failed, can anyone help with mentioning the required using .. and the required "dependencies": {
"Microsoft.AspNetCore.Mvc": "1.1.0",
...
},
to be used in the project.json.



some other sample codes are here and here and here



NOTE
I need the solution to get the view converted to string in .NET Core, regardless same code got converted, or another way that can do it.










share|improve this question




























    up vote
    24
    down vote

    favorite
    11












    I found some article how to return view to string in ASP.NET, but could not covert any to be able to run it with .NET Core



    public static string RenderViewToString(this Controller controller, string viewName, object model)
    {
    var context = controller.ControllerContext;
    if (string.IsNullOrEmpty(viewName))
    viewName = context.RouteData.GetRequiredString("action");

    var viewData = new ViewDataDictionary(model);

    using (var sw = new StringWriter())
    {
    var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
    var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
    viewResult.View.Render(viewContext, sw);

    return sw.GetStringBuilder().ToString();
    }
    }


    which assumed to be able to call from a Controller using:



    var strView = this.RenderViewToString("YourViewName", yourModel);


    When I try to run the above into .NET Core I get lots of compilation errors.



    I tried to convert it to work with .NET Core, but failed, can anyone help with mentioning the required using .. and the required "dependencies": {
    "Microsoft.AspNetCore.Mvc": "1.1.0",
    ...
    },
    to be used in the project.json.



    some other sample codes are here and here and here



    NOTE
    I need the solution to get the view converted to string in .NET Core, regardless same code got converted, or another way that can do it.










    share|improve this question


























      up vote
      24
      down vote

      favorite
      11









      up vote
      24
      down vote

      favorite
      11






      11





      I found some article how to return view to string in ASP.NET, but could not covert any to be able to run it with .NET Core



      public static string RenderViewToString(this Controller controller, string viewName, object model)
      {
      var context = controller.ControllerContext;
      if (string.IsNullOrEmpty(viewName))
      viewName = context.RouteData.GetRequiredString("action");

      var viewData = new ViewDataDictionary(model);

      using (var sw = new StringWriter())
      {
      var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
      var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
      viewResult.View.Render(viewContext, sw);

      return sw.GetStringBuilder().ToString();
      }
      }


      which assumed to be able to call from a Controller using:



      var strView = this.RenderViewToString("YourViewName", yourModel);


      When I try to run the above into .NET Core I get lots of compilation errors.



      I tried to convert it to work with .NET Core, but failed, can anyone help with mentioning the required using .. and the required "dependencies": {
      "Microsoft.AspNetCore.Mvc": "1.1.0",
      ...
      },
      to be used in the project.json.



      some other sample codes are here and here and here



      NOTE
      I need the solution to get the view converted to string in .NET Core, regardless same code got converted, or another way that can do it.










      share|improve this question















      I found some article how to return view to string in ASP.NET, but could not covert any to be able to run it with .NET Core



      public static string RenderViewToString(this Controller controller, string viewName, object model)
      {
      var context = controller.ControllerContext;
      if (string.IsNullOrEmpty(viewName))
      viewName = context.RouteData.GetRequiredString("action");

      var viewData = new ViewDataDictionary(model);

      using (var sw = new StringWriter())
      {
      var viewResult = ViewEngines.Engines.FindPartialView(context, viewName);
      var viewContext = new ViewContext(context, viewResult.View, viewData, new TempDataDictionary(), sw);
      viewResult.View.Render(viewContext, sw);

      return sw.GetStringBuilder().ToString();
      }
      }


      which assumed to be able to call from a Controller using:



      var strView = this.RenderViewToString("YourViewName", yourModel);


      When I try to run the above into .NET Core I get lots of compilation errors.



      I tried to convert it to work with .NET Core, but failed, can anyone help with mentioning the required using .. and the required "dependencies": {
      "Microsoft.AspNetCore.Mvc": "1.1.0",
      ...
      },
      to be used in the project.json.



      some other sample codes are here and here and here



      NOTE
      I need the solution to get the view converted to string in .NET Core, regardless same code got converted, or another way that can do it.







      c# asp.net razor asp.net-core .net-core






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Sep 4 at 4:23









      sbhomra

      1,83111738




      1,83111738










      asked Dec 1 '16 at 13:49









      Hasan A Yousef

      5,10133064




      5,10133064
























          6 Answers
          6






          active

          oldest

          votes

















          up vote
          27
          down vote



          accepted










          Thanks to Paris Polyzos and his article.



          I'm re-posting his code here, just in case the original post got removed for any reason.



          Create Service in file viewToString.cs as below code:



          using System;
          using System.IO;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
           
          namespace WebApplication.Services
          {
              public interface IViewRenderService
              {
                  Task<string> RenderToStringAsync(string viewName, object model);
              }
           
              public class ViewRenderService : IViewRenderService
              {
                  private readonly IRazorViewEngine _razorViewEngine;
                  private readonly ITempDataProvider _tempDataProvider;
                  private readonly IServiceProvider _serviceProvider;
           
                  public ViewRenderService(IRazorViewEngine razorViewEngine,
                      ITempDataProvider tempDataProvider,
                      IServiceProvider serviceProvider)
                  {
                      _razorViewEngine = razorViewEngine;
                      _tempDataProvider = tempDataProvider;
                      _serviceProvider = serviceProvider;
                  }
           
                  public async Task<string> RenderToStringAsync(string viewName, object model)
                  {
                      var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
                      var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
           
                      using (var sw = new StringWriter())
                      {
                          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
           
                          if (viewResult.View == null)
                          {
                              throw new ArgumentNullException($"{viewName} does not match any available view");
                          }
           
                          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                          {
                              Model = model
                          };
           
                          var viewContext = new ViewContext(
                              actionContext,
                              viewResult.View,
                              viewDictionary,
                              new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                              sw,
                              new HtmlHelperOptions()
                          );
           
                          await viewResult.View.RenderAsync(viewContext);
                          return sw.ToString();
                      }
                  }
              }
          }




          1. Add the service to the Startup.cs file, as:



            using WebApplication.Services;

            public void ConfigureServices(IServiceCollection services)
            {
            ...
                services.AddScoped<IViewRenderService, ViewRenderService>();
            }



          Add "preserveCompilationContext": true to the buildOptions in the project.json, so the file looks like:



          {
          "version": "1.0.0-*",
          "buildOptions": {
          "debugType": "portable",
          "emitEntryPoint": true,
          "preserveCompilationContext": true
          },
          "dependencies": {
          "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
          "Microsoft.AspNetCore.Mvc": "1.0.1"
          },
          "frameworks": {
          "netcoreapp1.0": {
          "dependencies": {
          "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
          }
          },
          "imports": "dnxcore50"
          }
          }
          }




          1. Define you model, for example:



            public class InviteViewModel {
            public string UserId {get; set;}
            public string UserName {get; set;}
            public string ReferralCode {get; set;}
            public int Credits {get; set;}
            }



          2. Create your Invite.cshtml for example:



            @{
            ViewData["Title"] = "Contact";
            }
            @ViewData["Title"].
            user id: @Model.UserId


          3. In the Controller:



          a. Define the below at the beginning:



          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }


          b. Call and return the view with model as below:



          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);


          c. The FULL controller example, could be like:



          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Mvc;

          using WebApplication.Services;

          namespace WebApplication.Controllers
          {
          [Route("render")]
          public class RenderController : Controller
          {
          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }
           
          [Route("invite")]
          public async Task<IActionResult> RenderInviteView()
          {
          ViewData["Message"] = "Your application description page.";
          var viewModel = new InviteViewModel
          {
          UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
          UserName = "Hasan",
          ReferralCode = "55e12b710f78",
          Credits = 10
          };
           
          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);
          }
          }

          public class InviteViewModel {
          public string UserId {get; set;}
          public string UserName {get; set;}
          public string ReferralCode {get; set;}
          public int Credits {get; set;}
          }
          }





          share|improve this answer



















          • 9




            That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
            – philw
            Nov 1 '17 at 17:50






          • 2




            With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
            – martonx
            Feb 25 at 22:56










          • check my answer in the post. I pasted a sample code of cshtml.
            – Chan
            Nov 8 at 5:02


















          up vote
          21
          down vote













          If like me you have a number of controllers that need this, like in a reporting site, it's not really ideal to repeat this code, and even injecting or calling another service doesn't really seem right.



          So I've made my own version of the above with the following differences:




          • model strong-typing

          • error checking when finding a view

          • ability to render views as partials or pages

          • asynchronus

          • implemented as a controller extension


          • no DI needed



            using Microsoft.AspNetCore.Mvc;
            using Microsoft.AspNetCore.Mvc.Rendering;
            using Microsoft.AspNetCore.Mvc.ViewEngines;
            using Microsoft.AspNetCore.Mvc.ViewFeatures;
            using System.IO;
            using System.Threading.Tasks;

            namespace CC.Web.Helpers
            {
            public static class ControllerExtensions
            {
            public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
            {
            if (string.IsNullOrEmpty(viewName))
            {
            viewName = controller.ControllerContext.ActionDescriptor.ActionName;
            }

            controller.ViewData.Model = model;

            using (var writer = new StringWriter())
            {
            IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
            ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);

            if (viewResult.Success == false)
            {
            return $"A view with the name {viewName} could not be found";
            }

            ViewContext viewContext = new ViewContext(
            controller.ControllerContext,
            viewResult.View,
            controller.ViewData,
            controller.TempData,
            writer,
            new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);

            return writer.GetStringBuilder().ToString();
            }
            }
            }
            }



          Then just implement with:



          viewHtml = await this.RenderViewAsync("Report", model);


          Or this for a PartialView:



          partialViewHtml = await this.RenderViewAsync("Report", model, true);





          share|improve this answer



















          • 4




            This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
            – DGaspar
            May 11 at 10:40










          • Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
            – LentoMan
            May 18 at 14:25










          • @LentoMan could you post an example of the wrapper extension that you mentioned?
            – Mike Moore
            Jun 2 at 22:18










          • Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
            – LentoMan
            Jun 4 at 10:47












          • If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
            – Red
            Jun 4 at 14:08


















          up vote
          1
          down vote













          The link below tackles pretty much the same issue:



          Where are the ControllerContext and ViewEngines properties in MVC 6 Controller?



          In Hasan A Yousef's answer I had to make the same change as in the link above to make it work me:



          using Microsoft.AspNetCore.Hosting;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
          using System;
          using System.IO;
          using System.Threading.Tasks;

          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
          var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter()) {
          //var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false);
          if (viewResult.View == null) {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions());
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }





          share|improve this answer























          • Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
            – ppumkin
            Nov 16 at 14:44






          • 1




            Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
            – Richard Mneyan
            Nov 16 at 15:26


















          up vote
          1
          down vote













          The answers above are fine, but need to tweaking to get any tag helpers to work (we need to use the actually http context). Also you will need to explicitly set
          the layout in the view to get a layout rendered.



          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;
          private readonly HttpContext _http;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter())
          {
          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder
          if (viewResult.View == null)
          {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
          {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(_http, _tempDataProvider), sw, new HtmlHelperOptions());
          viewContext.RouteData = _http.GetRouteData();
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }
          }





          share|improve this answer

















          • 1




            Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
            – Dave Glassborow
            Jan 12 at 11:55




















          up vote
          1
          down vote













          I tried the solution which answered by @Hasan A Yousef in Dotnet Core 2.1, but the csthml do not work well to me. It always throws a NullReferenceException, see screenshot.
          enter image description here



          To solve it, I assign the Html.ViewData.Model to a new object. Here is my code.



          @page
          @model InviteViewModel
          @{
          var inviteViewModel = Html.ViewData.Model;
          }

          <p>
          <strong>User Id:</strong> <code>@inviteViewModel.UserId </code>
          </p>





          share|improve this answer





















          • I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
            – gbade_
            Nov 27 at 11:33




















          up vote
          -1
          down vote













          Microsoft has an excellent article on Controller Testing at https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing



          Once you have returned a ViewResult then you can get the string content by



          var strResult = ViewResult.Content






          share|improve this answer

















          • 1




            I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
            – Hasan A Yousef
            Dec 2 '16 at 10:48











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f40912375%2freturn-view-as-string-in-net-core%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          6 Answers
          6






          active

          oldest

          votes








          6 Answers
          6






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          27
          down vote



          accepted










          Thanks to Paris Polyzos and his article.



          I'm re-posting his code here, just in case the original post got removed for any reason.



          Create Service in file viewToString.cs as below code:



          using System;
          using System.IO;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
           
          namespace WebApplication.Services
          {
              public interface IViewRenderService
              {
                  Task<string> RenderToStringAsync(string viewName, object model);
              }
           
              public class ViewRenderService : IViewRenderService
              {
                  private readonly IRazorViewEngine _razorViewEngine;
                  private readonly ITempDataProvider _tempDataProvider;
                  private readonly IServiceProvider _serviceProvider;
           
                  public ViewRenderService(IRazorViewEngine razorViewEngine,
                      ITempDataProvider tempDataProvider,
                      IServiceProvider serviceProvider)
                  {
                      _razorViewEngine = razorViewEngine;
                      _tempDataProvider = tempDataProvider;
                      _serviceProvider = serviceProvider;
                  }
           
                  public async Task<string> RenderToStringAsync(string viewName, object model)
                  {
                      var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
                      var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
           
                      using (var sw = new StringWriter())
                      {
                          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
           
                          if (viewResult.View == null)
                          {
                              throw new ArgumentNullException($"{viewName} does not match any available view");
                          }
           
                          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                          {
                              Model = model
                          };
           
                          var viewContext = new ViewContext(
                              actionContext,
                              viewResult.View,
                              viewDictionary,
                              new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                              sw,
                              new HtmlHelperOptions()
                          );
           
                          await viewResult.View.RenderAsync(viewContext);
                          return sw.ToString();
                      }
                  }
              }
          }




          1. Add the service to the Startup.cs file, as:



            using WebApplication.Services;

            public void ConfigureServices(IServiceCollection services)
            {
            ...
                services.AddScoped<IViewRenderService, ViewRenderService>();
            }



          Add "preserveCompilationContext": true to the buildOptions in the project.json, so the file looks like:



          {
          "version": "1.0.0-*",
          "buildOptions": {
          "debugType": "portable",
          "emitEntryPoint": true,
          "preserveCompilationContext": true
          },
          "dependencies": {
          "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
          "Microsoft.AspNetCore.Mvc": "1.0.1"
          },
          "frameworks": {
          "netcoreapp1.0": {
          "dependencies": {
          "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
          }
          },
          "imports": "dnxcore50"
          }
          }
          }




          1. Define you model, for example:



            public class InviteViewModel {
            public string UserId {get; set;}
            public string UserName {get; set;}
            public string ReferralCode {get; set;}
            public int Credits {get; set;}
            }



          2. Create your Invite.cshtml for example:



            @{
            ViewData["Title"] = "Contact";
            }
            @ViewData["Title"].
            user id: @Model.UserId


          3. In the Controller:



          a. Define the below at the beginning:



          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }


          b. Call and return the view with model as below:



          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);


          c. The FULL controller example, could be like:



          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Mvc;

          using WebApplication.Services;

          namespace WebApplication.Controllers
          {
          [Route("render")]
          public class RenderController : Controller
          {
          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }
           
          [Route("invite")]
          public async Task<IActionResult> RenderInviteView()
          {
          ViewData["Message"] = "Your application description page.";
          var viewModel = new InviteViewModel
          {
          UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
          UserName = "Hasan",
          ReferralCode = "55e12b710f78",
          Credits = 10
          };
           
          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);
          }
          }

          public class InviteViewModel {
          public string UserId {get; set;}
          public string UserName {get; set;}
          public string ReferralCode {get; set;}
          public int Credits {get; set;}
          }
          }





          share|improve this answer



















          • 9




            That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
            – philw
            Nov 1 '17 at 17:50






          • 2




            With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
            – martonx
            Feb 25 at 22:56










          • check my answer in the post. I pasted a sample code of cshtml.
            – Chan
            Nov 8 at 5:02















          up vote
          27
          down vote



          accepted










          Thanks to Paris Polyzos and his article.



          I'm re-posting his code here, just in case the original post got removed for any reason.



          Create Service in file viewToString.cs as below code:



          using System;
          using System.IO;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
           
          namespace WebApplication.Services
          {
              public interface IViewRenderService
              {
                  Task<string> RenderToStringAsync(string viewName, object model);
              }
           
              public class ViewRenderService : IViewRenderService
              {
                  private readonly IRazorViewEngine _razorViewEngine;
                  private readonly ITempDataProvider _tempDataProvider;
                  private readonly IServiceProvider _serviceProvider;
           
                  public ViewRenderService(IRazorViewEngine razorViewEngine,
                      ITempDataProvider tempDataProvider,
                      IServiceProvider serviceProvider)
                  {
                      _razorViewEngine = razorViewEngine;
                      _tempDataProvider = tempDataProvider;
                      _serviceProvider = serviceProvider;
                  }
           
                  public async Task<string> RenderToStringAsync(string viewName, object model)
                  {
                      var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
                      var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
           
                      using (var sw = new StringWriter())
                      {
                          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
           
                          if (viewResult.View == null)
                          {
                              throw new ArgumentNullException($"{viewName} does not match any available view");
                          }
           
                          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                          {
                              Model = model
                          };
           
                          var viewContext = new ViewContext(
                              actionContext,
                              viewResult.View,
                              viewDictionary,
                              new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                              sw,
                              new HtmlHelperOptions()
                          );
           
                          await viewResult.View.RenderAsync(viewContext);
                          return sw.ToString();
                      }
                  }
              }
          }




          1. Add the service to the Startup.cs file, as:



            using WebApplication.Services;

            public void ConfigureServices(IServiceCollection services)
            {
            ...
                services.AddScoped<IViewRenderService, ViewRenderService>();
            }



          Add "preserveCompilationContext": true to the buildOptions in the project.json, so the file looks like:



          {
          "version": "1.0.0-*",
          "buildOptions": {
          "debugType": "portable",
          "emitEntryPoint": true,
          "preserveCompilationContext": true
          },
          "dependencies": {
          "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
          "Microsoft.AspNetCore.Mvc": "1.0.1"
          },
          "frameworks": {
          "netcoreapp1.0": {
          "dependencies": {
          "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
          }
          },
          "imports": "dnxcore50"
          }
          }
          }




          1. Define you model, for example:



            public class InviteViewModel {
            public string UserId {get; set;}
            public string UserName {get; set;}
            public string ReferralCode {get; set;}
            public int Credits {get; set;}
            }



          2. Create your Invite.cshtml for example:



            @{
            ViewData["Title"] = "Contact";
            }
            @ViewData["Title"].
            user id: @Model.UserId


          3. In the Controller:



          a. Define the below at the beginning:



          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }


          b. Call and return the view with model as below:



          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);


          c. The FULL controller example, could be like:



          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Mvc;

          using WebApplication.Services;

          namespace WebApplication.Controllers
          {
          [Route("render")]
          public class RenderController : Controller
          {
          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }
           
          [Route("invite")]
          public async Task<IActionResult> RenderInviteView()
          {
          ViewData["Message"] = "Your application description page.";
          var viewModel = new InviteViewModel
          {
          UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
          UserName = "Hasan",
          ReferralCode = "55e12b710f78",
          Credits = 10
          };
           
          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);
          }
          }

          public class InviteViewModel {
          public string UserId {get; set;}
          public string UserName {get; set;}
          public string ReferralCode {get; set;}
          public int Credits {get; set;}
          }
          }





          share|improve this answer



















          • 9




            That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
            – philw
            Nov 1 '17 at 17:50






          • 2




            With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
            – martonx
            Feb 25 at 22:56










          • check my answer in the post. I pasted a sample code of cshtml.
            – Chan
            Nov 8 at 5:02













          up vote
          27
          down vote



          accepted







          up vote
          27
          down vote



          accepted






          Thanks to Paris Polyzos and his article.



          I'm re-posting his code here, just in case the original post got removed for any reason.



          Create Service in file viewToString.cs as below code:



          using System;
          using System.IO;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
           
          namespace WebApplication.Services
          {
              public interface IViewRenderService
              {
                  Task<string> RenderToStringAsync(string viewName, object model);
              }
           
              public class ViewRenderService : IViewRenderService
              {
                  private readonly IRazorViewEngine _razorViewEngine;
                  private readonly ITempDataProvider _tempDataProvider;
                  private readonly IServiceProvider _serviceProvider;
           
                  public ViewRenderService(IRazorViewEngine razorViewEngine,
                      ITempDataProvider tempDataProvider,
                      IServiceProvider serviceProvider)
                  {
                      _razorViewEngine = razorViewEngine;
                      _tempDataProvider = tempDataProvider;
                      _serviceProvider = serviceProvider;
                  }
           
                  public async Task<string> RenderToStringAsync(string viewName, object model)
                  {
                      var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
                      var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
           
                      using (var sw = new StringWriter())
                      {
                          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
           
                          if (viewResult.View == null)
                          {
                              throw new ArgumentNullException($"{viewName} does not match any available view");
                          }
           
                          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                          {
                              Model = model
                          };
           
                          var viewContext = new ViewContext(
                              actionContext,
                              viewResult.View,
                              viewDictionary,
                              new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                              sw,
                              new HtmlHelperOptions()
                          );
           
                          await viewResult.View.RenderAsync(viewContext);
                          return sw.ToString();
                      }
                  }
              }
          }




          1. Add the service to the Startup.cs file, as:



            using WebApplication.Services;

            public void ConfigureServices(IServiceCollection services)
            {
            ...
                services.AddScoped<IViewRenderService, ViewRenderService>();
            }



          Add "preserveCompilationContext": true to the buildOptions in the project.json, so the file looks like:



          {
          "version": "1.0.0-*",
          "buildOptions": {
          "debugType": "portable",
          "emitEntryPoint": true,
          "preserveCompilationContext": true
          },
          "dependencies": {
          "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
          "Microsoft.AspNetCore.Mvc": "1.0.1"
          },
          "frameworks": {
          "netcoreapp1.0": {
          "dependencies": {
          "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
          }
          },
          "imports": "dnxcore50"
          }
          }
          }




          1. Define you model, for example:



            public class InviteViewModel {
            public string UserId {get; set;}
            public string UserName {get; set;}
            public string ReferralCode {get; set;}
            public int Credits {get; set;}
            }



          2. Create your Invite.cshtml for example:



            @{
            ViewData["Title"] = "Contact";
            }
            @ViewData["Title"].
            user id: @Model.UserId


          3. In the Controller:



          a. Define the below at the beginning:



          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }


          b. Call and return the view with model as below:



          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);


          c. The FULL controller example, could be like:



          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Mvc;

          using WebApplication.Services;

          namespace WebApplication.Controllers
          {
          [Route("render")]
          public class RenderController : Controller
          {
          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }
           
          [Route("invite")]
          public async Task<IActionResult> RenderInviteView()
          {
          ViewData["Message"] = "Your application description page.";
          var viewModel = new InviteViewModel
          {
          UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
          UserName = "Hasan",
          ReferralCode = "55e12b710f78",
          Credits = 10
          };
           
          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);
          }
          }

          public class InviteViewModel {
          public string UserId {get; set;}
          public string UserName {get; set;}
          public string ReferralCode {get; set;}
          public int Credits {get; set;}
          }
          }





          share|improve this answer














          Thanks to Paris Polyzos and his article.



          I'm re-posting his code here, just in case the original post got removed for any reason.



          Create Service in file viewToString.cs as below code:



          using System;
          using System.IO;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
           
          namespace WebApplication.Services
          {
              public interface IViewRenderService
              {
                  Task<string> RenderToStringAsync(string viewName, object model);
              }
           
              public class ViewRenderService : IViewRenderService
              {
                  private readonly IRazorViewEngine _razorViewEngine;
                  private readonly ITempDataProvider _tempDataProvider;
                  private readonly IServiceProvider _serviceProvider;
           
                  public ViewRenderService(IRazorViewEngine razorViewEngine,
                      ITempDataProvider tempDataProvider,
                      IServiceProvider serviceProvider)
                  {
                      _razorViewEngine = razorViewEngine;
                      _tempDataProvider = tempDataProvider;
                      _serviceProvider = serviceProvider;
                  }
           
                  public async Task<string> RenderToStringAsync(string viewName, object model)
                  {
                      var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
                      var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
           
                      using (var sw = new StringWriter())
                      {
                          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
           
                          if (viewResult.View == null)
                          {
                              throw new ArgumentNullException($"{viewName} does not match any available view");
                          }
           
                          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
                          {
                              Model = model
                          };
           
                          var viewContext = new ViewContext(
                              actionContext,
                              viewResult.View,
                              viewDictionary,
                              new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
                              sw,
                              new HtmlHelperOptions()
                          );
           
                          await viewResult.View.RenderAsync(viewContext);
                          return sw.ToString();
                      }
                  }
              }
          }




          1. Add the service to the Startup.cs file, as:



            using WebApplication.Services;

            public void ConfigureServices(IServiceCollection services)
            {
            ...
                services.AddScoped<IViewRenderService, ViewRenderService>();
            }



          Add "preserveCompilationContext": true to the buildOptions in the project.json, so the file looks like:



          {
          "version": "1.0.0-*",
          "buildOptions": {
          "debugType": "portable",
          "emitEntryPoint": true,
          "preserveCompilationContext": true
          },
          "dependencies": {
          "Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
          "Microsoft.AspNetCore.Mvc": "1.0.1"
          },
          "frameworks": {
          "netcoreapp1.0": {
          "dependencies": {
          "Microsoft.NETCore.App": {
          "type": "platform",
          "version": "1.0.1"
          }
          },
          "imports": "dnxcore50"
          }
          }
          }




          1. Define you model, for example:



            public class InviteViewModel {
            public string UserId {get; set;}
            public string UserName {get; set;}
            public string ReferralCode {get; set;}
            public int Credits {get; set;}
            }



          2. Create your Invite.cshtml for example:



            @{
            ViewData["Title"] = "Contact";
            }
            @ViewData["Title"].
            user id: @Model.UserId


          3. In the Controller:



          a. Define the below at the beginning:



          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }


          b. Call and return the view with model as below:



          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);


          c. The FULL controller example, could be like:



          using System;
          using System.Collections.Generic;
          using System.Linq;
          using System.Threading.Tasks;
          using Microsoft.AspNetCore.Mvc;

          using WebApplication.Services;

          namespace WebApplication.Controllers
          {
          [Route("render")]
          public class RenderController : Controller
          {
          private readonly IViewRenderService _viewRenderService;
           
          public RenderController(IViewRenderService viewRenderService)
          {
          _viewRenderService = viewRenderService;
          }
           
          [Route("invite")]
          public async Task<IActionResult> RenderInviteView()
          {
          ViewData["Message"] = "Your application description page.";
          var viewModel = new InviteViewModel
          {
          UserId = "cdb86aea-e3d6-4fdd-9b7f-55e12b710f78",
          UserName = "Hasan",
          ReferralCode = "55e12b710f78",
          Credits = 10
          };
           
          var result = await _viewRenderService.RenderToStringAsync("Email/Invite", viewModel);
          return Content(result);
          }
          }

          public class InviteViewModel {
          public string UserId {get; set;}
          public string UserName {get; set;}
          public string ReferralCode {get; set;}
          public int Credits {get; set;}
          }
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited May 23 at 9:48









          Glorfindel

          16.4k114869




          16.4k114869










          answered Dec 2 '16 at 13:07









          Hasan A Yousef

          5,10133064




          5,10133064








          • 9




            That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
            – philw
            Nov 1 '17 at 17:50






          • 2




            With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
            – martonx
            Feb 25 at 22:56










          • check my answer in the post. I pasted a sample code of cshtml.
            – Chan
            Nov 8 at 5:02














          • 9




            That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
            – philw
            Nov 1 '17 at 17:50






          • 2




            With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
            – martonx
            Feb 25 at 22:56










          • check my answer in the post. I pasted a sample code of cshtml.
            – Chan
            Nov 8 at 5:02








          9




          9




          That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
          – philw
          Nov 1 '17 at 17:50




          That pretty much works for Core 2.0, with two exceptions: (1) _razorViewEngine.FindView doesn't work on absolute paths, and I at least need those because the standard template apps don't use Views folders which it assumes. Tto use his is documented as "by design" on the Core 2.0 GitHub site, and the solution is to use _razorViewEngine.GetView, which supports absolute paths. (2) that preserveCompilationContext (not in the original article) isn't explained - why do you need it? It's not clear where to put it with COre 2.0, and it seems to work without it.
          – philw
          Nov 1 '17 at 17:50




          2




          2




          With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
          – martonx
          Feb 25 at 22:56




          With this code ViewData["Message"] = "Your application description page."; will be null in the view. Why? Could anybody post a fixed version which contains correct handling of ViewData, not just view model.
          – martonx
          Feb 25 at 22:56












          check my answer in the post. I pasted a sample code of cshtml.
          – Chan
          Nov 8 at 5:02




          check my answer in the post. I pasted a sample code of cshtml.
          – Chan
          Nov 8 at 5:02












          up vote
          21
          down vote













          If like me you have a number of controllers that need this, like in a reporting site, it's not really ideal to repeat this code, and even injecting or calling another service doesn't really seem right.



          So I've made my own version of the above with the following differences:




          • model strong-typing

          • error checking when finding a view

          • ability to render views as partials or pages

          • asynchronus

          • implemented as a controller extension


          • no DI needed



            using Microsoft.AspNetCore.Mvc;
            using Microsoft.AspNetCore.Mvc.Rendering;
            using Microsoft.AspNetCore.Mvc.ViewEngines;
            using Microsoft.AspNetCore.Mvc.ViewFeatures;
            using System.IO;
            using System.Threading.Tasks;

            namespace CC.Web.Helpers
            {
            public static class ControllerExtensions
            {
            public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
            {
            if (string.IsNullOrEmpty(viewName))
            {
            viewName = controller.ControllerContext.ActionDescriptor.ActionName;
            }

            controller.ViewData.Model = model;

            using (var writer = new StringWriter())
            {
            IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
            ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);

            if (viewResult.Success == false)
            {
            return $"A view with the name {viewName} could not be found";
            }

            ViewContext viewContext = new ViewContext(
            controller.ControllerContext,
            viewResult.View,
            controller.ViewData,
            controller.TempData,
            writer,
            new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);

            return writer.GetStringBuilder().ToString();
            }
            }
            }
            }



          Then just implement with:



          viewHtml = await this.RenderViewAsync("Report", model);


          Or this for a PartialView:



          partialViewHtml = await this.RenderViewAsync("Report", model, true);





          share|improve this answer



















          • 4




            This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
            – DGaspar
            May 11 at 10:40










          • Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
            – LentoMan
            May 18 at 14:25










          • @LentoMan could you post an example of the wrapper extension that you mentioned?
            – Mike Moore
            Jun 2 at 22:18










          • Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
            – LentoMan
            Jun 4 at 10:47












          • If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
            – Red
            Jun 4 at 14:08















          up vote
          21
          down vote













          If like me you have a number of controllers that need this, like in a reporting site, it's not really ideal to repeat this code, and even injecting or calling another service doesn't really seem right.



          So I've made my own version of the above with the following differences:




          • model strong-typing

          • error checking when finding a view

          • ability to render views as partials or pages

          • asynchronus

          • implemented as a controller extension


          • no DI needed



            using Microsoft.AspNetCore.Mvc;
            using Microsoft.AspNetCore.Mvc.Rendering;
            using Microsoft.AspNetCore.Mvc.ViewEngines;
            using Microsoft.AspNetCore.Mvc.ViewFeatures;
            using System.IO;
            using System.Threading.Tasks;

            namespace CC.Web.Helpers
            {
            public static class ControllerExtensions
            {
            public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
            {
            if (string.IsNullOrEmpty(viewName))
            {
            viewName = controller.ControllerContext.ActionDescriptor.ActionName;
            }

            controller.ViewData.Model = model;

            using (var writer = new StringWriter())
            {
            IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
            ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);

            if (viewResult.Success == false)
            {
            return $"A view with the name {viewName} could not be found";
            }

            ViewContext viewContext = new ViewContext(
            controller.ControllerContext,
            viewResult.View,
            controller.ViewData,
            controller.TempData,
            writer,
            new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);

            return writer.GetStringBuilder().ToString();
            }
            }
            }
            }



          Then just implement with:



          viewHtml = await this.RenderViewAsync("Report", model);


          Or this for a PartialView:



          partialViewHtml = await this.RenderViewAsync("Report", model, true);





          share|improve this answer



















          • 4




            This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
            – DGaspar
            May 11 at 10:40










          • Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
            – LentoMan
            May 18 at 14:25










          • @LentoMan could you post an example of the wrapper extension that you mentioned?
            – Mike Moore
            Jun 2 at 22:18










          • Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
            – LentoMan
            Jun 4 at 10:47












          • If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
            – Red
            Jun 4 at 14:08













          up vote
          21
          down vote










          up vote
          21
          down vote









          If like me you have a number of controllers that need this, like in a reporting site, it's not really ideal to repeat this code, and even injecting or calling another service doesn't really seem right.



          So I've made my own version of the above with the following differences:




          • model strong-typing

          • error checking when finding a view

          • ability to render views as partials or pages

          • asynchronus

          • implemented as a controller extension


          • no DI needed



            using Microsoft.AspNetCore.Mvc;
            using Microsoft.AspNetCore.Mvc.Rendering;
            using Microsoft.AspNetCore.Mvc.ViewEngines;
            using Microsoft.AspNetCore.Mvc.ViewFeatures;
            using System.IO;
            using System.Threading.Tasks;

            namespace CC.Web.Helpers
            {
            public static class ControllerExtensions
            {
            public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
            {
            if (string.IsNullOrEmpty(viewName))
            {
            viewName = controller.ControllerContext.ActionDescriptor.ActionName;
            }

            controller.ViewData.Model = model;

            using (var writer = new StringWriter())
            {
            IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
            ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);

            if (viewResult.Success == false)
            {
            return $"A view with the name {viewName} could not be found";
            }

            ViewContext viewContext = new ViewContext(
            controller.ControllerContext,
            viewResult.View,
            controller.ViewData,
            controller.TempData,
            writer,
            new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);

            return writer.GetStringBuilder().ToString();
            }
            }
            }
            }



          Then just implement with:



          viewHtml = await this.RenderViewAsync("Report", model);


          Or this for a PartialView:



          partialViewHtml = await this.RenderViewAsync("Report", model, true);





          share|improve this answer














          If like me you have a number of controllers that need this, like in a reporting site, it's not really ideal to repeat this code, and even injecting or calling another service doesn't really seem right.



          So I've made my own version of the above with the following differences:




          • model strong-typing

          • error checking when finding a view

          • ability to render views as partials or pages

          • asynchronus

          • implemented as a controller extension


          • no DI needed



            using Microsoft.AspNetCore.Mvc;
            using Microsoft.AspNetCore.Mvc.Rendering;
            using Microsoft.AspNetCore.Mvc.ViewEngines;
            using Microsoft.AspNetCore.Mvc.ViewFeatures;
            using System.IO;
            using System.Threading.Tasks;

            namespace CC.Web.Helpers
            {
            public static class ControllerExtensions
            {
            public static async Task<string> RenderViewAsync<TModel>(this Controller controller, string viewName, TModel model, bool partial = false)
            {
            if (string.IsNullOrEmpty(viewName))
            {
            viewName = controller.ControllerContext.ActionDescriptor.ActionName;
            }

            controller.ViewData.Model = model;

            using (var writer = new StringWriter())
            {
            IViewEngine viewEngine = controller.HttpContext.RequestServices.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
            ViewEngineResult viewResult = viewEngine.FindView(controller.ControllerContext, viewName, !partial);

            if (viewResult.Success == false)
            {
            return $"A view with the name {viewName} could not be found";
            }

            ViewContext viewContext = new ViewContext(
            controller.ControllerContext,
            viewResult.View,
            controller.ViewData,
            controller.TempData,
            writer,
            new HtmlHelperOptions()
            );

            await viewResult.View.RenderAsync(viewContext);

            return writer.GetStringBuilder().ToString();
            }
            }
            }
            }



          Then just implement with:



          viewHtml = await this.RenderViewAsync("Report", model);


          Or this for a PartialView:



          partialViewHtml = await this.RenderViewAsync("Report", model, true);






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jun 4 at 14:09

























          answered Apr 25 at 13:57









          Red

          665523




          665523








          • 4




            This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
            – DGaspar
            May 11 at 10:40










          • Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
            – LentoMan
            May 18 at 14:25










          • @LentoMan could you post an example of the wrapper extension that you mentioned?
            – Mike Moore
            Jun 2 at 22:18










          • Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
            – LentoMan
            Jun 4 at 10:47












          • If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
            – Red
            Jun 4 at 14:08














          • 4




            This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
            – DGaspar
            May 11 at 10:40










          • Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
            – LentoMan
            May 18 at 14:25










          • @LentoMan could you post an example of the wrapper extension that you mentioned?
            – Mike Moore
            Jun 2 at 22:18










          • Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
            – LentoMan
            Jun 4 at 10:47












          • If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
            – Red
            Jun 4 at 14:08








          4




          4




          This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
          – DGaspar
          May 11 at 10:40




          This one should be way more upthere. It looks way more elegant and it worked like a charm for me.
          – DGaspar
          May 11 at 10:40












          Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
          – LentoMan
          May 18 at 14:25




          Thanks, excellent solution! The only thing I changed was adding an additional wrapped extension method for partial views. I actually ran into a bit of a problem when using the previously injected ViewRenderService since it could access partial views from the view tree of other controllers. Those views did render correctly, but would never automatically recompile during debug, moving them to Shared views solved the issue!
          – LentoMan
          May 18 at 14:25












          @LentoMan could you post an example of the wrapper extension that you mentioned?
          – Mike Moore
          Jun 2 at 22:18




          @LentoMan could you post an example of the wrapper extension that you mentioned?
          – Mike Moore
          Jun 2 at 22:18












          Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
          – LentoMan
          Jun 4 at 10:47






          Just add another method in the same extension class that Red suggested: ` public static async Task<string> RenderPartialViewAsync<TModel>(this Controller controller, string viewName, TModel model) { return await controller.RenderViewAsync(viewName, model, true); }`
          – LentoMan
          Jun 4 at 10:47














          If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
          – Red
          Jun 4 at 14:08




          If that code does what you need, you could just directly call controller.RenderViewAsync(viewName, model, true);. I don't see you're gaining anything, other than making it clearer that it's a Partial, but that could be important in your situation.
          – Red
          Jun 4 at 14:08










          up vote
          1
          down vote













          The link below tackles pretty much the same issue:



          Where are the ControllerContext and ViewEngines properties in MVC 6 Controller?



          In Hasan A Yousef's answer I had to make the same change as in the link above to make it work me:



          using Microsoft.AspNetCore.Hosting;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
          using System;
          using System.IO;
          using System.Threading.Tasks;

          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
          var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter()) {
          //var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false);
          if (viewResult.View == null) {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions());
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }





          share|improve this answer























          • Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
            – ppumkin
            Nov 16 at 14:44






          • 1




            Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
            – Richard Mneyan
            Nov 16 at 15:26















          up vote
          1
          down vote













          The link below tackles pretty much the same issue:



          Where are the ControllerContext and ViewEngines properties in MVC 6 Controller?



          In Hasan A Yousef's answer I had to make the same change as in the link above to make it work me:



          using Microsoft.AspNetCore.Hosting;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
          using System;
          using System.IO;
          using System.Threading.Tasks;

          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
          var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter()) {
          //var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false);
          if (viewResult.View == null) {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions());
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }





          share|improve this answer























          • Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
            – ppumkin
            Nov 16 at 14:44






          • 1




            Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
            – Richard Mneyan
            Nov 16 at 15:26













          up vote
          1
          down vote










          up vote
          1
          down vote









          The link below tackles pretty much the same issue:



          Where are the ControllerContext and ViewEngines properties in MVC 6 Controller?



          In Hasan A Yousef's answer I had to make the same change as in the link above to make it work me:



          using Microsoft.AspNetCore.Hosting;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
          using System;
          using System.IO;
          using System.Threading.Tasks;

          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
          var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter()) {
          //var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false);
          if (viewResult.View == null) {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions());
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }





          share|improve this answer














          The link below tackles pretty much the same issue:



          Where are the ControllerContext and ViewEngines properties in MVC 6 Controller?



          In Hasan A Yousef's answer I had to make the same change as in the link above to make it work me:



          using Microsoft.AspNetCore.Hosting;
          using Microsoft.AspNetCore.Http;
          using Microsoft.AspNetCore.Mvc;
          using Microsoft.AspNetCore.Mvc.Abstractions;
          using Microsoft.AspNetCore.Mvc.ModelBinding;
          using Microsoft.AspNetCore.Mvc.Razor;
          using Microsoft.AspNetCore.Mvc.Rendering;
          using Microsoft.AspNetCore.Mvc.ViewFeatures;
          using Microsoft.AspNetCore.Routing;
          using System;
          using System.IO;
          using System.Threading.Tasks;

          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
          var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter()) {
          //var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false);
          if (viewResult.View == null) {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary()) {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(actionContext.HttpContext, _tempDataProvider), sw, new HtmlHelperOptions());
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }






          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited Jun 28 '17 at 14:27

























          answered Jun 28 '17 at 14:17









          Richard Mneyan

          436168




          436168












          • Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
            – ppumkin
            Nov 16 at 14:44






          • 1




            Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
            – Richard Mneyan
            Nov 16 at 15:26


















          • Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
            – ppumkin
            Nov 16 at 14:44






          • 1




            Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
            – Richard Mneyan
            Nov 16 at 15:26
















          Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
          – ppumkin
          Nov 16 at 14:44




          Thanks- I was looking for something like this to merge a model in HTML using Razor. Not sure why MS wont just make a simpler way of this doing. Although.. its much easier than in MVC 1. Great solution and thanks for sharing the GetView change!
          – ppumkin
          Nov 16 at 14:44




          1




          1




          Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
          – Richard Mneyan
          Nov 16 at 15:26




          Your welcome @ppumkin, back then I spent long time figuring this out, and I needed this badly.
          – Richard Mneyan
          Nov 16 at 15:26










          up vote
          1
          down vote













          The answers above are fine, but need to tweaking to get any tag helpers to work (we need to use the actually http context). Also you will need to explicitly set
          the layout in the view to get a layout rendered.



          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;
          private readonly HttpContext _http;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter())
          {
          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder
          if (viewResult.View == null)
          {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
          {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(_http, _tempDataProvider), sw, new HtmlHelperOptions());
          viewContext.RouteData = _http.GetRouteData();
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }
          }





          share|improve this answer

















          • 1




            Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
            – Dave Glassborow
            Jan 12 at 11:55

















          up vote
          1
          down vote













          The answers above are fine, but need to tweaking to get any tag helpers to work (we need to use the actually http context). Also you will need to explicitly set
          the layout in the view to get a layout rendered.



          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;
          private readonly HttpContext _http;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter())
          {
          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder
          if (viewResult.View == null)
          {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
          {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(_http, _tempDataProvider), sw, new HtmlHelperOptions());
          viewContext.RouteData = _http.GetRouteData();
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }
          }





          share|improve this answer

















          • 1




            Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
            – Dave Glassborow
            Jan 12 at 11:55















          up vote
          1
          down vote










          up vote
          1
          down vote









          The answers above are fine, but need to tweaking to get any tag helpers to work (we need to use the actually http context). Also you will need to explicitly set
          the layout in the view to get a layout rendered.



          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;
          private readonly HttpContext _http;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter())
          {
          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder
          if (viewResult.View == null)
          {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
          {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(_http, _tempDataProvider), sw, new HtmlHelperOptions());
          viewContext.RouteData = _http.GetRouteData();
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }
          }





          share|improve this answer












          The answers above are fine, but need to tweaking to get any tag helpers to work (we need to use the actually http context). Also you will need to explicitly set
          the layout in the view to get a layout rendered.



          public class ViewRenderService : IViewRenderService
          {
          private readonly IRazorViewEngine _razorViewEngine;
          private readonly ITempDataProvider _tempDataProvider;
          private readonly IServiceProvider _serviceProvider;
          private readonly IHostingEnvironment _env;
          private readonly HttpContext _http;

          public ViewRenderService(IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider, IHostingEnvironment env, IHttpContextAccessor ctx)
          {
          _razorViewEngine = razorViewEngine; _tempDataProvider = tempDataProvider; _serviceProvider = serviceProvider; _env = env; _http = ctx.HttpContext;
          }

          public async Task<string> RenderToStringAsync(string viewName, object model)
          {
          var actionContext = new ActionContext(_http, new RouteData(), new ActionDescriptor());

          using (var sw = new StringWriter())
          {
          var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
          //var viewResult = _razorViewEngine.GetView(_env.WebRootPath, viewName, false); // For views outside the usual Views folder
          if (viewResult.View == null)
          {
          throw new ArgumentNullException($"{viewName} does not match any available view");
          }
          var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
          {
          Model = model
          };
          var viewContext = new ViewContext(actionContext, viewResult.View, viewDictionary, new TempDataDictionary(_http, _tempDataProvider), sw, new HtmlHelperOptions());
          viewContext.RouteData = _http.GetRouteData();
          await viewResult.View.RenderAsync(viewContext);
          return sw.ToString();
          }
          }
          }






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jan 4 at 15:37









          Dave Glassborow

          1,4141619




          1,4141619








          • 1




            Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
            – Dave Glassborow
            Jan 12 at 11:55
















          • 1




            Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
            – Dave Glassborow
            Jan 12 at 11:55










          1




          1




          Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
          – Dave Glassborow
          Jan 12 at 11:55






          Note: on azure, I needed to add the following to the Startup services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); Weirdly worked fine locally without this ...
          – Dave Glassborow
          Jan 12 at 11:55












          up vote
          1
          down vote













          I tried the solution which answered by @Hasan A Yousef in Dotnet Core 2.1, but the csthml do not work well to me. It always throws a NullReferenceException, see screenshot.
          enter image description here



          To solve it, I assign the Html.ViewData.Model to a new object. Here is my code.



          @page
          @model InviteViewModel
          @{
          var inviteViewModel = Html.ViewData.Model;
          }

          <p>
          <strong>User Id:</strong> <code>@inviteViewModel.UserId </code>
          </p>





          share|improve this answer





















          • I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
            – gbade_
            Nov 27 at 11:33

















          up vote
          1
          down vote













          I tried the solution which answered by @Hasan A Yousef in Dotnet Core 2.1, but the csthml do not work well to me. It always throws a NullReferenceException, see screenshot.
          enter image description here



          To solve it, I assign the Html.ViewData.Model to a new object. Here is my code.



          @page
          @model InviteViewModel
          @{
          var inviteViewModel = Html.ViewData.Model;
          }

          <p>
          <strong>User Id:</strong> <code>@inviteViewModel.UserId </code>
          </p>





          share|improve this answer





















          • I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
            – gbade_
            Nov 27 at 11:33















          up vote
          1
          down vote










          up vote
          1
          down vote









          I tried the solution which answered by @Hasan A Yousef in Dotnet Core 2.1, but the csthml do not work well to me. It always throws a NullReferenceException, see screenshot.
          enter image description here



          To solve it, I assign the Html.ViewData.Model to a new object. Here is my code.



          @page
          @model InviteViewModel
          @{
          var inviteViewModel = Html.ViewData.Model;
          }

          <p>
          <strong>User Id:</strong> <code>@inviteViewModel.UserId </code>
          </p>





          share|improve this answer












          I tried the solution which answered by @Hasan A Yousef in Dotnet Core 2.1, but the csthml do not work well to me. It always throws a NullReferenceException, see screenshot.
          enter image description here



          To solve it, I assign the Html.ViewData.Model to a new object. Here is my code.



          @page
          @model InviteViewModel
          @{
          var inviteViewModel = Html.ViewData.Model;
          }

          <p>
          <strong>User Id:</strong> <code>@inviteViewModel.UserId </code>
          </p>






          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 8 at 4:59









          Chan

          686621




          686621












          • I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
            – gbade_
            Nov 27 at 11:33




















          • I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
            – gbade_
            Nov 27 at 11:33


















          I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
          – gbade_
          Nov 27 at 11:33






          I tried your method and now I'm getting this - Executed action Controllers.PortfolioController.PrintStatement in [ERR] An unhandled exception has occurred while executing the request System.NullReferenceException: Object reference not set to an instance of an object. at AspNetCore._Views_Portfolio_PrintStatement_cshtml. in PrintStatement.cshtml:line 248. --------------Prior to that, I was getting the nullreference error at line 0 in the cshtml file.
          – gbade_
          Nov 27 at 11:33












          up vote
          -1
          down vote













          Microsoft has an excellent article on Controller Testing at https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing



          Once you have returned a ViewResult then you can get the string content by



          var strResult = ViewResult.Content






          share|improve this answer

















          • 1




            I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
            – Hasan A Yousef
            Dec 2 '16 at 10:48















          up vote
          -1
          down vote













          Microsoft has an excellent article on Controller Testing at https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing



          Once you have returned a ViewResult then you can get the string content by



          var strResult = ViewResult.Content






          share|improve this answer

















          • 1




            I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
            – Hasan A Yousef
            Dec 2 '16 at 10:48













          up vote
          -1
          down vote










          up vote
          -1
          down vote









          Microsoft has an excellent article on Controller Testing at https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing



          Once you have returned a ViewResult then you can get the string content by



          var strResult = ViewResult.Content






          share|improve this answer












          Microsoft has an excellent article on Controller Testing at https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/testing



          Once you have returned a ViewResult then you can get the string content by



          var strResult = ViewResult.Content







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 1 '16 at 20:04









          John Davidson

          416311




          416311








          • 1




            I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
            – Hasan A Yousef
            Dec 2 '16 at 10:48














          • 1




            I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
            – Hasan A Yousef
            Dec 2 '16 at 10:48








          1




          1




          I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
          – Hasan A Yousef
          Dec 2 '16 at 10:48




          I got error CS0117: 'ViewResult' doesn't contain a definition for 'Content'
          – Hasan A Yousef
          Dec 2 '16 at 10:48


















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f40912375%2freturn-view-as-string-in-net-core%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          這個網誌中的熱門文章

          Academy of Television Arts & Sciences

          L'Équipe

          1995 France bombings