无法访问已释放的对象 - WCF客户端。

6

我有一个WCF客户端出现了问题。
不时地,我会遇到这个异常:无法访问已释放的对象。这是我打开连接的方式:

private static LeverateCrmServiceClient crm = null;

public static CrmServiceClient Get(string crmCertificateName)
        {

            if (crm != null)
            {
                crm.Close();
            }
            try 
            {
                crm = new LeverateCrmServiceClient("CrmServiceEndpoint");
                crm.ClientCredentials.ClientCertificate.SetCertificate(
                               StoreLocation.LocalMachine,
                               StoreName.My,
                               X509FindType.FindBySubjectName,
                               crmCertificateName);
            }
            catch (Exception e) 
            {
                log.Error("Cannot access CRM ", e);
                throw;
            }
            return crm;
        }

正如您所看到的,我每次都在关闭和重新打开连接。

您认为可能会有什么问题?

堆栈:

System.ServiceModel.Security.MessageSecurityException: Message security verification failed. ---> System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'System.ServiceModel.Security.SymmetricSecurityProtocol'.
  at System.ServiceModel.Channels.CommunicationObject.ThrowIfClosedOrNotOpen()
  at System.ServiceModel.Security.MessageSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
  --- End of inner exception stack trace ---

Server stack trace:
  at System.ServiceModel.Security.MessageSecurityProtocol.VerifyIncomingMessage(Message& message, TimeSpan timeout, SecurityProtocolCorrelationState[] correlationStates)
  at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
  at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
  at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
  at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:
  at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
  at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
  at Externals.CrmService.ICrmService.GetTradingPlatformAccountDetails(Guid ownerUserId, String organizationName, String businessUnitName, Guid tradingPlatformAccountId)
  at MyAppName.Models.ActionsMetadata.Trader.BuildTrader(Guid tradingPlatformAccountId) in C:\Users\X\Documents\Visual Studio 2010\Projects\MyAppName\MyAppName\Models\ActionsMetadata\Trader.cs:line 120
  at MyAppName.Models.ActionsMetadata.Trader.Login(String accountNumber, String password) in C:\Users\X\Documents\Visual Studio 2010\Projects\MyAppName\MyAppName\Models\ActionsMetadata\Trader.cs:line 48
  at MyAppName.Models.ActionsMetadata.Handlers.LoginHandler.Handle(StepHandlerWrapper wrapper) in C:\Users\X\Documents\Visual Studio 2010\Projects\MyAppName\MyAppName\Models\ActionsMetadata\Handlers\LoginHandler.cs:line 23
  at MyAppName.Models.ActionsMetadata.Handlers.HandlerInvoker.Invoke(IAction brokerAction, ActionStep actionStep, Dictionary`2 stepValues, HttpContext httpContext, BaseStepDataModel model) in C:\Users\X\Documents\Visual Studio 2010\Projects\MyAppName\MyAppName\Models\ActionsMetadata\Handlers\StepServerInoker.cs:line 42
  at MyAppName.Controllers.LoginController.Login(String step) in C:\Users\X\Documents\Visual Studio 2010\Projects\MyAppName\MyAppName\Controllers\LoginController.cs:line 35
  at lambda_method(Closure , ControllerBase , Object[] )
  at System.Web.Mvc.ReflectedActionDescriptor.Execute(ControllerContext controllerContext, IDictionary`2 parameters)
  at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
  at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass15.<InvokeActionMethodWithFilters>b__12()
  at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodFilter(IActionFilter filter, ActionExecutingContext preContext, Func`1 continuation)
  at System.Web.Mvc.ControllerActionInvoker.InvokeActionMethodWithFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor, IDictionary`2 parameters)
  at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)

这个问题似乎已经在这里得到了回答:https://dev59.com/im455IYBdhLWcg3wCfmC - Chriseyre2000
1个回答

8
从那个堆栈跟踪中,我假设你有一个ASP.NET MVC应用程序,其中某些代码调用了那个Get方法来获取一个CrmServiceClient对象,然后继续调用该CrmServiceClient对象的各种方法。例如,登录过程的一部分就是这样操作的。
你的Get方法的工作方式是,每次调用它时,它都会首先关闭之前返回的CrmServiceClient对象(无论它是否仍在使用),然后创建并返回一个新的对象。
想象一下,两个用户几乎同时尝试登录到你的应用程序 - 在彼此之间的毫秒内。处理第一个用户登录的线程调用Get并获取其CrmServiceClient对象,然后一毫秒后,处理第二个用户登录的线程调用Get,这导致第一个线程的CrmServiceClient对象被关闭。但是,第一个线程仍在运行,现在当它尝试调用其CrmServiceClient对象上的方法时,它会得到一个System.ObjectDisposedException:Cannot access a disposed object
“正如您所看到的,我每次都关闭和重新打开连接。”
目前在您的Get方法中的代码不是实现此目的的好方法。相反,你应该让调用者负责关闭(或处理)CrmServiceClient对象,你也可以考虑将你的Get方法重命名为OpenCreate来暗示这一点。调用者应该使用using语句确保对象被关闭/处理,无论发生任何异常:
using (CrmServiceClient client = CrmServiceFactory.Get("my-crm-certificate"))
{
    client.Something();
    client.GetTradingPlatformAccountDetails();
    client.SomethingElse();
} // client is automatically closed at the end of the 'using' block

根据微软文档所述:“C#中的“using”语句会导致调用Dispose()。这与Close()相同,当发生网络错误时可能会抛出异常”,从而导致隐藏的异常。 - user5986440

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接