2010-12-10 5 views
2

私はASP.NETアプリケーションでサードパーティのWebサービスを使用しています。サードパーティのWebサービスへの呼び出しは同期する必要がありますが、ASP.NETは明らかにマルチスレッドであり、複数のページ要求が行われ、サードパーティWebサービスへの同時呼び出しが行われる可能性があります。 Webサービスへの呼び出しは、カスタムオブジェクトにカプセル化されます。私の考えは、オブジェクトをアプリケーション変数に格納し、C#のlockキーワードを使用して強制的に使用することです。ASP.NETアプリケーション変数をロックする

私はマルチスレッドのコンセプトに慣れていないので、私は神経質です。パブリックオブジェクト(アプリケーション変数が効果的です)をロックしないでください。また、ロックされたコードブロックが失敗した場合(Webサービスが失敗した場合)、アプリケーションドメインを不安定にしてアプリケーションを停止させる可能性があることも読んでいます。

サードパーティのWebサービスは私のWebサイトではめったに使用されておらず、同時に2つの要求が同時に行われることはまれであることに言及しておきます。

ThirdPartWebService objWebService = Application["ThirdPartWebService"] As ThirdPartWebService; 
lock (objWebService) 
{ 
    objWebService.CallThatNeedsToBeSynchronized(); 
} 

答えて

1

あなたは、静的な共有オブジェクトをロックすることができます

は、ここで私は、Webサービスの呼び出しを作ると思いますかのラフなコードサンプルです。これは、.Netでロックを使用する一般的な方法です。あなたが知っている静的オブジェクトを使用することによって、それはすべてのスレッド間で共有され、ロックが保証されます。

コールが失敗した場合にアプリを不安定にするためには、コールが適切に処理されないことが原因です。 "using"ステートメントを使用することで、呼び出しの最後にdisposeが呼び出されるようになります。なぜ、あなたがパフォーマンスに関してウェブサービスを処分すべきなのかについて、このSO threadを読んでください。

static readonly object _lockObj = new object(); 
... 
lock(_lockObj) 
{ 
    ThirdPartWebService objWebService = Application["ThirdPartWebService"] As ThirdPartWebService; 
    objWebService.CallThatNeedsToBeSynchronized(); 
} 
+0

サードパーティのWebサービスには高価なログインメソッドがあるため、実際にはCallThatNeedsToBeSynchronizedメソッドを呼び出すたびにオブジェクトを破棄したくありません。サービスをログインしたままにして、アプリケーション状態で保存したい。 –

+0

Webサービスを再作成する必要がある場合は、usingブロックを削除し、独自の処理を作成します。 –

1

