Где находятся свойства ControllerContext и ViewEngines в контроллере MVC 6?
Я создал новый проект MVC6 и создаю новый сайт. Цель состоит в том, чтобы получить визуализированный результат просмотра. Я нашел следующий код, но я не могу заставить его работать, потому что я не могу найти ControllerContext
и ViewEngines
.
Вот код, который я хочу переписать:
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();
}
}
Ответы
Ответ 1
Обновление. Я обновляю это для работы с .Net Core 2.x, поскольку API изменились с 2015 года.
Прежде всего, мы можем использовать встроенную инъекцию зависимостей, которая поставляется с 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();
}
Ответ 2
Выпущен выпущенный ядро 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;
}
Ответ 3
Решение, предоставленное Мартином Томесом, работало для меня, но мне пришлось заменить:
ViewEngineResult viewResult = engine.FindView(ControllerContext, viewName, false);
с
ViewEngineResult viewResult = engine.GetView(_env.WebRootPath, viewName, false);
Также в конструкторе контроллера нужно было добавить
private IHostingEnvironment _env;
public AccountController(IHostingEnvironment env)
{
_env = env;
}
Ответ 4
Решение Мартина Томаса хорошо работает. Мои изменения: удалить serviceProvider и получить ICompositeViewEngine в конструкторе через DI.
Конструктор выглядит так:
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);