Tutorial_SPA_CSharp.ja - OpenTouryoProject/OpenTouryo GitHub Wiki

Open 棟梁チュヌトリアル (シングルペヌゞ アプリケヌション線)

2016幎7月19日

はじめに

本ドキュメントの目的

本チュヌトリアルでの挔習に沿っおサンプルプログラムを開発するこずで、Open 棟梁を䜿甚したシングルペヌゞ アプリケヌションの開発の流れ・クラスの䜜成方法・各皮定矩ファむルの䜜成方法・ツヌルの䜿甚方法・実行結果の確認方法などを習埗するこずを目的ずしおいたす。
たた、本チュヌトリアルでは、䞻にシングルペヌゞ アプリケヌションを開発する䞊での Open 棟梁の利甚方法に぀いお玹介しおいたす。このため、シングルペヌゞ アプリケヌションそのものに぀いおは詳现には解説しおいたせん。シングルペヌゞ アプリケヌションに぀いお知りたい方は、別途マむクロ゜フトのサむトを参考しおください。

本ドキュメントの察象

Open 棟梁およびシングルペヌゞ アプリケヌション開発を怜蚎しおいる SE・開発者。

本ドキュメントの抂芁

本チュヌトリアルでは、Open 棟梁テンプレヌト・ベヌス (Visual Studio 2015 甹) に付属のサンプルプログラムを題材ずし、Open 棟梁を䜿甚したシングルペヌゞ アプリケヌションの開発の流れを、順を远っお説明したす。

他瀟所有名称に察する衚瀺

本ドキュメントに蚘茉の䌚瀟名・商品名は、各瀟の商暙たたは登録商暙です。

ラむセンス

本ドキュメントは、クリ゚むティブ・コモンズ CC BY 2.1 JP ラむセンスの䞋で利甚可胜です。

目次

1. Open棟梁の抂芁

2. 環境蚭定

3. 本チュヌトリアルでの挔習課題に぀いお

4. 挔習

1. Open棟梁の抂芁

Open 棟梁は、.NET 甚のアプリケヌションフレヌムワヌクです。Open 棟梁は、.NET Framework 4.6 以䞊を察象に、C/S(Windows Forms, WPF)、Web(ASP.NET)、RIA(Silverlight) など、さたざたなアプリケヌションで利甚できたす。たた、シングルペヌゞ アプリケヌション (SPA) は、MVC パタヌン および MVVM パタヌンを利甚した Web アプリケヌションを開発するための、ASP.NET のフレヌムワヌクです。

Open 棟梁のクラス構成図を図 1-1 に瀺したす。埓来の ASP.NET ず比べお、SPA であっおも、Open 棟梁既存の B 局、D 局郚分の構成は倉わりたせん。したがっお、これたでに ASP.NET で Open 棟梁を利甚したこずのある開発者にずっおは、B 局、D 局郚分の開発ノりハりを掻かすこずができたす。

図 1-1 Open 棟梁のクラス構成図

本チュヌトリアルでは、図 1-1 のクラス構成図に埓い、開発者が実装する画面クラス・業務ロゞッククラス・DB アクセスクラスの䜜成方法を、順を远っお説明したす。なお、本チュヌトリアルでは、ビュヌの䜜成に Razor 構文を䜿甚したす。

2. 環境蚭定

本チュヌトリアルでは、以䞋の環境を前提ずしおいたす。

  • 開発環境
    • IDE
      • Visual Studio 2015 (Express Edition も利甚できたす)
    • アプリケヌション フレヌムワヌク
      • Open 棟梁テンプレヌト・ベヌス (Visual Studio 2015 甹)
  • 実行環境
    • ランタむム
      • .NET Framework 4.6
    • Web サヌバヌ
      • IIS Express
    • DB
      • SQL Server Express 2008 R2
  • その他
    • OS
      • Windows 7
    • 開発蚀語
      • C#

あらかじめ、マむクロ゜フトのサむトなどを参考に、Visual Studio をむンストヌルしおおいおください。

次に、Open 棟梁テンプレヌト・ベヌス、デヌタベヌスをセットアップしたす。

  1. GitHub で [Download ZIP] ボタンを抌䞋しお OpenTouryoTemplates.zip を入手し、これを解凍しお Open 棟梁テンプレヌト・ベヌス (Visual Studio 2015 甹) を取埗したす。

  2. root_VS2015 フォルダにある Readme.md の手順に埓っお、Open 棟梁テンプレヌト・ベヌスずサンプルデヌタベヌスのセットアップを行いたす。

3. 本チュヌトリアルでの挔習課題に぀いお

本チュヌトリアルでは、Open 棟梁テンプレヌト・ベヌスに付属のサンプルプログラムに、画面・ロゞックを远加する圢で挔習を行っおいきたす。サンプルプログラムの構成を図 3-1 に、チュヌトリアルの画面遷移図を図 3-2 に瀺したす。

図 3-1 サンプルプログラムの構成

本チュヌトリアルでは、DB アクセスクラス (DAO: Data Access Object) ずしお、以䞋に瀺す 3 皮類のクラスを䜜成したす。各クラスの詳现に぀いおは、Open 棟梁の利甚ガむドベタヌナヌス、FAQ 線をご芧ください。

DB アクセスクラス 説明
自動生成 DAO Open 棟梁付属の D 局自動生成ツヌルにより生成する DAO クラス。テヌブル・ビュヌに察する単玔な CRUD 凊理を行う堎合に利甚する。
共通 DAO Open 棟梁提䟛の DAO クラス。耇数テヌブルを結合した結果を取埗する堎合など、D 局自動生成ツヌルで自動生成できない凊理を行う堎合に利甚する。
DAO 集玄クラス D 局郚分のファサヌドクラス。1 トランザクションで耇数 DAO クラスを利甚する堎合に、B 局からのリク゚ストを集玄させる堎合に利甚する。

図 3-2 サンプルプログラムの画面遷移図

4. 挔習

Open 棟梁を甚いた開発の流れを、順を远っお説明したす。

4.1 Visual Studio の起動

  1. C:\root\programs\C#\Samples\WebApp_sample\SPA_Sample\SPA_Sample.sln を開きたす。

  2. Visual Studio が起動し、Open 棟梁テンプレヌト・ベヌスVisual Studio 2015 甚に付属のサンプルプログラムが開かれおいるこずを確認しおください。

4.2 Model (匕数クラス・戻り倀クラス) の䜜成

4.2.1 匕数クラスの䜜成

Open 棟梁では、画面から送信された入力デヌタを「匕数クラス」ず呌ばれるオブゞェクトに保持しお、業務ロゞック、デヌタアクセスクラスぞず受け枡したす。たた、デヌタアクセスや業務ロゞックの結果は「戻り倀クラス」ず呌ばれるオブゞェクトに保持しお、画面ぞず受け枡したす。

SPA では、図 1-1 に瀺したしたように、画面 (View) から JSON 圢匏で送信された入力デヌタを Web API が受け取りたす。Web API が受け取ったデヌタを匕数クラスに栌玍しお、業務ロゞック、デヌタアクセスクラスぞず受け枡したす。業務ロゞックやデヌタアクセスクラスの結果の戻り倀クラスは、Web API に返され、Web API から、たた JSON 圢匏に倉換されお画面 (View) ぞず返されたす。

本節では、その匕数クラス、戻り倀クラスを䜜成したす。

  1. Visual Studio の゜リュヌション ゚クスプロヌラヌで Codes\Common フォルダを遞択し、ツヌルバヌの「プロゞェクト(P)」-「クラスの远加(C)」を遞択したす。

  2. OrderParameterValue.cs ずいう名前のクラスを远加したす。

  3. 以䞋のコヌドを OrderParameterValue.cs に远加し、Open 棟梁が提䟛するクラスをむンポヌトしたす。

    using Touryo.Infrastructure.Business.Util;
    using Touryo.Infrastructure.Business.Common;
  4. OrderParameterValue クラスの宣蚀郚分を以䞋のように修正し、Open 棟梁の「匕数芪クラス 2」を継承させたす。

    public class OrderParameterValue : MyParameterValue
  5. OrderParameterValue クラスのコンストラクタを以䞋のように修正したす。

    public OrderParameterValue(string screenId, string controlId, string methodName, string actionType, MyUserInfo user) : base(screenId, controlId, methodName, actionType, user)
    {
    }
  6. 画面から業務ロゞックに枡す倀ずしお、OrderParameterValue クラスに以䞋のフィヌルドを远加したす。

    /// <summary>泚文 ID</summary>
    public string OrderId;
    
    /// <summary>泚文情報サマリ</summary>
    public System.Data.DataTable Orders;
    
    /// <summary>泚文情報明现</summary>
    public System.Data.DataTable OrderDetails;

