我只使用一个调用相同C#DLL文件(在WCF之外)的简单应用程序进行测试,并且它可以完美地工作.所以,WCF和那个C DLL文件正在发生一些事情,但我们无法弄清楚是什么.我已经将Visual Basic 6.0 DLL文件更改为使用Run Unattended和Store in Memory(以便能够使用它),但这似乎并不重要.
有没有人有这方面的经验,或者有任何想法为什么会挂?我的想法是WCF服务以某种方式锁定DLL文件,这就是为什么当Visual Basic 6.0 DLL文件使用它时,它无法访问它,导致它死锁.
C包装
public interface ISummaryWrapper { void LoadInfo(Application info); SummaryApp GetSummary(); } public class SummaryWrapper : ISummaryWrapper { private SummaryApp _summary; public SummaryWrapper() { _summary = new SummaryApp(); } public SummaryWrapper(Application info) { _summary = new SummaryApp(); LoadInfo(info); } public void LoadInfo(Application info) { _summary.Initialize(info); } public SummaryApp GetSummary() { return _summary; } }
info对象包含有关Summary对象需要生成的内容的信息.它仅用于Initialize方法.
Visual Basic 6.0对象通过接口加载:
public void LoadPageObject(Application info) { _pageInfo = new Page@R_431_4045@ion(); _pageInfo.oInfo = info; _pageInfo.oSummary = _summary; }
所以现在Visual Basic 6.0对象Page@R_431_4045@ion有了摘要对象.
_pageInfo.buildreport();
这在Visual Basic 6.0 DLL文件中,并且在代码尝试使用摘要对象时,它会挂起
// Omitted actual params for brevity,though all the params exist double value = oSummary.GetData(string parm1,string parm2)
double value = _summary.GetData(string parm1,string parm2);
同样,当我在WCF之外使用这个包装器时,它会很好地完成代码.只有当它在WCF中运行时它才会挂起.
这似乎是在MTA中运行的问题,我不确定在IIS上运行的WCF服务应用程序是否可以设置为在STA中运行.这可能吗?
解决了:
我在Stack Overflow问题中找到了答案:
How to make a WCF service STA (single-threaded)
基本上,我必须创建一个设置为STA的线程,并在其中运行API(我的C#DLL文件).由于我使用TaskFactory运行所有这些(所以我可以取消调用,并运行多个请求),这有点棘手.现在,我仍然可以在MTA中同时运行多个报告,但每个报告都在STA中运行.此外,我也不会失去WCF的取消功能.
这是代码(我还有一些清理工作):
public class Builder { public string OperationId { get; set; } public IServiceCallback CallBack { get; set; } public Dictionary<string,CancellationTokenSource> Queue { get; set; } public void buildreport() { OperationContext context = OperationContext.Current; Thread thread = new Thread( new ThreadStart( delegate { using (OperationContextScope scope = new OperationContextScope(context)) { try { CancellationToken token = Queue[OperationId].Token; CallBack.SendStatus(OperationId,Status.Processing); IAPI api = new API(token); api.MessagingEvents += MessageEvent; // Build Report CallBack.SendStatus(OperationId,Status.BuildingReport); if (!api.buildreport()) return; CallBack.SendStatus(OperationId,Status.Completed); } catch (OperationCanceledException oc) { // Sending this on the method that receives the cancel request,no need to send again } catch (Exception ex) { // May not be able to use callback if it's a Timeout Exception,log error first // Todo: Log Error CallBack.SendMessage(OperationId,MessageType.Error,ex.Message); CallBack.SendStatus(OperationId,Status.Error); } finally { Queue.Remove(OperationId); } } })); thread.SetApartmentState(ApartmentState.STA); thread.Start(); thread.Join(); } }
我的服务通过以下方式调用:
// I initialize taskfactory when the service is created,omitting other code for brevity public void buildreport(ReportRequest request) { CallBack.SendReportStatus(request.OperationId,Status.Received); CancellationTokenSource cancelSource = new CancellationTokenSource(); Queue.Add(request.OperationId,cancelSource); Builder builder = new Builder { OperationId = request.OperationId,CallBack = CallBack,Queue = _queue }; _taskFactory.StartNew(builder.buildreport,cancelSource.Token); }
我希望这可以帮助遇到这个问题的任何人!
解决方法
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。