MVC 6 Controller中的ControllerContext和ViewEngines属性在哪里?

时间:2015-08-09 15:06:31

标签: c# asp.net-mvc asp.net-core asp.net-core-mvc

我创建了一个新的MVC6项目并构建了一个新站点。目标是获取视图的渲染结果。我找到了以下代码,但由于找不到ControllerContextViewEngines,我无法使其生效。

以下是我要重写的代码:

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.RouteData.GetRequiredString("action");

    ViewData.Model = model;

    using (StringWriter sw = new StringWriter())
    {
        ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
        ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
        viewResult.View.Render(viewContext, sw);

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

6 个答案:

答案 0 :(得分:20)

  

更新:我正在更新此功能以使用.Net Core 2.x,因为自2015年以来API已发生变化!

首先,我们可以利用ASP.Net MVC Core附带的内置依赖注入,它将为我们提供手动渲染视图所需的ICompositeViewEngine对象。例如,控制器看起来像这样:

public class MyController : Controller
{
    private ICompositeViewEngine _viewEngine;

    public MyController(ICompositeViewEngine viewEngine)
    {
        _viewEngine = viewEngine;
    }

    //Rest of the controller code here
}

接下来,我们实际需要呈现视图的代码。请注意,现在是async方法,因为我们将在内部进行异步调用:

private async Task<string> RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.ActionDescriptor.ActionName;

    ViewData.Model = model;

    using (var writer = new StringWriter())
    {
        ViewEngineResult viewResult = 
            _viewEngine.FindView(ControllerContext, viewName, false);

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

        await viewResult.View.RenderAsync(viewContext);

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

要调用该方法,就像这样简单:

public async Task<IActionResult> Index()
{
    var model = new TestModel
    {
        SomeProperty = "whatever"
    }

    var renderedView = await RenderPartialViewToString("NameOfView", model);

    //Do what you want with the renderedView here

    return View();
}

答案 1 :(得分:14)

已发布的dotnet核心1.0已更改,上述代码的此版本适用于1.0 RTM。

protected string RenderPartialViewToString(string viewName, object model)
{
    if (string.IsNullOrEmpty(viewName))
        viewName = ControllerContext.ActionDescriptor.DisplayName;

    ViewData.Model = model;

    using (StringWriter sw = new StringWriter())
    {
        var engine = _serviceProvider.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine; // Resolver.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
        ViewEngineResult viewResult = engine.FindView(ControllerContext, viewName, false);

        ViewContext viewContext = new ViewContext(
            ControllerContext,
            viewResult.View,
            ViewData,
            TempData,
            sw,
            new HtmlHelperOptions() //Added this parameter in
        );

        //Everything is async now!
        var t = viewResult.View.RenderAsync(viewContext);
        t.Wait();

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

此代码需要使用这些用法:

using System.IO;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;

我还必须在控制器构造函数中添加DI接口:

IServiceProvider serviceProvider

我的帐户构造函数现在看起来像这样:

public AccountController(
    UserManager<ApplicationUser> userManager,
    SignInManager<ApplicationUser> signInManager,
    IEmailSender emailSender,
    ISmsSender smsSender,
    ILoggerFactory loggerFactory,
    IServiceProvider serviceProvider)
{
    _userManager = userManager;
    _signInManager = signInManager;
    _emailSender = emailSender;
    _smsSender = smsSender;
    _logger = loggerFactory.CreateLogger<AccountController>();
    _serviceProvider = serviceProvider;
}

答案 2 :(得分:1)

Martin Tomes提供的解决方案为我工作,但我必须更换:

=SUMPRODUCT(B:B*(MONTH(A:A)=4))

ViewEngineResult viewResult = engine.FindView(ControllerContext, viewName, false);

另外在控制器构造函数中必须添加

ViewEngineResult viewResult = engine.GetView(_env.WebRootPath, viewName, false);

答案 3 :(得分:1)

Martin Tomes的解决方案效果很好。我的更改:删除了serviceProvider并通过DI在构造函数中获取ICompositeViewEngine。 构造函数看起来像:

$stmt = $con->prepare("UPDATE `personal_detail` SET `Name` = ?, `CNIC` = ?, `Date` = ?, `Ocassion` = ?, `Address` = ?, `Phone_No` = ?, `Bride_Mobile` = ?, `Groom_Mobile` = ?, `Family_Mobile` = ?, `EMail` = ?, `Referring` = ?, `Share` = ?, `Permission` = ? WHERE `CNIC` = ?");

并放

private readonly ICompositeViewEngine _viewEngine;

        public AccountController(

                UserManager<ApplicationUser> userManager,
                SignInManager<ApplicationUser> signInManager,
                IEmailSender emailSender,
                ISmsSender smsSender,
                ILoggerFactory loggerFactory,
                ICompositeViewEngine viewEngine)
            {
                _userManager = userManager;
                _signInManager = signInManager;
                _emailSender = emailSender;
                _smsSender = smsSender;
                _logger = loggerFactory.CreateLogger<AccountController>();
                _viewEngine = viewEngine;;
            }

而不是

ViewEngineResult viewResult = _viewEngine.FindView(ControllerContext, viewName, false);

答案 4 :(得分:0)

DavidG 提供的解决方案运行良好,但我将其更改为独立服务。

namespace WebApplication.Services
{
    public interface IViewRenderService
    {
        Task<string> RenderPartialViewToString(Controller Controller, string viewName, object model);
    }

    public class ViewRenderService: IViewRenderService
    {
        private readonly ICompositeViewEngine _viewEngine;

        public ViewRenderService(ICompositeViewEngine viewEngine)
        {
            _viewEngine = viewEngine;
        }
       public async Task<string> RenderPartialViewToString(Controller Controller, string viewName, object model)
            {
                if (string.IsNullOrEmpty(viewName))
                    viewName = Controller.ControllerContext.ActionDescriptor.ActionName;

                Controller.ViewData.Model = model;

                using (var writer = new StringWriter())
                {
                    ViewEngineResult viewResult =
                        _viewEngine.FindView(Controller.ControllerContext, viewName, false);

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

                    await viewResult.View.RenderAsync(viewContext);

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

为启动添加服务:

services.AddScoped<IViewRenderService, ViewRenderService>();

现在像这样使用依赖注入:

public class MyController : Controller
{
private readonly IViewRenderService _viewRender;

public MyController(IViewRenderService viewRender)
{
    _viewRender = viewRender;
}

//Rest of the controller code here
}

现在您可以像这样在操作方法中使用它:

var renderedView = await_viewRender.RenderPartialViewToString(this,"nameofview", model);

答案 5 :(得分:-1)

我遵循了您的建议,并且这样做了,在我的基本控制器中添加了方法,并从当前控制器传递了视图引擎,因此无论我在何处使用它都很容易:

Image from visual studio
Visual Studio (单击图片可放大)