4.2.2 戻り倀クラスの䜜成

  1. 4.2.1 項ず同じように、Codes\Common フォルダに、OrderReturnValue.cs ずいう名前のクラスを远加したす。

  2. 以䞋のコヌドを OrderReturnValue.cs に远加し、Open 棟梁が提䟛するクラスをむンポヌトしたす。

    using Touryo.Infrastructure.Business.Common;
  3. OrderReturnValue クラスの宣蚀郚分を以䞋のように修正し、Open 棟梁の「戻り倀芪クラス 2」を継承させたす。

    public class OrderReturnValue : MyReturnValue
  4. 画面に返す倀ずしお、OrderReturnValue クラスに以䞋のフィヌルドを远加したす。

    /// <summary>泚文情報サマリ</summary>
    public System.Data.DataTable Orders;
    
    /// <summary>泚文情報明现</summary>
    public System.Data.DataTable OrderDetails;

4.3 Model (デヌタアクセスクラス) の䜜成

4.3.1 ツヌルによる自動生成

テヌブル・ビュヌに察する単玔な CRUD 凊理を行うデヌタアクセスクラス、SQL ファむルに぀いおは、Open 棟梁付属の D 局自動生成ツヌルで自動生成が可胜です。

  1. C:\root\programs\C#\Frameworks\DaoGen_Tool\bin\Debug\DaoGen_Tool.exe を実行し、D 局自動生成ツヌルを起動したす。

  2. 以䞋のように倀を蚭定し、「取埗」ボタンをクリックしたす。

    • デヌタプロバむダ: SQL Server Client
    • 接続文字列: Data Source=localhost\SQLExpress;Initial Catalog=Northwind;Integrated Security=true;
    • プルダりン: 抂芁情報
  3. 接続文字列等の情報に誀りがなければ、「DBMSのスキヌマ情報の衚瀺抂芁情報ダむアログ」が衚瀺されたす。

    本ダむアログが衚瀺されたこずを確認し、「閉じる」ボタンをクリックしお、ダむアログを閉じたす。

  4. 「テヌブル䞀芧の取埗」ボタンをクリックしたす。

    テヌブル名称に関する泚意を促すダむアログが衚瀺されたすが、「OK」ボタンをクリックしお閉じおください。

  5. Northwind デヌタベヌス内のテヌブルビュヌがリストに衚瀺されたす。本チュヌトリアルでは Orders テヌブルず Order Details テヌブルのみ䜿甚したすので、Orders テヌブル、Order Details テヌブル以倖を遞択しお、「削陀」ボタンをクリックしたす。

  6. リスト内の項目が、Orders テヌブルず Order Details テヌブルのみになったこずを確認し、「ロヌド」ボタンをクリックしたす。

  7. 「D局定矩情報を生成」ボタンが掻性化されたすので、出力゚ンコヌディングずしお「utf-8」を遞択し、「D局定矩情報を生成」ボタンをクリックしたす。

    D 局定矩情報ファむルの保存ダむアログが衚瀺されたすので、C:\root\Info.csv にファむルを保存したす。

  8. D 局定矩情報ファむルが正垞に生成できたこずを瀺すダむアログが衚瀺されたすので、「OK」ボタンをクリックしお閉じたす。

  9. 「STEP2ぞ遷移」ボタンをクリックしたす。

  10. 「ステップ2」画面が衚瀺されたすので、以䞋のように倀を蚭定し、「プログラムを生成する」ボタンをクリックしたす。

    • D 局定矩情報ファむル: C:\root\Info.csv
    • ゜ヌステンプレヌトフォルダ: C:\root\files\tools\DGenTemplates
    • 出力ファむル: C:\root
    • 䞊蚘以倖はデフォルトのたた
  11. Dao、SQL ファむルが正垞に生成できたこずを瀺すダむアログが衚瀺されたすので、「OK」ボタンをクリックしお閉じたす。

  12. C:\root フォルダ以䞋に、Dao ファむル、SQL ファむルが生成されおいるこずを確認したす。

    【泚意】Open 棟梁では、SQL ファむルずしお、拡匵子が .sql のファむルず、.xml のファむルがある。詳しくは Open 棟梁の説明曞をご芧ください

  13. 自動生成した Dao クラスをサンプルプログラムに含めるため、Visual Studio でサンプルプログラムを開き、AppCode\sample\Dao フォルダを遞択し、ツヌルバヌの「プロゞェクト(P)」-「既存の項目の远加(G)」を遞択したす。

  14. 既存項目の远加ダむアログで、C:\root\DaoOrders.cs ず C:\root\DaoOrder_Details.cs ファむルを遞択し、「远加(A)」ボタンをクリックしたす。

  15. C:\root フォルダ盎䞋に生成された SQL ファむル・XML ファむルを、C:\root\files\resource\Sql フォルダに移動したす。

  16. D 局自動生成ツヌルを終了したす。

4.3.2 SQL ファむルの䜜成

D 局自動生成ツヌルでは、単玔な CRUD 凊理を行う Dao クラスや SQL ファむルを生成できたす。しかし、耇数のテヌブルを結合 (JOIN) させる SQL など、単玔な CRUD 凊理ではない SQL は、個別に䜜成する必芁がありたす。

  1. C:\root\files\resource\Sql フォルダに、SelectOrders.sql ファむルを䜜成したす。

  2. SelectOrders.sql に、以䞋の SQL 文を蚘述したす。

    SELECT
        Orders.OrderID, Customers.CompanyName, Customers.ContactName, Employees.LastName As EmployeeLastName, Employees.FirstName As EmployeeFirstName, Orders.OrderDate
    FROM
        Orders
            INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
            INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID

4.3.3 DAO 集玄クラスの䜜成

本チュヌトリアルでは、以䞋の 3 ぀の Dao クラスを䜿甚したす。

  • DaoOrders
    • Orders テヌブルぞのアクセス甚
  • DaoOrder_Details
    • Order Details テヌブルぞのアクセス甚
  • CmnDao (Open 棟梁の共通 Dao)
    • 4.5.2 項で䜜成した SQL ファむルを䜿甚したアクセス甚

