Partager via


実例で学ぶアプリケーション開発 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開発等のトピックについては、折に触れてご紹介していきたいと思っていますので、何卒よろしくお願いいたします。

鈴木 章太郎