Windows Mobile 6.5、Compact Framework 3.5 用のアプリを開発しています。アプリケーションは、単純なログイン フォームをロードすることから始まります。ログイン フォームが作成されて開かれている間、Web サービスからセットアップ データを取得するための新しいスレッドが作成されます。3 このスレッド内で、同じ Web サービスに対して個別の呼び出しが非同期で行われます。
最初の呼び出しは、会社のリストを取得します。2 番目の呼び出しは、会社に属する場所のリストを取得します。3 番目の呼び出しは、場所と会社に属するユーザーとそのログイン ID のリストを取得します。
各 Web サービスの OnGet***Completed イベントは、返されたデータをローカルの SQLite データベースに保存します。
そのロジックをコンパイルして Visual Studio デバッガーで実行すると、すべてがうまく動作します。アプリが起動し、フォームが表示され、3 つの Web サービス呼び出しが作成されて終了します。ユーザーとしてログインして続行できます。大丈夫です!
例外として、CAB ファイルをビルドし、デバッグに使用するのとまったく同じデバイスにアプリケーションをインストールすると、アプリケーションが 60 秒間待機し、3 つの WebException "The operation has timed-out" エラーが発生し、アプリケーションが強制的に閉じられます。 .
私はこの問題を数日間プレイして調査してきました。Web サービスの構成で最大接続を設定することについてよく読んで、以下に示すようにバインディングを大きな値に設定しました。
<add address="*" maxconnection="324"/>
と
<binding name="BasicHttpBinding_IGenericContract" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="2147483647" maxBufferPoolSize="2147483647" maxReceivedMessageSize="2147483647"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647" maxArrayLength="2147483647"
maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
</binding>
また、Windows Mobile アプリケーションで Web サービス呼び出しを開始する前に、既定の接続制限を 22 に設定しました。
これは、各クラスの新しいインスタンスを作成することによって、3 つの非同期 Web サービス呼び出しすべてを開始する私のコードです (以下に示すクラス構造)。
'Currently Inside of Initial Synchronize Thread
System.Net.ServicePointManager.DefaultConnectionLimit = 22
Dim syncCompanies As New SyncCompanies(True)
Dim syncLocations As New SyncLocations(True)
Dim syncUsers As New SyncUsers(True)
これが SyncCompanies クラスです。 New メソッドは、Web サービス呼び出しを非同期または同期で実行するようにクラスに指示する「非同期」ブール値パラメーターを受け入れます。3 つの Web サービスをすべて非同期で実行したいと考えています。
Public Class SyncCompanies
Private service As New RDScanService.BasicHttpBinding_IGenericContract
'Method that Retrieves the Companies data from the server
Public Sub New(ByVal Asynchronous As Boolean)
DoAsynchronously = Asynchronous
NewCompanies = New Companies(False, False)
Try
IsBusy = True
If DoAsynchronously Then
'Begin the Asynchronous Call
Dim cb As New AsyncCallback(AddressOf onGetCompaniesComplete)
service.BeginGetCompanies(currentSetup.LastCompaniesSync, True, cb, Nothing)
Else
'Perform the Synchronous Call, create a list of Companies and pass to the Execute function for saving
For Each company In service.GetCompanies(currentSetup.LastCompaniesSync, True)
Dim newCompany As New Company(False, False, "")
newCompany.Code = company.Code
newCompany.ReportName = company.ReportName
NewCompanies.Companies.Add(newCompany)
Next
Execute()
IsBusy = False
End If
Catch ex As Exception
service.Abort()
IsBusy = False
Success = False
ErrorVerb = "retrieving companies from server"
ErrorMessage = ex.Message
Finally
Dispose()
End Try
End Sub
Private Sub onGetCompaniesComplete(ByVal ar As IAsyncResult)
'End the Asynchronous Web Service Call and start the Asynchronous Processing
For Each company In service.EndGetCompanies(ar)
Dim newCompany As New Company(False, False, "")
newCompany.Code = company.Code
newCompany.ReportName = company.ReportName
NewCompanies.Companies.Add(newCompany)
Next
ExecuteAsync()
End Sub
Public Sub ExecuteAsync()
'Run the Synchronous method on a new ThreadPool thread
ThreadPool.QueueUserWorkItem(AddressOf DoExecute)
End Sub
Public Sub Execute()
'First determine if the Web Service returned any Companies to save...
If NewCompanies.Companies.Count > 0 Then
NewCompanies.SubmitToDB(True)
If NewCompanies.Success Then
Success = True
Else
Success = False
ErrorVerb = "syncing companies"
ErrorMessage = NewCompanies.Message
End If
End If
IsBusy = False
End Sub
Private Sub DoExecute(ByVal stateInfo As Object)
'Call the Synchronous method on this ThreadPool thread
Execute()
End Sub
Private _newCompanies As Companies
Public Property NewCompanies() As Companies
Get
Return (_newCompanies)
End Get
Set(ByVal value As Companies)
_newCompanies = value
End Set
End Property
Private _success As Boolean
Public Property Success() As Boolean
Get
Return (_success)
End Get
Set(ByVal value As Boolean)
_success = value
End Set
End Property
Private _errVerb As String
Public Property ErrorVerb() As String
Get
Return (_errVerb)
End Get
Set(ByVal value As String)
_errVerb = value
End Set
End Property
Private _errMessage As String
Public Property ErrorMessage() As String
Get
Return (_errMessage)
End Get
Set(ByVal value As String)
_errMessage = value
End Set
End Property
Private _isBusy As Boolean
Public Property IsBusy() As Boolean
Get
Return (_isBusy)
End Get
Set(ByVal value As Boolean)
_isBusy = value
End Set
End Property
Private _doAsynchronously As Boolean
Public Property DoAsynchronously() As Boolean
Get
Return (_doAsynchronously)
End Get
Set(ByVal value As Boolean)
_doAsynchronously = value
End Set
End Property
Protected Sub Dispose()
service.Dispose()
End Sub
クラス終了
私の人生では、アプリケーションが Visual Studio Debugger を介してスムーズに実行される理由を理解できませんが、MC55A Motorola デバイスにインストールするとクラッシュします。アプリケーションはエミュレーターでも正常に動作します。
非同期 Web サービス呼び出しの 1 つを削除しようとしましたが、インストールされていれば問題なく動作しましたが、3 つ以上しようとすると失敗します。これは、アプリケーションがデバイスにインストールされたときのように、デフォルトの接続制限が無視され、2 に戻されます。
小説で申し訳ありませんが、Stackoverflowで同様の問題を見たので、十分な情報を提供したかっただけですが、これとまったく同じものはありません. 一度に 1 つの Web サービス接続のみを開いて、これらの呼び出しを同期的に実行できることは認識していますが、このアプリケーションをお客様にとって最速のものにする必要に迫られています。この初期同期操作を同期的に実行することはできますが、将来的には 2 つ以上の Web サービス接続を同時に実行する必要がある場所があることはわかっています。