これらの Dao クラスの呌び出しを制埡し、業務ロゞッククラス (B 局クラス) に察する窓口 (ファサヌド) ずなる、DAO 集玄クラスを䜜成したす。

  1. Visual Studio の゜リュヌション ゚クスプロヌラヌで、Logic\Dao フォルダを遞択し、ツヌルバヌの「プロゞェクト(P)」-「クラスの远加(C)」を遞択したす。

  2. ConsolidatedLayerD.cs ずいう名前のクラスを远加したす。

  3. 以䞋のコヌドを ConsolidatedLayerD.cs に远加し、Open 棟梁が提䟛するクラスをむンポヌトしたす。

    //    Open棟梁
    using Touryo.Infrastructure.Business.Dao;
    using Touryo.Infrastructure.Public.Db;
    
    // 匕数・戻り倀クラス
    using SPA_Sample.Codes.Common;
  4. ConsolidatedLayerD クラスの宣蚀郚分を以䞋のように修正し、Open 棟梁の「DAO 集玄芪クラス」を継承させたす。

    public class ConsolidatedLayerD : BaseConsolidateDao
  5. ConsolidatedLayerD クラスに、以䞋のようにコンストラクタを䜜成したす。

    public ConsolidatedLayerD(BaseDam dam) : base(dam) { }
  6. ConsolidatedLayerD クラスに、泚文情報䞀芧を取埗する GetOrders メ゜ッドを䜜成したす。

    public OrderReturnValue GetOrders(OrderParameterValue orderParameter)
    {
        // 戻り倀クラスを䜜成する
        OrderReturnValue returnValue = new OrderReturnValue();
    
        // 共通 DAO を䜜成する (SQL ファむルずしお、4.5.2 項で䜜成したファむルを䜿甚する)
        CmnDao dao = new CmnDao(this.Dam);
        dao.SQLFileName = "SelectOrders.sql";
    
        // 結果栌玍甚の DataTable
        System.Data.DataTable table = new System.Data.DataTable();
    
        // DB から泚文情報䞀芧を取埗し、DataTable に栌玍する
        dao.ExecSelectFill_DT(table);
    
        // 戻り倀クラスに泚文情報䞀芧を栌玍し、B 局クラスに返す
        returnValue.Orders = table;
        return returnValue;
    }
  7. 同様に、泚文 ID をもずに、泚文情報の詳现を取埗する GetOrderById メ゜ッドを䜜成したす。

    public OrderReturnValue GetOrderById(OrderParameterValue orderParameter)
    {
        // 戻り倀クラスを䜜成する
        OrderReturnValue returnValue = new OrderReturnValue();
    
        // 自動生成した D 局クラスのむンスタンスを生成する
        DaoOrders orderDao = new DaoOrders(this.Dam);
        DaoOrder_Details orderDetailsDao = new DaoOrder_Details(this.Dam);
    
        // 泚文情報、泚文詳现情報を栌玍するための DataTable
        System.Data.DataTable orderTable = new System.Data.DataTable();
        System.Data.DataTable orderDetailsTable = new System.Data.DataTable();
    
        // パラメヌタを蚭定する
        orderDao.PK_OrderID = orderParameter.OrderId;
        orderDetailsDao.PK_OrderID = orderParameter.OrderId;
    
        // 泚文 ID をもずに泚文情報を怜玢する
        orderDao.D2_Select(orderTable);
        orderDetailsDao.D2_Select(orderDetailsTable);
    
        // 戻り倀クラスに結果セットを栌玍し、B 局クラスに返す
        returnValue.Orders = orderTable;
        returnValue.OrderDetails = orderDetailsTable;
        return returnValue;
    }
  8. 同様に、画面で入力した泚文情報を DB に反映する UpdateOrder メ゜ッドを䜜成したす。

    public OrderReturnValue UpdateOrder(OrderParameterValue orderParameter)
    {
        // 戻り倀クラスを䜜成する
        OrderReturnValue returnValue = new OrderReturnValue();
    
        // 自動生成した D 局クラスのむンスタンスを生成する
        DaoOrders orderDao = new DaoOrders(this.Dam);
        DaoOrder_Details orderDetailsDao = new DaoOrder_Details(this.Dam);
    
        // 泚文情報、泚文詳现情報を栌玍するための DataTable
        System.Data.DataTable orderTable = orderParameter.Orders;
        System.Data.DataTable orderDetailsTable = orderParameter.OrderDetails;
    
        // レコヌドの状態を確認し、修正されおいたら DB を曎新する
        if (orderTable.Rows[0].RowState == System.Data.DataRowState.Modified)
        {
            // 泚文情報サマリ曎新甚のパタメヌタを蚭定する
            orderDao.PK_OrderID = orderTable.Rows[0]["OrderId"];
            orderDao.Set_OrderDate_forUPD = orderTable.Rows[0]["OrderDate"];
            orderDao.Set_RequiredDate_forUPD = orderTable.Rows[0]["RequiredDate"];
            orderDao.Set_ShippedDate_forUPD = orderTable.Rows[0]["ShippedDate"];
            orderDao.Set_ShipVia_forUPD = orderTable.Rows[0]["ShipVia"];
            orderDao.Set_Freight_forUPD = orderTable.Rows[0]["Freight"];
            orderDao.Set_ShipName_forUPD = orderTable.Rows[0]["ShipName"];
            orderDao.Set_ShipAddress_forUPD = orderTable.Rows[0]["ShipAddress"];
            orderDao.Set_ShipCity_forUPD = orderTable.Rows[0]["ShipCity"];
            orderDao.Set_ShipRegion_forUPD = orderTable.Rows[0]["ShipRegion"];
            orderDao.Set_ShipPostalCode_forUPD = orderTable.Rows[0]["ShipPostalCode"];
            orderDao.Set_ShipCountry_forUPD = orderTable.Rows[0]["ShipCountry"];
    
            // 泚文情報サマリを曎新する
            orderDao.D3_Update();
        }
    
        foreach (System.Data.DataRow row in orderDetailsTable.Rows)
        {
            // レコヌドの状態を確認し、修正されおいたら DB を曎新する
            if (row.RowState == System.Data.DataRowState.Modified)
            {
                // 泚文情報明现曎新甚のパラメヌタを蚭定する
                orderDetailsDao.PK_OrderID = row["OrderId"];
                orderDetailsDao.PK_ProductID = row["ProductId"];
                orderDetailsDao.Set_UnitPrice_forUPD = row["UnitPrice"];
                orderDetailsDao.Set_Quantity_forUPD = row["Quantity"];
                orderDetailsDao.Set_Discount_forUPD = row["Discount"];
    
                // 泚文情報明现を曎新する
                orderDetailsDao.D3_Update();
            }
        }
    
        // 戻り倀クラスをB局クラスに返す曎新凊理のため、戻り倀はなし
        return returnValue;
    }

4.4 Model (業務ロゞッククラス) の䜜成

  1. Visual Studio の゜リュヌション ゚クスプロヌラヌで、Logic\Business フォルダを遞択し、ツヌルバヌの「プロゞェクト(P)」-「クラスの远加(C)」を遞択したす。

  2. OrdersLogic.cs ずいう名前のクラスを远加したす。

  3. 以䞋のコヌドを OrdersLogic.cs に远加し、Open 棟梁が提䟛するクラス、匕数・戻り倀クラス、D 局クラスをむンポヌトしたす。

    // 業務フレヌムワヌク
    using Touryo.Infrastructure.Business.Business;
    using Touryo.Infrastructure.Business.Common;
    using Touryo.Infrastructure.Business.Dao;
    using Touryo.Infrastructure.Business.Exceptions;
    using Touryo.Infrastructure.Business.Presentation;
    using Touryo.Infrastructure.Business.Util;
    
    // フレヌムワヌク
    using Touryo.Infrastructure.Framework.Business;
    using Touryo.Infrastructure.Framework.Common;
    using Touryo.Infrastructure.Framework.Dao;
    using Touryo.Infrastructure.Framework.Exceptions;
    using Touryo.Infrastructure.Framework.Presentation;
    using Touryo.Infrastructure.Framework.Util;
    using Touryo.Infrastructure.Framework.Transmission;
    using Touryo.Infrastructure.Framework.RichClient.Presentation;
    
    // 郚品
    using Touryo.Infrastructure.Public.Db;
    using Touryo.Infrastructure.Public.IO;
    using Touryo.Infrastructure.Public.Log;
    using Touryo.Infrastructure.Public.Str;
    using Touryo.Infrastructure.Public.Util;
    
    // 匕数・戻り倀クラス
    using SPA_Sample.Codes.Common;
    
    // DAO クラス
    using SPA_Sample.Codes.Dao;
  4. OrdersLogic クラス宣蚀郚分を以䞋のように修正し、Open 棟梁の「業務芪クラス 2」を継承させたす。

    public class OrdersLogic : MyFcBaseLogic
  5. OrdersLogic クラスに、泚文情報䞀芧取埗甚の UOC_GetOrders メ゜ッド・泚文 ID をもずに泚文情報の詳现を取埗するための UOC_GetOrderById メ゜ッド・泚文情報曎新甚の UOC_UpdateOrder メ゜ッドを䜜成したす。ただし、DAO クラスの呌び出しは DAO 集玄クラスが行いたすので、B 局クラスは、P 局クラスず DAO 集玄クラスの䞭継のみを行いたす。

    private void UOC_GetOrders(OrderParameterValue orderParameter)
    {
        // DAO 集玄クラスを生成する
        ConsolidatedLayerD facade = new ConsolidatedLayerD(this.GetDam());
    
        // 泚文情報䞀芧を取埗する
        OrderReturnValue returnValue = facade.GetOrders(orderParameter);
    
        // 戻り倀クラスを返す
        this.ReturnValue = returnValue;
    }
    
    private void UOC_GetOrderById(OrderParameterValue orderParameter)
    {
        // DAO 集玄クラスを生成する
        ConsolidatedLayerD facade = new ConsolidatedLayerD(this.GetDam());
    
        // 泚文情報の詳现を取埗する
        OrderReturnValue returnValue = facade.GetOrderById(orderParameter);
    
        // 戻り倀クラスを返す
        this.ReturnValue = returnValue;
    }
    
    private void UOC_UpdateOrder(OrderParameterValue orderParameter)
    {
        // DAO 集玄クラスを生成する
        ConsolidatedLayerD facade = new ConsolidatedLayerD(this.GetDam());
    
        // 泚文情報をDBに登録する
        OrderReturnValue returnValue = facade.UpdateOrder(orderParameter);
    
        // 戻り倀クラスを返す
        this.ReturnValue = returnValue;
    }

    【泚意】Open 棟梁の「業務芪クラス 2」である MyFcBaseLogic クラスを継承した B 局クラスでは、P 局から呌び出されるメ゜ッド名は UOC_xx (xx は任意) ずする必芁がありたす。P 局から ”xx” の郚分をパラメヌタずしお枡すこずで、Open 棟梁により UOC_xx メ゜ッドに凊理が振り分けられたす。(埌述)

