c# - 在 ASP.NET Core 2.x 中手动创建 HttpContext

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

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

 _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 代码深处遇到了很多错误和空异常,这非常难以调试。我试过像 RazorLight 这样的库这不符合我的需要,因为它没有正确支持 @inject 指令。我认为我最好的解决方案是尝试模拟一个假的 HttpContext/ControllerContext 以传递给 native ViewEngine。然而,当我创建一个新的 DefaultHttpContext 时,我在 here 附近得到了一个 NullReferenceException。 ,但很难跟踪代码并找到它的来源。

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

最佳答案

您可以通过创建 DefaultHttpContext 来模拟它,但是 MVC 需要一些范围内的服务,这些服务不存在于根 DI 范围内,因此您必须为您的服务创建一个 ServiceProvider 范围渲染。

这是一个呈现 View 的示例 IHostedService(我确实使用 MVC 在 WebApplication 模板中运行它):

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/

关于c# - 在 ASP.NET Core 2.x 中手动创建 HttpContext,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53605268/

相关文章:

c# - 添加 View 模型时命名空间错误

c# - 如何阻止 ASP.NET Core 发布本地化的 Microsoft.CodeAnalysis.*.resources.dll 文件?

c# - 非托管代码中的 ASP.NET Core 1.1 和 EF 6 异常

asp.net-mvc - F# 支持最新的 asp.net 5 和 MVC6

c# - Entity Framework 核心 : Challenge Modeling Product Variants Database Design with Many to Many

asp.net-mvc - MVC 6 中 @Scripts.Render 的替代品是什么

c# - 付款错误 : PayPal error: Invalid request. 查看详情。 (VALIDATION_ERROR) Paypal

c# - 抛出异常时 try catch 性能问题

时间:2019-05-17 标签:c# "as"vs "()"conversion

typescript - VSO ASP.NET5 CI 构建期间出错 - "Your project uses a different version of the TypeScript compiler"但我没有使用 TypeScript