web-dev-qa-db-ja.com

MVC 6コントローラーのControllerContextプロパティとViewEnginesプロパティはどこにありますか?

新しい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();
    }
}
19
Martijn

pdate:APIが2015年から変更されているため、.Net Core 2.xで動作するように更新しています!

まず最初に、ASP.Net MVCコアに付属する組み込みの依存関係注入を利用して、ビューを手動でレンダリングするために必要な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();
}
25
DavidG

リリースされた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;
}
14
Martin Tomes

Martin Tomesによって提供されたソリューションは私にとってはうまくいきましたが、私は置き換える必要がありました:

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

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

また、コントローラのコンストラクタで追加する必要がありました

private IHostingEnvironment _env;

public AccountController(IHostingEnvironment env)
{
    _env = env;
}
2
Richard Mneyan

Martin Tomesによる解決策はうまく機能します。私の変更:serviceProviderを削除し、DIを介してコンストラクターでICompositeViewEngineを取得しました。コンストラクタは次のようになります。

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);

の代わりに

var engine = _serviceProvider.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine; // Resolver.GetService(typeof(ICompositeViewEngine)) as ICompositeViewEngine;
ViewEngineResult viewResult = engine.FindView(ControllerContext, viewName, false);
1
Proggear