5

問題が発生している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)
4

1 に答える 1

7

Getそのスタックトレースから、オブジェクトを取得するためにそのメソッドを呼び出しCrmServiceClient、次にそのオブジェクトのさまざまなメソッドの呼び出しに進むコードを備えたASP.NETMVCアプリケーションがあると想定しCrmServiceClientます。たとえば、ログインプロセスの一部がこれを行います。

メソッドが機能するGet方法は、呼び出されるたびに、最初にCrmServiceClient以前に返されたオブジェクトを閉じ(まだ使用されているかどうかに関係なく)、次に新しいオブジェクトを作成して返します。

2人のユーザーがほぼ同時に(互いにミリ秒以内に)アプリケーションにログインしようとしたとします。最初のユーザーのログイン呼び出しGetを処理してそのCrmServiceClientオブジェクトを取得し、1ミリ秒後に、2番目のユーザーのログイン呼び出しを処理するスレッド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
于 2012-04-04T13:29:01.520 に答える