使用IViewComponentHelper将ViewComponent转换为HTML字符串时出现线程问题

问题描述

我正在尝试以多线程方式使用IViewComponentHelper。但这是抛出:((请参阅文章底部的完整异常)

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Items()

我不知道为什么。

这是我的设置:(为简便起见,已简化)

控制器:

public async Task<IActionResult> Get()
{
    var pdfStream = await _pdfService.GenerateAsync();

    return File(pdfStream,"application/pdf");
}

PdfService:

public class PdfService
{
    private readonly PdfSDK _pdfSDK;

    public constructor(PdfSDK pdfSDK)
    {
        _pdfSDK = pdfSDK;
    }

    public async Task<Stream> GenerateAsync()
    {
        List<Task<PdfDocument>> tasks = await _context.Foos.Select(x => DoWorkAsync(x));

        var pdfs = await Task.WhenAll(tasks);
        var mergedPdf = _pdfSDK.MergePdfs(pdfs);

        return mergedPdf.Stream;
    }

    private async Task<PdfDocument> DoWorkAsync(Foo foo)
    {
        var html = await _renderViewComponentService.RenderViewComponentAsstringAsync<MyViewComponent>(foo);
        var document = await _pdfSDK.HtmlTodocumentAsync(html);

        return document;
    }
}

PdfSDK:

public class PdfSDK
{
    public async Task<PdfDocument> HtmlTodocumentAsync(string html)
    {
        using var pdfEngine = new PdfEngine();
        var pdf = await pdfEngine.HtmlAsPdfAsync(html);

        return pdf;
    }

    public PdfDocument MergePdfs(params PdfDocument[] pdfs)
    {
        var pdf = PdfDocument.Merge(pdfs);

        return pdf;
    }
}

MyViewComponent:

public class MyViewComponent : ViewComponent
{
    public IViewComponentResult Invoke(Foo args)
    {
        return View(args);
    }
}

Default.cshtml

@model Foo

<h1>Hello from @Foo.Id<h1>

RenderViewComponentService:

public class RenderViewComponentService
{
    private readonly IServiceProvider _serviceProvider;
    private readonly ITempDataProvider _tempDataProvider;
    private readonly IViewComponentHelper _viewComponentHelper;

    public RenderViewComponentService(
        IServiceProvider serviceProvider,ITempDataProvider tempDataProvider,IViewComponentHelper viewComponentHelper
    )
    {
        _serviceProvider = serviceProvider;
        _tempDataProvider = tempDataProvider;
        _viewComponentHelper = viewComponentHelper;
    }

    public async Task<string> RenderViewComponentAsstringAsync<TViewComponent>(object args)
        where TViewComponent : ViewComponent
    {
        var viewContext = GetFakeViewContext();
        (_viewComponentHelper as IViewContextAware).Contextualize(viewContext);

        // this appears to call InvokeAsync in TViewComponent,but it'll also call Invoke (synchronously) if it's implemented
        // see https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components?view=aspnetcore-3.1#perform-synchronous-work
        var htmlContent = await _viewComponentHelper.InvokeAsync<TViewComponent>(args); // exception is thrown here!
        using var stringWriter = new StringWriter();
        htmlContent.Writeto(stringWriter,HtmlEncoder.Default);
        var html = stringWriter.ToString();

        return html;
    }

    private ViewContext GetFakeViewContext(ActionContext actionContext = null,TextWriter writer = null)
    {
        actionContext ??= GetFakeActionContext();
        var viewData = new ViewDataDictionary(new EmptyModelMetadataProvider(),new ModelStateDictionary());
        var tempData = new TempDataDictionary(actionContext.HttpContext,_tempDataProvider);

        var viewContext = new ViewContext(
            actionContext,NullView.Instance,viewData,tempData,writer ?? TextWriter.Null,new HtmlHelperOptions());

        return viewContext;
    }

    private ActionContext GetFakeActionContext()
    {
        var httpContext = new DefaultHttpContext
        {
            RequestServices = _serviceProvider,};

        var routeData = new RouteData();
        var actionDescriptor = new ActionDescriptor();

        return new ActionContext(httpContext,routeData,actionDescriptor);
    }

    private class NullView : IView
    {
        public static readonly NullView Instance = new NullView();
        public string Path => string.Empty;
        public Task RenderAsync(ViewContext context)
        {
            if (context == null) { throw new ArgumentNullException(nameof(context)); }
            return Task.CompletedTask;
        }
    }
}

例外:

fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
      An unhandled exception has occurred while executing the request.
System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.AspNetCore.Http.DefaultHttpContext.get_Items()
   at Microsoft.AspNetCore.Mvc.Routing.UrlHelperFactory.GetUrlHelper(ActionContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorPageActivator.<>c__displayClass4_0.<.ctor>b__0(ViewContext context)
   at Microsoft.Extensions.Internal.PropertyActivator`1.Activate(Object instance,TContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorPagePropertyActivator.Activate(Object page,ViewContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorPageActivator.Activate(IRazorPage page,ViewContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageCoreAsync(IRazorPage page,ViewContext context)
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderPageAsync(IRazorPage page,ViewContext context,Boolean invokeViewStarts)        
   at Microsoft.AspNetCore.Mvc.Razor.RazorView.RenderAsync(ViewContext context)
   at Microsoft.AspNetCore.Mvc.ViewComponents.ViewViewComponentResult.ExecuteAsync(ViewComponentContext context)
   at Microsoft.AspNetCore.Mvc.ViewComponents.defaultviewComponentInvoker.InvokeAsync(ViewComponentContext context)
   at Microsoft.AspNetCore.Mvc.ViewComponents.defaultviewComponentHelper.InvokeCoreAsync(ViewComponentDescriptor descriptor,Object arguments)
   at MyProject.Services.RenderViewComponentService.RenderViewComponentToStringAsync[TViewComponent](Object args) in MyProject\Services\RenderViewComponentService.cs:line ??
   at MyProject.Services.PdfService.DoWorkAsync(Foo foo) in MyProject\Services\PdfService.cs:line ??
   at MyProject.Services.PdfService.GenerateAsync() in MyProject\Services\PdfService.cs:line ??
   at MyProject.Controllers.MyController.Get() in MyProject\Controllers\MyController.cs:line ??
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper,ObjectMethodExecutor executor,Object controller,Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker,ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterasync>g__Awaited|10_0(ControllerActionInvoker invoker,Task lastTask,State next,Scope scope,Object state,Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next,Scope& scope,Object& state,Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterasync>g__Awaited|13_0(ControllerActionInvoker 
invoker,Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker,Task 
lastTask,Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next,Boolean& isCompleted)    
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker,Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker,Task task,Idisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint,Task requestTask,ILogger logger)
   at Microsoft.AspNetCore.HeaderPropagation.HeaderPropagationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

我认为问题是我如何将IViewComponentHelper上下文化。但是我不知道该怎么做。

你能发现我做错了什么吗?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...