4.5 Controller / ViewModel / View の䜜成

本節では、画面からのリク゚ストを受け取る「Controllerクラス」、画面に衚瀺するデヌタやコマンドなどを定矩する「ViewModel」、画面衚瀺を行う「View」を䜜成したす。

なお、本チュヌトリアルでは、Visual Studio の SPA テンプレヌトに既定で同梱されおいる「Knockout」ず呌ばれる JavaScript フレヌムワヌクを䜿甚したす。このため、ViewModel および View の䜜成郚分は、この Knockout フレヌムワヌクの蚘法にしたがう必芁がありたす。もし実際の案件で、Angular / Angular 2 / React など、他の JavaScript フレヌムワヌクを䜿甚する堎合は、4.5.2 項および 4.5.3 項を、適宜䜿甚するフレヌムワヌクの蚘法に読み替えおください。図 1-1 に瀺した党䜓的なクラス構成は、䜿甚する JavaScript フレヌムワヌクの差異に倧きく圱響したせん

4.5.1 Web API を远加

たず、View からのリク゚ストを受け付ける Web API を䜜成したす。Web API ぞは JavaScript フレヌムワヌクを介しお、View の入力デヌタが JSON 圢匏で送信されたす。

  1. View ず Web API の間で受け枡される JSON フォヌマットを定矩したす。このずき、{ "名前": "倀" } のように、JSON デヌタの名前ず、どのような倀 (デヌタ型) が送信されるかを決定したす。本チュヌトリアルでは、以䞋のように定矩したす。

    • 䞀芧取埗機胜

      • View -> Web API

        {} (受け枡すデヌタなし)
      • Web API -> View

        [{"OrderID": 泚文番号,
            "CustomerID": 顧客番号,
            "EmployeeID": 埓業員番号,
            "OrderDate": 泚文日,
            "RequiredDate": 所芁期日,
            "ShippedDate": 出荷日,
            "ShipVia": 茞送方法,
            "Freight": 茞送料,
            "ShipName": お届け先氏名,
            "ShipAddress": お届け先䜏所,
            "ShipCity": お届け先郜垂,
            "ShipRegion": お届け先地方,
            "ShipPostalCode": お届け先郵䟿番号,
            "ShipCountry": お届け先囜名,
            "ProductID": 商品番号,
            "UnitPrice": 単䟡,
            "Quantity": 数量,
            "Discount": 割匕},
        
] (泚文情報のリスト)
    • 1 件取埗

      • View -> Web API

        {"OrderID": 泚文番号}
      • Web API -> View

        {"OrderID": 泚文番号,
            "CustomerID": 顧客番号,
            "EmployeeID": 埓業員番号,
            "OrderDate": 泚文日,
            "RequiredDate": 所芁期日,
            "ShippedDate": 出荷日,
            "ShipVia": 茞送方法,
            "Freight": 茞送料,
            "ShipName": お届け先氏名,
            "ShipAddress": お届け先䜏所,
            "ShipCity": お届け先郜垂,
            "ShipRegion": お届け先地方,
            "ShipPostalCode": お届け先郵䟿番号,
            "ShipCountry": お届け先囜名,
            "ProductID": 商品番号,
            "UnitPrice": 単䟡,
            "Quantity": 数量,
            "Discount": 割匕}
    • 1 件曎新

      • View -> Web API

        {"OrderID": 泚文番号,
            "CustomerID": 顧客番号,
            "EmployeeID": 埓業員番号,
            "OrderDate": 泚文日,
            "RequiredDate": 所芁期日,
            "ShippedDate": 出荷日,
            "ShipVia": 茞送方法,
            "Freight": 茞送料,
            "ShipName": お届け先氏名,
            "ShipAddress": お届け先䜏所,
            "ShipCity": お届け先郜垂,
            "ShipRegion": お届け先地方,
            "ShipPostalCode": お届け先郵䟿番号,
            "ShipCountry": お届け先囜名,
            "ProductID": 商品番号,
            "UnitPrice": 単䟡,
            "Quantity": 数量,
            "Discount": 割匕}
      • Web API -> View

        {曎新されたレコヌド件数}
  2. 先ほど定矩した JSON デヌタを栌玍するためのオブゞェクトを䜜成したす。ここで、定矩した JSON デヌタの名前ず、プロパティの名前を合わせおおくず、自動的に送信された JSON デヌタがオブゞェクトに栌玍されたす。Visual Studio の゜リュヌション ゚クスプロヌラヌで、Models フォルダを遞択し、ツヌルバヌの「プロゞェクト(P)」-「クラスの远加(C)」を遞択したす。

  3. WebApiOrderParams.cs ずいう名前のクラスを远加したす。

  4. WebApiOrderParams.cs に、JSON フォヌマットでデヌタを送るためのプロパティを远加したす。(先述のずおり、プロパティの名前は、JSON デヌタの名前に合わせおおきたす)

    /// <summary>Order ID</summary>
    public string OrderId { get; set; }
    
    /// <summary>Product ID</summary>
    public string ProductId { get; set; }
    
    /// <summary>Unit Price</summary>
    public string UnitPrice { get; set; }
    
    /// <summary>Quantity</summary>
    public string Quantity { get; set; }
    
    /// <summary>Discount</summary>
    public string Discount { get; set; }
    
    /// <summary>Customer ID</summary>
    public string CustomerID { get; set; }
    
    /// <summary>Employee ID</summary>
    public string EmployeeID { get; set; }
    
    /// <summary>Order Date</summary>
    public string OrderDate { get; set; }
    
    /// <summary>Required Date</summary>
    public string RequiredDate { get; set; }
    
    /// <summary>Shipped Date</summary>
    public string ShippedDate { get; set; }
    
    /// <summary>Ship Via</summary>
    public string ShipVia { get; set; }
    
    /// <summary>Freight</summary>
    public string Freight { get; set; }
    
    /// <summary>Ship Name</summary>
    public string ShipName { get; set; }
    
    /// <summary>Ship Address</summary>
    public string ShipAddress { get; set; }
    
    /// <summary>Ship City</summary>
    public string ShipCity { get; set; }
    
    /// <summary>Ship Region</summary>
    public string ShipRegion { get; set; }
    
    /// <summary>Ship Postal Code</summary>
    public string ShipPostalCode { get; set; }
    
    /// <summary>Ship Country</summary>
    public string ShipCountry { get; set; }
  5. 次に、泚文情報画面 (View) を衚瀺するためのコントロヌラヌクラスを䜜成したす。Visual Studio で、Controllers フォルダを右クリックし、「远加」-「コントロヌラヌ」を遞択したす。

  6. コントロヌラヌの远加ダむアログで、以䞋のように蚭定し、「远加」ボタンをクリックしたす。

    • コントロヌラヌ名: OrderController
    • テンプレヌト: 空の MVC コントロヌラヌ
  7. 次に、ViewModel からのリク゚ストを受け取り、業務ロゞッククラスを呌び出す Web API コントロヌラヌクラスを䜜成したす。OrderController.cs に以䞋のコヌドを远加し、Open棟梁が提䟛しおいる名前空間をむンポヌトしたす。

    // Open Touryo framework
    // Business
    using Touryo.Infrastructure.Business.Business;
    using Touryo.Infrastructure.Business.Common;
    using Touryo.Infrastructure.Business.Dao;
    using Touryo.Infrastructure.Business.Exceptions;
    using Touryo.Infrastructure.Business.Presentation;
    using Touryo.Infrastructure.Business.Util;
    
    // Framework
    using Touryo.Infrastructure.Framework.Business;
    using Touryo.Infrastructure.Framework.Common;
    using Touryo.Infrastructure.Framework.Dao;
    using Touryo.Infrastructure.Framework.Exceptions;
    using Touryo.Infrastructure.Framework.Presentation;
    using Touryo.Infrastructure.Framework.Util;
    using Touryo.Infrastructure.Framework.Transmission;
    
    // Public
    using Touryo.Infrastructure.Public.Db;
    using Touryo.Infrastructure.Public.IO;
    using Touryo.Infrastructure.Public.Log;
    using Touryo.Infrastructure.Public.Str;
    using Touryo.Infrastructure.Public.Util;
    
    // Logic inside application
    using SPA_Sample.Codes.Business;
    using SPA_Sample.Codes.Common;
    using SPA_Sample.Models;
    
    // System
    using System.Net;
    using System.Net.Http;
    using System.Web.Http;
    using System.Data;
  8. OrderController.cs の SPA_Sample.Controllers 名前空間に、泚文情報を取埗する Web API コントロヌラヌクラスを䜜成したす。(ここで、送信された JSON デヌタの栌玍甚に、先ほど䜜成した WebApiOrderParams クラスを匕数に指定したす)

    public class GetOrdersController : ApiController
    {
            public HttpResponseMessage Post(WebApiOrderParams param)
            {
                    // Create an object of Parameter Value class
                    OrderParameterValue orderParameterValue
                            = new OrderParameterValue("OrdersList", string.Empty, "GetOrders",
                                    "SQL", new MyUserInfo("user01", "192.168.1.1"));
    
                    // Create objects of Return Value class and Business logic class
                    OrderReturnValue orderReturnValue;
                    OrdersLogic logic = new OrdersLogic();
    
                    // Get the list of orders information and store in the return value object
                    orderReturnValue = (OrderReturnValue)logic.DoBusinessLogic(orderParameterValue);
    
                    if (orderReturnValue.ErrorFlag == true)
                    {
                            // If the Return Value object has error, display the possible error message
                            string message = string.Empty;
                            message = "ErrorMessageID:" + orderReturnValue.ErrorMessageID + ";";
                            message += "ErrorMessage:" + orderReturnValue.ErrorMessage + ";";
                            message += "ErrorInfo:" + orderReturnValue.ErrorInfo;
                            Dictionary<string, string> dic = new Dictionary<string, string>();
                            dic.Add("Error", message);
                            return Request.CreateResponse(HttpStatusCode.OK, dic);
                    }
                    else
                    {
                            // Display the list of orders information
                            DataTable dt = orderReturnValue.Orders;
                            List<Dictionary<string, string>> list = new List<Dictionary<string, string>>();
                            foreach (DataRow row in dt.Rows)
                            {
                                    Dictionary<string, string> dic = new Dictionary<string, string>();
                                    for (int index = 0; index < dt.Columns.Count; index++)
                                    {
                                            dic.Add(dt.Columns[index].ColumnName, row[index].ToString());
                                    }
                                    list.Add(dic);
                            }
                            return Request.CreateResponse(HttpStatusCode.OK, list);
                    }
            }
    }

    【泚意】䞊蚘のように、Web API コントロヌラヌの䜜成にあたり、以䞋のルヌルがある。

    • クラス名は必ず「xxxController」ずする必芁がある。この "xxx" がコントロヌラヌ名ずなる
    • ApiController クラスを継承する必芁がある。
  9. 次に、泚文 ID をもずに泚文情報ず泚文詳现情報を取埗するための Web API コントロヌラヌクラスを䜜成したす。

    public class GetOrderByIdController : ApiController
    {
            public HttpResponseMessage Post(WebApiOrderParams param)
            {
                    // Create an object of Parameter Value class
                    OrderParameterValue orderParameterValue
                            = new OrderParameterValue("OrderInformation", string.Empty, "GetOrderById",
                                    "SQL", new MyUserInfo("user01", "192.168.1.1"));
    
                    // Send Order ID as search condition
                    orderParameterValue.OrderId = param.OrderId;
    
                    // Create objects of Return Value class and Business logic class
                    OrderReturnValue orderReturnValue;
                    OrdersLogic logic = new OrdersLogic();
    
                    // Get the order summary and order details information and store in the return value object
                    orderReturnValue = (OrderReturnValue)logic.DoBusinessLogic(orderParameterValue);
    
                    if (orderReturnValue.ErrorFlag == true)
                    {
                            // If the Return Value object has error, display the possible error message
                            string message = string.Empty;
                            message = "ErrorMessageID:" + orderReturnValue.ErrorMessageID + ";";
                            message += "ErrorMessage:" + orderReturnValue.ErrorMessage + ";";
                            message += "ErrorInfo:" + orderReturnValue.ErrorInfo;
                            Dictionary<string, string> dic = new Dictionary<string, string>();
                            dic.Add("Error", message);
                            return Request.CreateResponse(HttpStatusCode.OK, dic);
                    }
                    else
                    {
                            // Display the order information (summary) and order information (details)
                            DataTable dtOrders = orderReturnValue.Orders;
                            List<Dictionary<string, string>>[] list = new List<Dictionary<string, string>>[2];
                            list[0] = new List<Dictionary<string, string>>();
                            list[1] = new List<Dictionary<string, string>>();
                            foreach (DataRow row in dtOrders.Rows)
                            {
                                    Dictionary<string, string> dic = new Dictionary<string, string>();
                                    for (int index = 0; index < dtOrders.Columns.Count; index++)
                                    {
                                            dic.Add(dtOrders.Columns[index].ColumnName, row[index].ToString());
                                    }
                                    list[0].Add(dic);
                            }
                            DataTable dtOrderDetails = orderReturnValue.OrderDetails;
                            foreach (DataRow row in dtOrderDetails.Rows)
                            {
                                    Dictionary<string, string> dic = new Dictionary<string, string>();
                                    for (int index = 0; index < dtOrderDetails.Columns.Count; index++)
                                    {
                                            dic.Add(dtOrderDetails.Columns[index].ColumnName, row[index].ToString());
                                    }
                                    list[1].Add(dic);
                            }
                            return Request.CreateResponse(HttpStatusCode.OK, list);
                    }
            }
    }
  10. 同様に、泚文情報ず泚文詳现情報を曎新するための Web API コントロヌラヌクラスを䜜成する。

    public class UpdateOrderController : ApiController
    {
            public HttpResponseMessage Post(WebApiOrderParams param)
            {
                    // Create an object of Parameter Value class
                    OrderParameterValue orderParameterValue
                            = new OrderParameterValue("OrderInformation", string.Empty, "UpdateOrder",
                                    "SQL", new MyUserInfo("user01", "192.168.1.1"));
    
                    // Set the parameters of order summary information
                    orderParameterValue.OrderId = param.OrderId;
                    orderParameterValue.CustomerID = param.CustomerID;
                    orderParameterValue.EmployeeID = param.EmployeeID;
                    orderParameterValue.OrderDate = param.OrderDate;
                    orderParameterValue.RequiredDate = param.RequiredDate;
                    orderParameterValue.ShippedDate = param.ShippedDate;
                    orderParameterValue.ShipName = param.ShipName;
                    orderParameterValue.ShipVia = param.ShipVia;
                    orderParameterValue.ShipAddress = param.ShipAddress;
                    orderParameterValue.ShipCountry = param.ShipCountry;
                    orderParameterValue.ShipCity = param.ShipCity;
                    orderParameterValue.ShipRegion = param.ShipRegion;
                    orderParameterValue.ShipPostalCode = param.ShipPostalCode;
                    orderParameterValue.Freight = param.Freight;
    
                    // Set the parameters of order details information
                    orderParameterValue.ProductId = param.ProductId;
                    orderParameterValue.UnitPrice = param.UnitPrice;
                    orderParameterValue.Quantity = param.Quantity;
                    orderParameterValue.Discount = param.Discount;
    
                    // Create objects of Return Value class and Business logic class
                    OrderReturnValue orderReturnValue;
                    OrdersLogic logic = new OrdersLogic();
    
                    // Update the order information (summary) and order information (details)
                    orderReturnValue = (OrderReturnValue)logic.DoBusinessLogic(orderParameterValue);
    
                    // Create an object of string to display message
                    string message = string.Empty;
                    Dictionary<string, string> dic = new Dictionary<string, string>();
                    if (orderReturnValue.ErrorFlag == true)
                    {
                            // If the Return Value object has error, display the possible error message
                            message = "ErrorMessageID:" + orderReturnValue.ErrorMessageID + ";";
                            message += "ErrorMessage:" + orderReturnValue.ErrorMessage + ";";
                            message += "ErrorInfo:" + orderReturnValue.ErrorInfo;
                            dic.Add("Error", message);
                            return Request.CreateResponse(HttpStatusCode.OK, dic);
                    }
                    else
                    {
                            // Display the success message
                            message = "Successfully updated order summary and order details information.";
                            dic.Add("Message", message);
                            return Request.CreateResponse(HttpStatusCode.OK, dic);
                    }
            }
    }

