在具有 2 个不同 .SVC 文件的多线程环境中调用 WCF 服务。同时调用两个服务时出错

Posted

技术标签:

【中文标题】在具有 2 个不同 .SVC 文件的多线程环境中调用 WCF 服务。同时调用两个服务时出错【英文标题】:Calling WCF Service in Multithreading Environment that has 2 different .SVC Files. Error while calling both service at the same time 【发布时间】:2018-11-17 19:33:36 【问题描述】:

我有一个应用程序,其中包含两个特定于两个不同模块的 .SVC 文件。 在现有的应用程序中,我们在同一个线程中一个接一个地进行调用。我从来没有遇到过问题。

作为重构的一部分,我清理了它们从两个不同的线程调用这些服务(第一个线程调用第一个方法,第二个线程调用第二个方法)。这两种方法甚至是不同的。有时代码正在执行而没有任何问题。但有时,我遇到错误,说找不到实例。同样,此错误并不总是发生。

      Exception:
                RMS Conversion failed : System.ServiceModel.FaultException`1[System.ServiceModel.ExceptionDetail]: ComponentActivator: 

could not instantiate Axis.Edc.Service.RMS.RMSConversionService (Fault Detail is equal to An ExceptionDetail, likely created by IncludeExceptionDetailInFaults=true, whose value is:
    Castle.MicroKernel.ComponentActivator.ComponentActivatorException: ComponentActivator: could not instantiate RMS.RMSConversionService ----> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ----> System.InvalidOperationException: The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.
       at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
       at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
       at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
       at System.Data.Entity.Internal.Linq.InternalSet`1.GetEnumerator...).

这是对服务的代码调用:

public EnumConversionStatus GenerateRmsImportFiles(int submissionId)
        
            lock (new object())
            
                using (var client = new RMSConversionService.RMSConversionServiceClient())
                
                    var result = client.GenerateRmsImportFiles(submissionId);
                    client.Close();
                    return result;
                
            
        


public EnumConversionStatus GenerateAirImportFiles(int submissionId)
        
            lock (new object())
            
                using (var client = new AIRConversionService.AirConversionServiceClient())
                
                    var result = client.GenerateAirImportFiles(submissionId);
                    return result;
                
            
        

这里我们有两个不同的端点用于 2 个不同的 SVC 服务。 在这里我们也有锁。我不确定如何解决这个错误?

谢谢, 丽塔

【问题讨论】:

这与 WCF 无关,您有 2 个或更多线程尝试调用您的 GenerateRmsImportFiles() 方法。 【参考方案1】:

使用lock (new object()) 每次都会创建一个新对象。这意味着每个线程锁定不同的对象。这根本不是锁定。

如果您的两个服务不使用相同的资源,则不需要锁定。 但正如我从您的异常中看到的那样,您正在使用两个服务之间的共享资源 - 这是实体框架 DbContext。

我假设一个线程正在初始化 DbContext,同时第二个线程正在使用相同的 DbContext。从异常消息中可以看出:

在创建模型时不能使用上下文。如果在 OnModelCreating 方法中使用上下文,或者多个线程同时访问同一个上下文实例,则可能会引发此异常。请注意,不保证 DbContext 和相关类的实例成员是线程安全的。

更好的锁定方式是:

private object _lock = new object();

    public EnumConversionStatus GenerateRmsImportFiles(int submissionId)
            
                lock (_lock)
                
                    using (var client = new RMSConversionService.RMSConversionServiceClient())
                    
                        var result = client.GenerateRmsImportFiles(submissionId);
                        client.Close();
                        return result;
                    
                
            


    public EnumConversionStatus GenerateAirImportFiles(int submissionId)
            
                lock (_lock)
                
                    using (var client = new AIRConversionService.AirConversionServiceClient())
                    
                        var result = client.GenerateAirImportFiles(submissionId);
                        return result;
                    
                
            

【讨论】:

我会试试这个。但关键是,尽管它们在同一个项目中,但它们是两个不同的服务。想知道它们是如何干扰的,并且从一个线程调用一种方法,从第二个线程调用第二种方法。 . 我会为两者使用不同的锁定对象,否则一旦访问一个对象,另一个对象将被锁定。 耶。这可能有效。但正如我所说,第一个方法是从第一个线程调用的,第二个方法是从第二个线程调用的。不知道他们是怎么干涉的。 @Rita 你试过我的解决方案了吗?我已经更新了我的答案以更清楚。 @Karel,我试过了。工作得很好。谢谢你。我也正在测试通过将 WCF 服务模式从 Singleton 切换到 PerCall 来查看是否允许新实例。

以上是关于在具有 2 个不同 .SVC 文件的多线程环境中调用 WCF 服务。同时调用两个服务时出错的主要内容,如果未能解决你的问题,请参考以下文章

谷歌应用引擎中的多会话配置

不同机器上的单个进程与单台机器上的多线程,核心等于单 CPU 机器的数量

多线程编程之Linux环境下的多线程

具有内联汇编和访问 c 变量的多线程

双核cpu上的多线程

单一登录的多域,