无法访问已释放的对象-wcf客户端
本文关键字:对象 -wcf 客户端 释放 访问 | 更新日期: 2023-09-27 18:30:03
我有一个WCF客户端遇到问题
我时不时地会遇到这样的异常:Cannot access a disposed object
。这就是我打开连接的方式:
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)
根据堆栈跟踪,我假设您有一个ASP.NET MVC应用程序,其中包含一些代码,该应用程序调用Get
方法来获取CrmServiceClient
对象,然后继续调用该CrmServiceClient
对象上的各种方法。例如,登录过程的一部分就是这样做的。
Get
方法的工作方式是,每次调用它时,它都会首先关闭之前返回的CrmServiceClient
对象(无论它是否仍在使用),然后创建并返回一个新对象。
想象一下,两个用户几乎同时尝试登录到您的应用程序,彼此相隔几毫秒。处理第一个用户登录的线程调用Get
并获取其CrmServiceClient
对象,然后一毫秒后,处理第二个用户的登录的线程呼叫Get
,这导致第一个线程的CrmServiceClient
对象关闭。然而,第一个线程仍在运行,现在当它试图调用其CrmServiceClient
对象上的方法时,它会得到一个System.ObjectDisposedException: Cannot access a disposed object
。
"正如你所看到的,我每次都会关闭和重新打开连接。"
当前Get
方法中的代码不是实现这一点的好方法。相反,您应该让调用方负责关闭(或处置)CrmServiceClient
对象,并且您可能应该将Get
方法重命名为Open
或Create
来建议这样做。调用方应该使用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