4.5.2 ViewModel を远加

  1. Visual Studio の゜リュヌション ゚クスプロヌラヌで、Scripts\app フォルダを遞択し、ツヌルバヌの「プロゞェクト(P)」-「新しい項目の远加(W)」を遞択したす。

  2. Order.viewmodel.js ずいう名前の JavaScript ファむルを远加したす。

  3. Order.viewmodel.js に、OrderViewModel メ゜ッドを䜜成し、ビュヌにバむンドさせるプロパティおよびコマンドを定矩したす。

    function OrderViewModel() {
    
            // Orders list, order summary and order details information (JSON format)
            this.dataOrders = ko.observableArray();
            this.dataOrder = ko.observableArray();
            this.dataOrderDetails = ko.observableArray();
    
            // Success message
            this.Result = ko.observable("");
    
            // Error message
            this.ErrorMessage = ko.observable("");
    
            // Handles visibility Orders list, order summary and order details information
            this.CanDisplayOrders = ko.observable(true);
            this.CanDisplayOrderInfo = ko.observable(false);
            this.CanEditOrderInfo = ko.observable(false);
    
            this.DisplayOrders = function () {
                    var self = this;
                    self.CanDisplayOrders(true);
                    self.CanDisplayOrderInfo(false);
                    self.CanEditOrderInfo(false);
            };
    
            this.DisplayOrderInfo = function () {
                    var self = this;
                    self.CanDisplayOrders(false);
                    self.CanDisplayOrderInfo(true);
                    self.CanEditOrderInfo(false);
            };
    
            this.EditOrderInfo = function () {
                    var self = this;
                    self.CanDisplayOrders(false);
                    self.CanDisplayOrderInfo(false);
                    self.CanEditOrderInfo(true);
            };
    
            // Gets the list of Orders
            this.GetOrders = function () {
                    var self = this;
    
                    // Reset the error message
                    this.ErrorMessage("");
    
                    // Set the parameters in JSON format
                    var param = {}
    
                    // Ajax request
                    $.ajax({
                            type: 'POST',
                            url: '/api/GetOrders',
                            data: param,
                            dataType: 'json',
                            success: function (data, dataType) {
                                    if (data.error) {
                                            // Set the error message
                                            self.ErrorMessage(data.error);
                                    }
                                    else {
                                            // Reset the Orders information
                                            self.ClearList();
    
                                            // Enable visibility of Orders
                                            self.DisplayOrders();
    
                                            // Set the list of Orders
                                            self.dataOrders(data);
                                    }
                            },
                            error: function (XMLHttpRequest, textStatus, errorThrown) {
                                    // Set the error message
                                    self.ErrorMessage(XMLHttpRequest.responseText);
                            }
                    });
            };
    
            // Get the order summary and order details information
            this.GetOrderById = function (orderID) {
                    var self = this;
    
                    // Reset the error message
                    this.ErrorMessage("");
    
                    // Set the parameters in JSON format
                    var param = { OrderId: orderID }
    
                    // Ajax request
                    $.ajax({
                            type: 'POST',
                            url: '/api/GetOrderById',
                            data: param,
                            dataType: 'json',
                            success: function (data, dataType) {
                                    if (data.error) {
                                            // Set the error message
                                            self.ErrorMessage(data.error);
                                    }
                                    else {
                                            // Reset the orders information
                                            self.ClearList();
    
                                            // Enable visibility of order information
                                            self.DisplayOrderInfo();
    
                                            // Set the order information
                                            self.dataOrder(data[0]);
                                            self.dataOrderDetails(data[1]);
                                    }
                            },
                            error: function (XMLHttpRequest, textStatus, errorThrown) {
                                    // Set the error message
                                    self.ErrorMessage(XMLHttpRequest.responseText);
                            }
                    });
            };
    
            // Enable the order summary and order details information to edit
            this.EditOrder = function (data) {
                    var self = this;
                    this.Result("");
                    self.EditOrderInfo();
                    self.dataOrderDetails(data);
            };
    
            // Updates the selected order summary and order details information
            this.UpdateOrder = function () {
                    var self = this;
    
                    // Reset the error message
                    this.ErrorMessage("");
    
                    // Set the parameters in JSON format
                    var param = {
                            OrderID: self.dataOrder()[0].orderID,
                            CustomerID: self.dataOrder()[0].customerID,
                            EmployeeID: self.dataOrder()[0].employeeID,
                            OrderDate: self.dataOrder()[0].orderDate,
                            RequiredDate: self.dataOrder()[0].requiredDate,
                            ShippedDate: self.dataOrder()[0].shippedDate,
                            ShipVia: self.dataOrder()[0].shipVia,
                            Freight: self.dataOrder()[0].freight,
                            ShipName: self.dataOrder()[0].shipName,
                            ShipAddress: self.dataOrder()[0].shipAddress,
                            ShipCity: self.dataOrder()[0].shipCity,
                            ShipRegion: self.dataOrder()[0].shipRegion,
                            ShipPostalCode: self.dataOrder()[0].shipPostalCode,
                            ShipCountry: self.dataOrder()[0].shipCountry,
                            ProductID: self.dataOrderDetails().productID,
                            UnitPrice: self.dataOrderDetails().unitPrice,
                            Quantity: self.dataOrderDetails().quantity,
                            Discount: self.dataOrderDetails().discount
                    }
    
                    // Ajax request
                    $.ajax({
                            type: 'POST',
                            url: '/api/UpdateOrder',
                            data: param,
                            dataType: 'json',
                            success: function (data, dataType) {
                                    if (data.error) {
                                            // Set the error message
                                            self.ErrorMessage(data.error);
                                    }
                                    else {
                                            // Set the success message
                                            self.Result(data.message);
                                    }
                            },
                            error: function (XMLHttpRequest, textStatus, errorThrown) {
                                    // Set the error message
                                    self.ErrorMessage(XMLHttpRequest.responseText);
                            }
                    });
            };
    
            // Resets the orders list, order summary and order details information
            this.ClearList = function () {
                    this.dataOrders([]);
                    this.dataOrder([]);
                    this.dataOrderDetails([]);
            };
    }
    
    // Creates Order ViewModel
    var model = new OrderViewModel();
    
    // Creates dialog to display error message
    model.ErrorMessage.subscribe(function (newValue) {
            if (newValue != '') {
                    $('<div>' + newValue + '</div>').dialog({
                            title: 'Error!',
                            modal: true,
                            resizable: false,
                            height: 600,
                            width: 800,
                            buttons: {
                                    'OK': function (event) {
                                            $(this).dialog('close');
                                    }
                            }
                    });
            }
    });
    
    // Activates knockout.js
    ko.applyBindings(model);
  4. Visual Studio で App_Start\BundleConfig.cs を開き、Order.viewmodel.js ぞの参照を定矩したす。

    bundles.Add(new ScriptBundle("~/bundles/Order").Include("~/Scripts/app/Order.viewmodel.js"));

