実例で学ぶアプリケーション開発 ver.2 - サンプルアプリケーションのポイント(4)-Error Handling & Custom Update
皆様、こんにちは!実は私はこの連休と、明日からの数日間合わせて、遅い夏休みを取得しています。家庭でもやることは多々ありますがw、ブログやTwitterはタイミングを見て更新していきますので、よろしくお願いします。
Tech・Edを挟んでだいぶ間が空いてしまいましたが、本ソリューションサンプルの解説として、今回は、エラーハンドリングのところと、カスタム更新処理のところをご紹介します。順に、Server側(DomainService)でのエラーハンドリング、Client側(DomainDataSource/DomainContext)でのエラーハンドリング、そしSilverlight アプリケーションで発生した、ハンドルされていない例外の扱い、についてご説明します。そして、カスタム更新処理についても触れます。
エラーハンドリング
① DomainServiceでのエラーハンドリング
まずは、Server側(DomainService)でのエラーハンドリングです。
この点、本ソリューションサンプルでは明示的に実装していませんが、WCF RIA Services におけるDomainServiceのエラーハンドリングは、OnError メソッドをOverrideすることで実装が可能です。パラメータで受け渡される、DomainServiceErrorInfo クラスの Error プロパティで取得できる例外情報を、利用します。
サンプル: \MSStoreSample\MSStoreSample.Web\Services\MSStoreSampleDomainService.cs
protected override void OnError(DomainServiceErrorInfo errorInfo)
{
base.OnError(errorInfo);
}
次は、Client側(DomainDataSource/DomainContext)でのエラーハンドリングに移ります。
② Client側でのエラーハンドリング
(ア) ロードメソッドでのエラーハンドリング
非同期のコールバックメソッドのパラメータで受け渡される、LoadOperation(Of T) クラスのError プロパティで取得できる例外情報を、利用します。
private void ProductLoadOperationCompleted(LoadOperation<Products> loadOperation)
{
HandleException(loadOperation.Error);
}
(イ) DomainDataSource の LoadData イベントでのエラーハンドリング
DomainDataSource コントロールを追加するとコードビハインドファイルに DomainDataSource のLoadData イベントが追加され、標準で下記の実装が追加されます。この点は、Tech・Ed 2010のT6-401でもご紹介しました。
サンプル: \MSStoreSample\MSStoreSample\Views\Home.xaml.cs
private void categoriesDomainDataSource_LoadedData(object sender, LoadedDataEventArgs e)
{
if (e.HasError)
{
System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
e.MarkErrorAsHandled();
}
}
(ウ) 更新処理でのエラーハンドリング
更新処理は、Tech・Ed 2010のT6-401でもご紹介しました。この更新処理でのエラーハンドリングは、DomainContext クラスの SubmitChanges メソッドの非同期のコールバックメソッドで実装します。パラメータで受け渡される SubmitOperation クラスの Error プロパティで、例外情報を取得し、これを利用します。
サンプル: \MSStoreSample\MSStoreSample\Views\Basket.xaml.cs
/// <summary>
/// バスケットへの商品追加処理を実装します。
/// バスケットへの商品追加はドメインサービスでカスタムのビジネスロジックとして実装しています。
/// </summary>
/// <param name="basketItem"></param>
private void AddToBasket(BasketItems basketItem)
{
…
context.SubmitChanges(SubmitOperationCompleted, null);
}
/// <summary>
/// DomainContext を利用したデータ更新処理の完了処理を実装します。
/// ここではエラー発生時の処理としてエラーウィンドウの表示を実装します。
/// </summary>
/// <param name="operation"></param>
private void SubmitOperationCompleted(SubmitOperation operation)
{
if (operation.HasError)
{
operation.MarkErrorAsHandled();
Dispatcher.BeginInvoke(() =>
{
ErrorWindow.CreateNew(operation.Error);
});
}
…
}
Silverlight アプリケーションで発生した、ハンドルされていない例外の扱い
Silverlight アプリケーションで発生した、ハンドルされていない例外に関しては、Application クラスの UnhandledException イベントで一括してハンドルしています。実は、この機能は Silverlight Business Application テンプレートによって標準で提供されています。
サンプル: \MSStoreSample\MSStoreSample \App.Xaml.cs
public partial class App : Application
{
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
// If the app is running outside of the debugger then report the exception using
// a ChildWindow control.
if (!System.Diagnostics.Debugger.IsAttached)
{
// NOTE: This will allow the application to continue running after an exception has been thrown
// but not handled.
// For production applications this error handling should be replaced with something that will
// report the error to the website and stop the application.
e.Handled = true;
ErrorWindow.CreateNew(e.ExceptionObject);
}
}
}
カスタム更新処理の実装
さて、最後はカスタム更新処理の実装についてです。WCF RIA Services のDomainService ではエンティティに対する追加、更新、削除の処理を、拡張することが可能です。クライアントから、エンティティが変更された DomainContext クラスのインスタンスに対して SubmitChanges メソッドを呼び出すことで、DomainService の更新処理が実行されます。
ソリューションサンプルでは BasketItems エンティティの追加処理を変更し、認証済みのユーザーのバスケットに明細を追加する処理を実現しています。
public void InsertBasketItems(BasketItems basketItems)
{
basketItems.BasketItemId = Guid.NewGuid();
if ((basketItems.EntityState != EntityState.Detached))
{
this.ObjectContext.ObjectStateManager.ChangeObjectState(basketItems, EntityState.Added);
}
else
{
this.ObjectContext.BasketItems.AddObject(basketItems);
}
string userId = this.ServiceContext.User.Identity.Name;
Baskets basket = this.ObjectContext.Baskets.FirstOrDefault(b => b.Customers.UserId == userId);
…
}
以上です。いかがでしたでしょうか?本ソリューションサンプルにおける共通項としての解説は、次回(といっても今週中w)のクライアントアプリケーション側の解説迄です。その後、第3回から、第11回までの部分で、個別にコメントと解説をしていく予定です。よろしくお願いします。
ただし、このソリューションサンプルには、まだまだ”続き”があります。そこで、今後のことも拡張も念頭に置いて、今後もWCF RIA Services、MVVM等、そしてWindows Phone 7開発等のトピックについては、折に触れてご紹介していきたいと思っていますので、何卒よろしくお願いいたします。
鈴木 章太郎