2016-05-17 40 views
2

C#(.NET 4.5)で書かれたASMX Webサービスを使用する従来のVB6アプリケーションは、ライブラリ(C#/ .NET 4.5)を使用してビジネスロジックを実行します。ライブラリメソッドの1つは、長期実行のデータベースストアドプロシージャをトリガし、その最後に、ストアドプロシージャによって生成されたデータを消費する別のプロセスを開始する必要があります。要件の1つは、Webサービスを呼び出した後、コントロールがすぐにVB6クライアントに返されなければならないということです。ライブラリメソッドはasyncで、Actionコールバックをパラメータとし、webserviceはコールバックを匿名メソッドとして定義し、結果はawaitライブラリメソッド呼び出しのコールバックを使用した.NET非同期Webサービス呼び出し

ハイレベルで、それは次のようになります。

 
using System; 
using System.Data.SqlClient; 
using System.Threading.Tasks; 
using System.Web.Services; 

namespace Sample 
{ 
    [WebService(Namespace = "urn:Services")] 
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
    public class MyWebService 
    { 
     [WebMethod] 
     public string Request(string request) 
     { 
      // Step 1: Call the library method to generate data 
      var lib = new MyLibrary(); 
      lib.GenerateDataAsync(() => 
      { 
       // Step 2: Kick off a process that consumes the data created in Step 1 
      }); 

      return "some kind of response"; 
     } 
    } 

    public class MyLibrary 
    { 
     public async Task GenerateDataAsync(Action onDoneCallback) 
     { 
      try 
      { 
       using (var cmd = new SqlCommand("MyStoredProc", new SqlConnection("my DB connection string"))) 
       { 
        cmd.CommandType = System.Data.CommandType.StoredProcedure; 
        cmd.CommandTimeout = 0; 
        cmd.Connection.Open(); 

        // Asynchronously call the stored procedure. 
        await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); 

        // Invoke the callback if it's provided. 
        if (onDoneCallback != null) 
         onDoneCallback.Invoke(); 
       } 
      } 
      catch (Exception ex) 
      { 
       // Handle errors... 
      } 
     } 
    } 
} 

現地試験では上記の作品が、Webサービスステップ2がさえステップ1かかわらず実行されることはありませんように、コードが展開されるときストアドプロシージャが完了し、データを生成します。

私たちは間違って何をしていますか?

私は、コードの非同期実行に古いスタイル(開始/終了)のアプローチを必要とする私の問題への解決策を発見した
+0

ローカルマシンのファイアウォールが着信接続をブロックしている可能性があります... – Eser

+0

ステップ1は 'lib.GenerateDataAsync'(' GenerateData'と表示されていません)を呼び出していると思います。問題は、asmxリクエストが実行を終了し、「ドアが外れている」ということです。コールバックを実行する場所はありません。あなたはその電話を待ってみましたか? –

+0

リクエストの実装を確認してください。 asyncを使用している場合は、パイプライン全体で一貫性のあるソリューションを使用する必要があります。 –

答えて

1

public void GenerateData(Action onDoneCallback) 
    { 
     try 
     { 
      var cmd = new SqlCommand("MyStoredProc", new SqlConnection("my DB connection string")); 
      cmd.CommandType = System.Data.CommandType.StoredProcedure; 
      cmd.CommandTimeout = 0; 
      cmd.Connection.Open(); 

      cmd.BeginExecuteNonQuery(
       (IAsyncResult result) => 
       { 
        cmd.EndExecuteNonQuery(result); 
        cmd.Dispose(); 

        // Invoke the callback if it's provided, ignoring any errors it may throw. 
        var callback = result.AsyncState as Action; 
        if (callback != null) 
         callback.Invoke(); 
       }, 
       onUpdateCompleted); 
     } 
     catch (Exception ex) 
     { 
      // Handle errors... 
     } 
    } 

onUpdateCompletedコールバックアクションは二通りBeginExecuteNonQueryメソッドに渡されます最初の引数であるAsyncCallbackで消費されます。これは、VS内でデバッグするときとIISにデプロイするときの両方の魅力のように機能します。

2

IISでタスクを実行したままにすると危険です。メソッドドメインが終了する前に、アプリケーションドメインがシャットダウンされている可能性があります。 HostingEnvironment.QueueBackgroundWorkItemを使用する場合は、実行中の作業が必要な作業があることをIISに伝えることができます。あなたは90余分な秒がいくつかの他のオプションについては、ステファン・クリアリーによる記事「Fire and Forget on ASP.NET」を参照してくださいよりも、より信頼性の高い何かをしたい場合はこれが(デフォルトで)余分な90秒間生き

using System; 
using System.Data.SqlClient; 
using System.Threading.Tasks; 
using System.Web.Services; 

namespace Sample 
{ 
    [WebService(Namespace = "urn:Services")] 
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] 
    public class MyWebService 
    { 
     [WebMethod] 
     public string Request(string request) 
     { 
      // Step 1: Call the library method to generate data 
      var lib = new MyLibrary(); 
      HostingEnvironment.QueueBackgroundWorkItem((token) => 
       lib.GenerateDataAsync(() => 
       { 
        // Step 2: Kick off a process that consumes the data created in Step 1 
       })); 

      return "some kind of response"; 
     } 
    } 

    public class MyLibrary 
    { 
     public async Task GenerateDataAsync(Action onDoneCallback) 
     { 
      try 
      { 
       using (var cmd = new SqlCommand("MyStoredProc", new SqlConnection("my DB connection string"))) 
       { 
        cmd.CommandType = System.Data.CommandType.StoredProcedure; 
        cmd.CommandTimeout = 0; 
        cmd.Connection.Open(); 

        // Asynchronously call the stored procedure. 
        await cmd.ExecuteNonQueryAsync().ConfigureAwait(false); 

        // Invoke the callback if it's provided. 
        if (onDoneCallback != null) 
         onDoneCallback(); 
       } 
      } 
      catch (Exception ex) 
      { 
       // Handle errors... 
      } 
     } 
    } 
} 

をアプリケーションドメインを維持します。

関連する問題