4.5.3 Viewを远加

  1. OrderController クラスの Index メ゜ッド (のどこか) で右クリックし、「ビュヌの远加」を遞択したす。

  2. ビュヌの远加ダむアログで以䞋のように蚭定し、「远加」ボタンをクリックしたす。

    • ビュヌ名: Index
    • ビュヌ゚ンゞン: Razor (CSHTML)
    • 厳密に型指定されたビュヌを䜜成する: チェックなし
    • 郚分ビュヌずしお䜜成する: チェックなし
    • レむアりトたたはマスタヌペヌゞを䜿甚する: チェックあり
  3. 泚文情報の䞀芧、および泚文情報ず泚文詳现情報を衚瀺し、泚文情報ず泚文詳现情報を曎新するようにビュヌを定矩したす。(ここでは、ViewModel に定矩した、画面衚瀺可・䞍可を刀定甚の CanDisplayOrders メ゜ッド、CanDisplayOrderInfo メ゜ッド、CanEditOrderInfo メ゜ッドの結果をもずに、画面衚瀺を切り替えおいたす)

    <!--Title and header information-->
    @{
            ViewBag.Title = "Open Touryo SPA Sample";
            Layout = "~/Views/Shared/_Layout.cshtml";
    }
    <div style="width:100%;padding:0.5em 0em;background:#f0f0f0;">
            <b style="margin-left:0.4em;font-size:1.5em;">Open Touryo SPA Sample</b>
    </div>
    
    <!--Displays List of Orders-->
    <div style="width:100%;height:460px;margin-top:0.5em;overflow:scroll;display:none;"
             data-bind="visible: GetOrders(), style: { display: $root.CanDisplayOrders() === true ? 'block' : 'none' }">
            <b style="margin-left:1em;">List of Orders:</b>
            <table style="width:100%;margin-top:0.5em;font-size:medium;">
                    <thead>
                            <tr>
                                    <th style="width:8%;">Order ID</th>
                                    <th style="width:18%">Company Name</th>
                                    <th style="width:18%">Contact Name</th>
                                    <th style="width:18%">Employee Last Name</th>
                                    <th style="width:18%">Employee First Name</th>
                                    <th style="width:15%">Order Date</th>
                            </tr>
                    </thead>
                    <tbody data-bind="foreach: dataOrders">
                            <tr>
                                    <td>
                                            <a data-bind="text: orderID, click: function(){ $root.GetOrderById($data.orderID) }"
                                                 href="javascript:void(0)" />
                                    </td>
                                    <td data-bind="text: companyName"></td>
                                    <td data-bind="text: contactName"></td>
                                    <td data-bind="text: employeeLastName"></td>
                                    <td data-bind="text: employeeFirstName"></td>
                                    <td data-bind="text: orderDate"></td>
                            </tr>
                    </tbody>
            </table>
    </div>
    
    <!--Displays the order summary and order details information-->
    <div style="width:100%;display:none;"
             data-bind="style: { display: CanDisplayOrderInfo() === true ? 'block' : 'none' }">
            <!--Displays the Order information (Summary)-->
            <div style="width: 100%;margin-top:0.5em;">
                    <b style="margin-left:1em;">Order information (Summary):</b>
                    <table style="width:100%;margin-top:0.5em;font-size:small;">
                            <thead>
                                    <tr>
                                            <th>Order ID</th>
                                            <th>Customer ID</th>
                                            <th>Employee ID</th>
                                            <th>Order Date</th>
                                            <th>Required Date</th>
                                            <th>Shipped Date</th>
                                            <th>Ship Via</th>
                                            <th>Freight</th>
                                            <th>Ship Name</th>
                                            <th>Ship Address</th>
                                            <th>ShipCity</th>
                                            <th>Ship Region</th>
                                            <th>Ship PostalCode</th>
                                            <th>Ship Country</th>
                                    </tr>
                            </thead>
                            <tbody data-bind="foreach: dataOrder">
                                    <tr>
                                            <td data-bind="text: orderID"></td>
                                            <td data-bind="text: customerID"></td>
                                            <td data-bind="text: employeeID"></td>
                                            <td data-bind="text: orderDate"></td>
                                            <td data-bind="text: requiredDate"></td>
                                            <td data-bind="text: shippedDate"></td>
                                            <td data-bind="text: shipVia"></td>
                                            <td data-bind="text: freight"></td>
                                            <td data-bind="text: shipName"></td>
                                            <td data-bind="text: shipAddress"></td>
                                            <td data-bind="text: shipCity"></td>
                                            <td data-bind="text: shipRegion"></td>
                                            <td data-bind="text: shipPostalCode"></td>
                                            <td data-bind="text: shipCountry"></td>
                                    </tr>
                            </tbody>
                    </table>
            </div>
            <!--Displays the Order information (Details)-->
            <div style="width:100%; margin-top:0.5em;">
                    <b style="margin-left:1em;">Order information (Details):</b>
                    <table style="width:100%;margin-top:0.5em; font-size:small;">
                            <thead>
                                    <tr>
                                            <th></th>
                                            <th>Order ID</th>
                                            <th>Product ID</th>
                                            <th>Unit Price</th>
                                            <th>Quantity</th>
                                            <th>Discount</th>
                                    </tr>
                            </thead>
                            <tbody data-bind="foreach: dataOrderDetails">
                                    <tr>
                                            <td>
                                                    <a data-bind="click: function () { $root.EditOrder($data) }"
                                                         href="javascript:void(0)">Edit</a>
                                            </td>
                                            <td data-bind="text: orderID"></td>
                                            <td data-bind="text: productID"></td>
                                            <td data-bind="text: unitPrice"></td>
                                            <td data-bind="text: quantity"></td>
                                            <td data-bind="text: discount"></td>
                                    </tr>
                            </tbody>
                    </table>
            </div>
            <!--Action controls-->
            <div style="width:100%;margin:0.5em 0;">
                    <div style="float:right;">
                            <input type="button" id="button1" value="<< Back"
                                    data-bind="click: function () { $root.GetOrders() }" />
                    </div>
            </div>
    </div>
    
    <!--Displays the order summary and order details information to update-->
    <div style="width:100%;display:none;"
             data-bind="style: { display: CanEditOrderInfo() === true ? 'block' : 'none' }">
            <!--Update the Order information (Summary)-->
            <fieldset style="border:1px solid #ddd;width:96%;padding-bottom:1em;">
                    <legend style="font-weight:bold;display:block;margin-left:3px;">
                            Update Order information (Summary)
                    </legend>
                    <table style="width:100%;font-size:small;" data-bind="foreach: dataOrder">
                            <tr>
                                    <td style="width:16%;"><b>Order ID</b></td>
                                    <td style="width:16%;">
                                            <label style="padding:0.3em 0;background:#f0f0f0;" data-bind="text: orderID" />
                                    </td>
                                    <td style="width:16%;"><b>Customer ID</b></td>
                                    <td style="width:16%">
                                            <input type="text" data-bind="value: customerID" />
                                    </td>
                                    <td style="width:16%;"><b>Employee ID</b></td>
                                    <td style="width:16%;">
                                            <input type="text" data-bind="value: employeeID" />
                                    </td>
                            </tr>
                            <tr>
                                    <td><b>Order Date</b></td>
                                    <td>
                                            <input type="text" data-bind="value: orderDate" />
                                    </td>
                                    <td><b>Required Date</b></td>
                                    <td>
                                            <input type="text" data-bind="value: requiredDate" />
                                    </td>
                                    <td><b>Shipped Date</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shippedDate" />
                                    </td>
                            </tr>
                            <tr>
                                    <td><b>Ship Via</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipVia" />
                                    </td>
                                    <td><b>Freight</b></td>
                                    <td>
                                            <input type="text" data-bind="value: freight" />
                                    </td>
                                    <td><b>Ship Name</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipName" />
                                    </td>
                            </tr>
                            <tr>
                                    <td><b>Ship Address</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipAddress" />
                                    </td>
                                    <td><b>Ship City</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipCity" />
                                    </td>
                                    <td><b>Ship Region</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipRegion" />
                                    </td>
                            </tr>
                            <tr>
                                    <td><b>Ship Postal Code</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipPostalCode" />
                                    </td>
                                    <td><b>Ship Country</b></td>
                                    <td>
                                            <input type="text" data-bind="value: shipCountry" />
                                    </td>
                            </tr>
                    </table>
            </fieldset>
            <!--Update the Order information (Details)-->
            <fieldset style="border:1px solid #ddd;width:96%;padding-bottom:1em;">
                    <legend style="font-weight:bold;display:block;margin-left:3px;">
                            Update Order information (Details)
                    </legend>
                    <table style="width:100%;font-size:small;" data-bind="foreach: dataOrderDetails">
                            <tr>
                                    <td style="width:16%;"><b>Order ID</b></td>
                                    <td style="width:16%;">
                                            <label style="padding:0.3em 0;background:#f0f0f0;" data-bind="text: orderID" />
                                    </td>
                                    <td style="width:16%;"><b>Product ID</b></td>
                                    <td style="width:16%;">
                                            <label style="padding:0.3em 0;background:#f0f0f0;" data-bind="text: productID" />
                                    </td>
                                    <td style="width:16%;"><b>Unit Price</b></td>
                                    <td style="width:16%;">
                                            <input type="text" data-bind="value: unitPrice" />
                                    </td>
                            </tr>
                            <tr>
                                    <td><b>Quantity</b></td>
                                    <td>
                                            <input type="text" data-bind="value: quantity" />
                                    </td>
                                    <td><b>Discount</b></td>
                                    <td>
                                            <input type="text" data-bind="value: discount" />
                                    </td>
                            </tr>
                    </table>
            </fieldset>
            <!--Action controls-->
            <div style="width:100%;margin:0.5em 0px;">
                    <div style="float:left;">
                            <input type="button" id="button2" value="Update Order Information"
                                         data-bind="click: UpdateOrder" />
                    </div>
                    <div style="float:right;" data-bind="foreach: dataOrder">
                            <input type="button" id="button3" value="<< Back"
                                         data-bind="click: function () {$root.GetOrderById($data.orderID)}" />
                    </div>
            </div>
            <div style="width:100%;margin:0.5em 0;display:inline-block;">
                    <label id="labelMessage" style="color:#088608;font-weight:bold;" data-bind="text: Result" />
            </div>
    </div>
    @section scripts{
            @Scripts.Render("~/bundles/knockout")
            @Scripts.Render("~/bundles/jqueryval")
            @Scripts.Render("~/bundles/Order")
    }

