Создание HttpContext вручную в ASP.NET Core 2.x - PullRequest
0 голосов
/ 04 декабря 2018

Я пытаюсь отобразить представление Razor в строке из размещенной службы.Используя IRazorViewEngine, я могу визуализировать представление в строку, используя что-то вроде следующего:

 _viewEngine.FindView(actionContext, viewName, false);
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()
                );
                viewContext.RouteData = httpContext.GetRouteData();   //set route data here

                await viewResult.View.RenderAsync(viewContext);

Однако это разваливается, когда оно не вызывается из Controller из-за отсутствия HttpContext.Я пытался создать HttpContext вручную, но я получаю много ошибок и нулевых исключений глубоко в коде Microsoft Mvc, который чрезвычайно сложно отладить.Я пробовал библиотеки типа RazorLight , которые не соответствуют моим потребностям, потому что они не поддерживают должным образом директиву @inject.Я думаю, что мое лучшее решение состоит в том, чтобы попробовать макет поддельного HttpContext / ControllerContext, чтобы передать его родному ViewEngine.Однако, когда я создаю новый DefaultHttpContext, я получаю исключение NullReferenceException около здесь , но очень трудно отследить код и найти, откуда он поступает.

Есть ли способсоздать новый HttpContext?

Ответы [ 2 ]

0 голосов
/ 04 декабря 2018

Вы можете смоделировать его, создав DefaultHttpContext, однако для MVC требуются некоторые сервисы с областями действия, которых нет в корневой области DI, поэтому вам необходимо создать область ServiceProvider для рендеринга.

ВотПример IHostedService, который отображает представление (я запускал его в шаблоне WebApplication с MVC):

public class ViewRenderService : IHostedService
{
    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)
    {
        using (var requestServices = _serviceProvider.CreateScope())
        {
            var httpContext = new DefaultHttpContext { RequestServices = requestServices.ServiceProvider };
            var routeData = new RouteData();
            routeData.Values.Add("controller", "Home");
            var actionContext = new ActionContext(httpContext, 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();
            }
        }
    }

    public async Task StartAsync(CancellationToken cancellationToken)
    {
        var html = await RenderToStringAsync("About", null);
        return;
    }

    public async Task StopAsync(CancellationToken cancellationToken)
    {
    }
}

Примечание. Этот пример основан на сообщении в блоге, найденном здесь, но измененном для работы в IHostedService.https://ppolyzos.com/2016/09/09/asp-net-core-render-view-to-string/

0 голосов
/ 04 декабря 2018

Попробуйте:

public class YourClass 
{
   private readonly IHttpContextAccessor _httpContextAccessor;
   public YourClass(IHttpContextAccessor httpContextAccessor)
   {
      _httpContextAccessor = httpContextAccessor;
   }

   public void YourMethod()
   {
      // access HttpContext with __httpContextAccessor.HttpContext
   }
}

А затем зарегистрируйте IHttpContextAccessor в классе запуска следующим образом:

public void ConfigureServices(IServiceCollection services)
{
    services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();

    // Or you can also register as follows

    services.AddHttpContextAccessor();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...