在ASP.NET Core 2.x中手动创建HttpContext [英] Manually creating an HttpContext in ASP.NET Core 2.x

查看:68
本文介绍了在ASP.NET Core 2.x中手动创建HttpContext的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将Razor视图呈现为来自托管服务的字符串.通过使用 IRazorViewEngine ,我可以使用以下内容将视图呈现为字符串:

I'm trying to render a Razor view to a string from a Hosted Service. By using the IRazorViewEngine I am able to render a view to a string using something like the following:

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

但是,由于缺少 HttpContext 而未从 Controller 调用它时,此方法却分崩离析.我尝试过手动构建HttpContext,但是在Microsoft Mvc代码的深处却遇到了很多错误和null异常,这很难调试.我已经尝试过像 RazorLight 这样的库,因为它不能正确支持 @inject 指令.我认为我最好的解决方案是尝试模拟一个伪造的HttpContext/ControllerContext传递给本地ViewEngine.但是,当我创建一个新的 DefaultHttpContext 时,我在

However this falls apart when it is not called from a Controller due to missing HttpContext. I've tried building an HttpContext manually, but I get many errors and null exceptions deep in the Microsoft Mvc code which is extremely hard to debug. I've tried libraries like RazorLight which don't suit my needs because it doesn't properly support the @inject directive. I think my best solution is to try and mock up a fake HttpContext/ControllerContext to pass to the native ViewEngine. However, when I create a new DefaultHttpContext, I get a NullReferenceException around here, but it's very hard to trace the code and find where it is coming from.

有什么方法可以创建一个新的HttpContext?

Is there any way to create a new HttpContext?

推荐答案

您可以通过创建 DefaultHttpContext 来对其进行模拟,但是MVC要求根DI范围中不存在某些范围内的服务,因此您可以为呈现创建 ServiceProvider 范围.

You can mock it by creating a DefaultHttpContext, however MVC requires some scoped services not present in the root DI scope, so you have to create a ServiceProvider scope for your rendering.

这是呈现视图的示例 IHostedService (我确实在MVC的WebApplication模板中运行了该视图):

Here is a sample IHostedService that renders a view (I did run it in the WebApplication template with 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/

Note: This sample is based on a blog post found here, but modified to work in IHostedService. https://ppolyzos.com/2016/09/09/asp-net-core-render-view-to-string/

这篇关于在ASP.NET Core 2.x中手动创建HttpContext的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