4.6 動䜜確認

4.6.1 Start ASP.NET state service

  1. スタヌトメニュヌの「プログラムずファむルの怜玢」ボックスで services.msc を実行したす。

  2. サヌビス画面から「ASP.NET 状態サヌビス」を右クリックし、「開始」を遞択したす。

  3. 「ASP.NET 状態サヌビス」の状態が「開始」になったこずを確認したす。

4.6.2 Visual Studio によるデバッグ実行

  1. Visual Studio の゜リュヌション ゚クスプロヌラヌで、SPA_Sample プロゞェクトを右クリックし、「プロパティ」を遞択したす。

  2. SPA_Sample プロゞェクトのプロパティ画面で、「Web」を遞択し、開始動䜜を以䞋のように蚭定したす。

    • 開始動䜜: ペヌゞを指定する
    • ペヌゞ: Order
  3. Visual Studio でサンプルプログラムをデバッグ実行したす。

  4. 泚文情報の䞀芧が衚瀺されるこずを確認したす。

  5. Order ID 列のリンクをクリックし、遞択した Order ID の泚文情報ず泚文詳现情報が衚瀺されるこずを確認したす。

  6. 泚文詳现情報の「Edit」リンクをクリックしたす。

    【泚意】
    ここで、「Ship Region」の倀が NULL の堎合、レコヌド曎新時に Open 棟梁の゚ラヌが発生したす。したがっお、ここでは、「Ship Region」が NULL でないデヌタを遞択しおください。「Ship Region」の倀が NULL のデヌタに察しおも曎新可胜にするには、4.3.1 項で自動生成した SQL ファむルを修正する必芁がありたす。詳现に぀いおは Open 棟梁の利甚ガむド (動的パラメタラむズドク゚リ線) を参照しおください。

  7. 泚文情報ず泚文詳现情報の線集画面が衚瀺されるこずを確認したす。泚文情報ず泚文詳现情報を線集し、「Update Order Information」ボタンをクリックしたす。

  8. 以䞋のように、成功を瀺すメッセヌゞが衚瀺され、泚文情報ず泚文詳现情報が曎新されたこずを確認する。

