我试图在ASP.NET MVC web应用程序中使用本地报告服务生成PDF报告。
问题是,当对Render()方法的调用在一个单独的Task中完成时,我会得到一个异常:
Microsoft.ReportingServices.ReportProcessing.ReportProcessingException:未能加载表达式宿主程序集。详细信息:模拟令牌无效-它不能被复制。
如果对Render()的调用在同一个线程中被用户请求(通过控制器->类库)命中,则不会引发异常。
我现在没有选择了。到目前为止我尝试过的事情:
我尝试过将任务包装在一个using块中。
// Doesn't work even with (true) or ()
IntPtr currentUser = WindowsIdentity.GetCurrent(false).Token;
Task.Run(() =>
{
using (WindowsIdentity.Impersonate(currentUser))
{
ProcessStart();
}
});
public static void ProcessStart()
{
LocalReport localReport = new LocalReport();
...
getting data for the report
...
// this statement throws the exception
byte[] pdfStream = localReport.Render(formatString,
deviceInfo,
out mimetype,
out encoding,
out fileNameExtension,
out streams,
out warnings);
...
saving bytestream to file
...
}我检查了这个职位,但我看不出这对我有什么帮助,因为我目前只是在本地主机上调试。
我检查了这个答案,但是它建议删除该任务,并在同一个线程中执行报告,这是我做不到的。
提前谢谢你的时间。
发布于 2018-06-29 17:05:18
在我使用工作解决方案的过程中,我首先开始修改alwaysFlowImpersonationPolicy配置标志,它似乎存在以处理ASP.NET请求生命周期中线程之间传递模拟令牌的问题,有一些有用的文件,但它是死胡同。
这里的问题是身份问题,以及LocalReport.Render使用沙箱应用程序域编译和执行表达式的事实。
如果我们能够阻止报表引擎创建沙箱应用程序域,那么它的代码将在与调用代码相同的域中和执行上下文中执行,从而避免引发内部异常的附加令牌传播。检查文档中的LocalReport类会发现ExecuteReportInCurrentAppDomain方法,并承诺这样做:
public static void ProcessStart()
{
var localReport = new LocalReport();
/* ...
* getting data for the report
* ... */
/* prepare to do all rendering in the same appdomain */
localReport.ExecuteReportInCurrentAppDomain(Assembly.GetExecutingAssembly().Evidence);
/* now this fails no more */
byte[] pdfStream = localReport.Render(
formatString,
deviceInfo,
out mimetype,
out encoding,
out fileNameExtension,
out streams,
out warnings
);
/* ...
* saving bytestream to file
* ... */
}我测试过了,它真的能用!但是也有一个缺点:在.NET 4.0和更高版本中,这个方法已经被废弃了。有必要添加两个遗留配置开关以使其工作:
<configuration>
<system.web>
<trust legacyCasModel="true" />
</system.web>
<runtime>
<legacyCasPolicy enabled="true" />
<NetFx40_LegacySecurityPolicy enabled="true"/>
</runtime>
</configuration>如果没有添加这些内容,调用ExecuteReportInCurrentAppDomain将引发异常。我现在正在生产中使用这段代码;我知道在.NET的未来版本中,这可能会中断--也许在此之前,报告引擎也会得到改进。当然,不建议添加这些遗留的CAS支持内容,它可能会对应用程序的其他部分产生影响,例如,它将阻止运行时使用来自GAC的NGEN映像。
尝试在任务上下文中放置请求标识与标志文件中的Aspnet.config一样毫无意义。
总的来说,这种方法还有许多其他问题,例如,没有阻止主机进程终止工作线程和后台任务的机制。因此和其他地方上的其他几篇文章处理了这些额外的复杂问题,无论如何,最健壮的解决方案仍然是让服务流程独立于IIS运行,并使用消息队列、命名管道或诸如此类的方式为其分配后台任务。从.NET框架版本4.5.2开始,您可以使用HostingEnvironment.QueueBackgroundWorkItem。
既然有这么多反对的建议,我们为什么还要继续这样做呢?海事组织只有一个很好的理由:每当我们要求尽快返回时,我们都不在乎结果是否被丢弃。我不知道OP的用户故事,但我允许这样做:我们在页面导航上触发来自SCORM电子学习包的请求,我们需要避免这里的任何延迟。如果用户在使用异步交付的报表之前导航,工作线程也可以提前终止任务。
https://stackoverflow.com/questions/40545540
复制相似问题