あなたは、Webサービスの呼び出しを行うクラスでprivate static readonly object _lock = new object();を作成し、ロックとしてそれを使用する必要があります。オブジェクトが静的であるだけなのでシングルトンオブジェクトは、アプリケーションのすべてを通じてそれらのいずれかがあるでしょうあなたは(http://en.wikipedia.org/wiki/Singleton_pattern)をご希望の場合は

public class MyWebServiceWrapper 
{ 
    private static readonly object _lock = new object(); 

    public void CallWebService() 
    { 
     lock(_lock) 
     { 
     var objWebService = (ThirdPartWebService)Application["ThirdPartWebService"]; 
     objWebService.CallThatNeedsToBeSynchronized(); 
     } 
    } 
} 

そのクラスの場合WebService呼び出しが何もしない場合は、これをロックすることもできます(lock(this))。これは、いくつかのメソッドがある場合、1つのメソッドを呼び出すと他のすべてのメソッドもブロックされるため、これをロックしてはいけないということです。

2

重要な場合は、いつでも独自のWindowsサービスを作成することをお勧めします。これは、どれくらいのフォールトトレランスが必要かによって異なります。

たとえば、Webサービスを呼び出しても、アプリケーションプールがリサイクルされたとします。新しいリクエストが到着すると、アプリケーションの新しいインスタンスによって処理され、Webサービス(たとえ他のインスタンスが実行中であっても)を呼び出すことができます。

これをWindowsのサービスに渡してから、クライアントからのポーリングメカニズムを使用してサービスが終了したかどうかを確認できます(クライアントはIISに要求しますか、IISはWindowsサービスから何らかの表示を探しますされた)。この方法ではIISで何かをロックすることはなく、スレッドプール内のスレッドなどの重要なリソースをサードパーティのサービスで待機することはありません。

Webアプリケーションの単一のリソースに決してロックするべきではありません。それはあまりにも危険です。ロックが行われているか、10ミリ秒が経過するまで

if (System.Threading.Monitor.TryEnter(syncObj,10)) 
    { 

     try 
     { 
      //CallWebService 
     } 
     finally 
     { 
      System.Threading.Monitor.Exit(syncObj); 
     } 
    } 
    else 
    { 
     //Tell Client they are still waiting 

    } 

TryEnterがブロックされます:

編集

別のオプションは、直接モニタオブジェクトを使用することです。タイムアウトで、クライアントに再試行する必要があることを伝えることができます。その後、要求を再発行するかどうかをクライアントコードに決定させることができます。セマフォーまたはミューテックスを使用することもできます(どちらがより適切かを忘れてしまいます)。しかし、それはあなたがそれらを使用する権限を持っていると仮定して、アプリケーションをリサイクルするケースを防止するマシンレベルでロックできるものをあなたに与えます。

+0

私はあなたの要点を見ていますが、私の場合、同時リクエストはほとんどなく、アプリケーションプールのリサイクルに起因するWebサービスへの呼び出しが2回発生した場合、私にとって大きな問題ではありません。だから、別のサービスを作ることは、おそらく(私にとっては)過度のものになるでしょう。それは、スパイダーのようなものが私のサイトの特定のページに数秒以内に何度もヒットした場合、多くのスレッドをロックしてWebサービスを呼び出すことができることを認識させます。私はそれを守る必要があります。 –

0

lock()は、Webサービスへの複数の呼び出しを防ぎません。これは、スレッドが同時にlock() {}内のコードブロックを実行していないことを保証します。 そのウェブサービスは何をしているのですか?

1)サードパーティで何らかのアクションを実行します(あなたの提供する値でDBを更新しますか?) 自分で提案したようにすることができます。彼らのサービスが同時通話を扱うことができなければ、それを修正すべきだと私は言うだろうが。それは本当に心配するあなたの問題ではありません。

2)使用するためにいくつかのデータを照会して返します。 この場合、コールの結果をキャッシュする予定がない限り、ロックは役に立たない。

var cachedValue = ReadValueFromCache(); 
if (cachedValue != null) 
    return cachedValue; 

lock (objWebService) 
{ 
    // yes you need to do it second time inside the lock 
    cachedValue = ReadValueFromCache(); 
    if (cachedValue != null) 
     return cachedValue; 

    cachedValue = objWebService.CallThatNeedsToBeSynchronized(); 
    SaveValueToCache(cachedValue); 
} 

return cachedValue; 

キャッシュを実装する方法は、ある程度セカンダリです。おそらく、Webキャッシュオブジェクトまたは単に静的変数です。

+0

Webサービスは、NetSuiteアカウンティングシステムとインターフェイスするためのAPIです。これには、データの挿入、更新、削除、およびデータのクエリのためのメソッドがあります。残念ながら、(何らかの理由で)すべての呼び出しを同期させる必要があります。 Webサービスのメソッドを呼び出すと、そのメソッドが返されるまで、そのサービスへのすべての呼び出しをブロックする必要があります。私は、ロックがオブジェクトへのアクセスを完全にブロックすると思ったが、コードのロックブロック内の呼び出しをブロックするように思える。 –

+0

が正しい。 lock()に渡すオブジェクトは、ロックの「キー」に過ぎません。つまり、同じオブジェクトを使用してさまざまなコードブロックをロックすることができます。 'lock(objWebService){objWebService.foo();}'と 'lock(objWebService){objWebService.bar();}'は、fooとbarブロックを互いにブロックするのに全面的に働きます。 –

関連する問題