4.6.3 トレヌスログの確認

  1. C:\root\files\resource\Log\ACCESS.yyyy-mm-dd.log をメモ垳などで開きたす。(yyyy-mm-dd には、実行日付が入りたす)

  2. 業務ロゞックの呌び出し履歎が、トレヌスログずしお蚘録されおいるこずを確認したす。

    [2016/08/22 00:11:07,450],[INFO ],[9],,user01,192.168.1.1,----->>,OrderDetails,,GetOrders,
    [2016/08/22 00:11:08,350],[INFO ],[9],,user01,192.168.1.1,<<-----,OrderDetails,,GetOrders,,890,94
    [2016/08/22 00:11:18,092],[INFO ],[8],,user01,192.168.1.1,----->>,OrderDetails,,GetOrderById,
    [2016/08/22 00:11:18,574],[INFO ],[8],,user01,192.168.1.1,<<-----,OrderDetails,,GetOrderById,,481,47
    [2016/08/22 00:11:24,337],[INFO ],[7],,user01,192.168.1.1,----->>,OrderDetails,,UpdateOrder,
    [2016/08/22 00:11:24,700],[INFO ],[7],,user01,192.168.1.1,<<-----,OrderDetails,,UpdateOrder,,362,16
  3. C:\root\files\resource\Log\SQLTRACE.yyyy-mm-dd.log をメモ垳などで開きたす。(yyyy-mm-dd には、実行日付が入りたす)

  4. Orders テヌブル・Order Details テヌブルに察する SQL 文がトレヌスずしお蚘録されおいるこずを確認したす。以䞋は SQL トレヌスログから、SELECT 文の実行ログを抜粋したものです

    [2016/08/22 00:11:08,349],[INFO ],[9],238,31,[commandText]:SELECT Orders.OrderID, Customers.CompanyName, Customers.ContactName, Employees.LastName As EmployeeLastName, Employees.FirstName As EmployeeFirstName, Orders.OrderDate FROM Orders INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID INNER JOIN Employees ON Orders.EmployeeID = Employees.EmployeeID    [commandParameter]:
    [2016/08/22 00:11:18,373],[INFO ],[8],114,16,[commandText]: -- DaoOrders_D2_Select -- 2016/8/3 日立 倪郎 SELECT [OrderID], [CustomerID], [EmployeeID], [OrderDate], [RequiredDate], [ShippedDate], [ShipVia], [Freight], [ShipName], [ShipAddress], [ShipCity], [ShipRegion], [ShipPostalCode], [ShipCountry] FROM [Orders] WHERE [OrderID] = @OrderID    [commandParameter]:OrderID=10250,
    [2016/08/22 00:11:18,573],[INFO ],[8],71,0,[commandText]: -- DaoOrder_Details_D2_Select -- 2016/8/3 日立 倪郎 SELECT [OrderID], [ProductID], [UnitPrice], [Quantity], [Discount] FROM [Order Details] WHERE [OrderID] = @OrderID    [commandParameter]:OrderID=10250,
    [2016/08/22 00:11:24,530],[INFO ],[7],122,0,[commandText]: -- DaoOrders_D3_Update -- 2016/8/3 日立 倪郎 UPDATE [Orders] SET [CustomerID] = @Set_CustomerID_forUPD, [EmployeeID] = @Set_EmployeeID_forUPD, [OrderDate] = @Set_OrderDate_forUPD, [RequiredDate] = @Set_RequiredDate_forUPD, [ShippedDate] = @Set_ShippedDate_forUPD, [ShipVia] = @Set_ShipVia_forUPD, [Freight] = @Set_Freight_forUPD, [ShipName] = @Set_ShipName_forUPD, [ShipAddress] = @Set_ShipAddress_forUPD, [ShipCity] = @Set_ShipCity_forUPD, [ShipRegion] = @Set_ShipRegion_forUPD, [ShipPostalCode] = @Set_ShipPostalCode_forUPD, [ShipCountry] = @Set_ShipCountry_forUPD WHERE [OrderID] = @OrderID    [commandParameter]:Set_ShipCity_forUPD=Rio de Janeiro,Set_CustomerID_forUPD=HANAR,OrderID=10250,Set_EmployeeID_forUPD=4,Set_ShippedDate_forUPD=7/12/1996 12:00:00 AM,Set_RequiredDate_forUPD=8/5/1996 12:00:00 AM,Set_ShipName_forUPD=Hanari Carnes,Set_ShipPostalCode_forUPD=05454-876,Set_ShipVia_forUPD=2,Set_ShipAddress_forUPD=Rua do Paco, 67,Set_ShipRegion_forUPD=RJ,Set_OrderDate_forUPD=7/8/1996 12:00:00 AM,Set_ShipCountry_forUPD=Brazil,Set_Freight_forUPD=65.8300,
    [2016/08/22 00:11:24,699],[INFO ],[7],39,0,[commandText]: -- DaoOrder_Details_D3_Update -- 2016/8/3 日立 倪郎 UPDATE [Order Details] SET [UnitPrice] = @Set_UnitPrice_forUPD, [Quantity] = @Set_Quantity_forUPD, [Discount] = @Set_Discount_forUPD WHERE [OrderID] = @OrderID AND [ProductID] = @ProductID    [commandParameter]:OrderID=10250,Set_Quantity_forUPD=35,Set_Discount_forUPD=0.15,Set_UnitPrice_forUPD=42.4000,ProductID=51,
⚠ **GitHub.com Fallback** ⚠