0

I want to create a common message box method that can be called throughout my ASP.NET 5 application

The code should be something like this:

public class WebHelper
{
    public static IActionResult MessageBox(string message)
    {
        return PartialView("~/Views/Shared/_MessageBox.cshtml", message);
    }
}

And then in my controller call:

return WebHelper.MessageBox("Hallo world");

instead of what I am currently doing of :

 return PartialView("~/Views/Shared/_MessageBox.cshtml", "Hallo world");

However PartialView is bound to the controller so it seems I cannot use it outside the controller.

I tried to use Answers 1 Answers 2 which are solutions for ASP.NET 4 but they don't work in ASP.NET 5 e.g.

 public string RenderPartialViewToString(string viewName, object model)
    {
        this.ViewData.Model = model;
        try
        {
            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(this.ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(this.ControllerContext, viewResult.View, this.ViewData, this.TempData, sw);
                viewResult.View.Render(viewContext, sw);

                return sw.GetStringBuilder().ToString();
            }
        }
        catch (System.Exception ex)
        {
            return ex.ToString();
        }
    }

as I can't find the ViewEngines.Engine in the ASP.NET 5 namespaces.

Question: What is the simplest way to solve my problem in `ASP.NET 5? Providing the method and calling method code

1

2 Answers 2

3

Here's the helper class that renders the view: (as you can see, the ViewEngines.Engine part that you couldn't find anymore is now injected as IRazorViewEngine)

using System;
using System.IO;
using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Razor;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing;

namespace WebApp.Demo.Helpers
{
    public class RazorViewToStringRenderer
    {
        private IRazorViewEngine _viewEngine;
        private ITempDataProvider _tempDataProvider;
        private IServiceProvider _serviceProvider;

        public RazorViewToStringRenderer(
            IRazorViewEngine viewEngine,
            ITempDataProvider tempDataProvider,
            IServiceProvider serviceProvider)
        {
            _viewEngine = viewEngine;
            _tempDataProvider = tempDataProvider;
            _serviceProvider = serviceProvider;
        }

        public string RenderViewToString<TModel>(string name, TModel model)
        {
            var actionContext = GetActionContext();

            var viewEngineResult = _viewEngine.FindView(actionContext, name);

            if (!viewEngineResult.Success)
            {
                throw new InvalidOperationException(string.Format("Couldn't find view '{0}'", name));
            }

            var httpContextAccessor = new HttpContextAccessor();

            httpContextAccessor.HttpContext = actionContext.HttpContext;

            var view = viewEngineResult.View;

            using (var output = new StringWriter())
            {
                var viewContext = new ViewContext(
                    actionContext,
                    view,
                    new ViewDataDictionary<TModel>(
                        metadataProvider: new EmptyModelMetadataProvider(),
                        modelState: new ModelStateDictionary())
                    {
                        Model = model
                    },
                    new TempDataDictionary(
                        httpContextAccessor,
                        _tempDataProvider),
                    output,
                    new HtmlHelperOptions());

                view.RenderAsync(viewContext).GetAwaiter().GetResult();

                return output.ToString();
            }
        }

        private ActionContext GetActionContext()
        {
            var httpContext = new DefaultHttpContext();
            httpContext.RequestServices = _serviceProvider;
            return new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
        }
    }
}

In Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
       // Add MVC services to the services container.
       services.AddMvc();
       // Add the helper rendering class as singleton
       services.AddSingleton<RazorViewToStringRenderer>();
}

Get injected helper class in controller for example:

public HomeController(RazorViewToStringRenderer renderer)
{
       string message = "Hallo world";

       var partialView = renderer.RenderViewToString("~/Views/Shared/_MessageBox.cshtml", message);
}

Code from here, with a few tweaks to work with the old packages like "Microsoft.AspNet.Mvc": "6.0.0-rc1-final": https://github.com/aspnet/Entropy/tree/dev/samples/Mvc.RenderViewToString

If you're using the new "Microsoft.AspNetCore.Mvc": "1.0.0-*", just get the code from there

Sign up to request clarification or add additional context in comments.

Comments

1

A bit late to the party, but I came across the same issue and the links in the previous answers and comments now seem to be broken.

A solution that I've used to get around this is to create an abstract class which inherits from 'Controller'.

    public abstract class MyControllerBase : Controller
    {
        protected IActionResult MessageBox(string message)
        {
            return PartialView("~/Views/Shared/_MessageBox.cshtml", message);
        }
    {

Just make sure that your controllers inherit from this base class and then in your controller you just need:

return MessageBox("Hello world");

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.