連載:Windowsフォーム開発入門【Visual Studio 2010対応】

リモート・データ活用術〜ASP.NET Webサービス編〜

初音 玲
2011/03/09
Page1 Page2

 業務アプリケーション構築におけるキー・ポイントの1つは、「リモートにあるデータをいかに効率よく活用するか」という点だ。例えば業務アプリケーションでRDBMSがよく使われるのも、リモート・データをデータベース・サーバに蓄積して集中管理することで、効率的にデータを活用できるようにするためだ。

 今回はリモート・データを扱う仕組みとして、ASP.NET Webサービス経由でのSQL Serverへのアクセスを想定している。次の図は、本稿で作成するサンプル・アプリケーションにおける、プログラム/ASP.NET Webサービス/SQL Serverの接続関係を表している。

図1 サンプル・アプリケーションの動作環境(プログラム/ASP.NET Webサービス/SQL Serverの接続関係)

 プログラムからSQL Serverに直接アクセスする場合に比べて、(ASP.NET Webサービスを経由させることには)どのような利点があり、Windowsフォームの作り方としてどのような点が変わってくるのかを見ていくことにしよう。

SQL ServerにアクセスするASP.NET Webサービスの作成

 まずは、SQL ServerにアクセスするASP.NET Webサービスのプロジェクトを作成する。

 Visual Studioの[新しいプロジェクト]ダイアログで[Web]テンプレートの「ASP.NET 空のアプリケーション」を選択して、ベースとなるWebアプリケーション・プロジェクトを生成する。

 プロジェクトが生成されたら、[ソリューション エクスプローラー]でプロジェクト項目の右クリック・メニューから[追加]-[新しい項目]を実行する。そこで表示される[新しい項目の追加]ダイアログで「Web サービス」を選択して(図2参照)、新しいASP.NET Webサービスのファイルをプロジェクトに追加する。

図2 プロジェクトへのASP.NET Webサービスの追加([新しい項目の追加]ダイアログ)

 作成するWebサービスは、(基本的に)認証を行う「Login.asmx」ファイル(=ログイン・サービス)と、レコードの取得・更新を行う「Titles.asmx」ファイル(=データ入出力サービス)の2つで構成される(図3参照)。

図3 画面遷移とWebサービス

XML Webサービスに待ち構える暗黒面
DBアクセス用のXML Webサービスとは?
WCFでASP.NET Webサービスを作成する

 そこで、新しい項目としてこの2つのファイルを追加する。以下では、これらの2つのファイルに対して、ログイン・サービスとデータ入出力サービスを実装していく。

ログイン・サービス

 まずはLogin.asmxファイルに、ログイン・サービスを実装する。具体的には、下記のようなコードになる。

<System.Web.Services.WebService(Namespace:="http://tempuri.org/")> _
<System.Web.Services.WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _
<ToolboxItem(False)> _
Public Class Login
  Inherits System.Web.Services.WebService

  <WebMethod()> _
  Public Function Check(ByVal userID As String,
                        ByVal password As String) As Boolean

    Dim isOK As Boolean = False

    Using _cn As New SqlConnection
      Try
        _cn.ConnectionString =
          String.Format(My.Settings.ConnectonString,
                        userID,
                        password)
        _cn.Open()
        isOK = True
      Catch ex As Exception
        ' 例外をキャッチした場所でログ出力などを行う
        Throw ex
      End Try
    End Using

    Return isOK

  End Function
End Class
namespace WebsSQLCs
{
  [WebService(Namespace = "http://tempuri.org/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  [System.ComponentModel.ToolboxItem(false)]
  public class Login : System.Web.Services.WebService
  {

    [WebMethod]
    public Boolean Check(string userID, string password)
    {
      Boolean isOK = false;
      using (SqlConnection _cn = new SqlConnection())
      {
        try
        {
          _cn.ConnectionString =
            String.Format(WebsSQLCs.Properties.Settings.Default.ConnectonString,
                          userID,
                          password);
          _cn.Open();
          isOK = true;
        }
        catch (Exception ex)
        {
          // 例外をキャッチした場所でログ出力などを行う
          throw ex;
        }
      }
      return isOK;
    }
  }
}
リスト1 ログイン認証を行うWebサービスのコード例(上:VB、下:C#)

 Webサービスのメソッドは、.asmxファイルの中でWebMethod属性を付けたメソッド(上記のコードではCheckメソッド)として定義する。

 今回作成したCheckメソッドでは、そのパラメータで指定されたIDとパスワードを使って、SQL Serverに対してSQL Server認証によるログインを実行する。正常にログインできたときは、その戻り値としてTrueを返す。ログインに失敗したときは、ログイン時に呼び出すOpenメソッドが例外を発生させるので、それを呼び出し元にそのままスロー(Throw)している。

データ入出力サービス ― タイトル検索

 次にTitles.asmxファイルに、データ入出力サービス(タイトル一覧の検索/個別のタイトルの検索/個別のタイトルの更新)を実装していく。

 データ入出力サービスに実装するWebメソッドの1つ目は、タイトルを検索して一覧データを作成するGetTitleDsメソッドだ。具体的には、LIKE検索のSELECT文を実行して、その実行結果をデータセット(DataSet)に格納して返却する。下記はそのコード例である。

<WebMethod()> _
Public Function GetTitleDs(ByVal userID As String,
                           ByVal password As String,
                           ByVal keyword As String) As DataSet

  Dim ds As New DataSet
  Using _cn As New SqlClient.SqlConnection
    _cn.ConnectionString =
      String.Format(My.Settings.ConnectonString,
                    userID,
                    password)
    _cn.Open()
    Using _cmd As New SqlCommand
      _cmd.Connection = _cn
      _cmd.CommandText = "SELECT * " &
                         "FROM titles " &
                         "WHERE title LIKE @Title"
      _cmd.Parameters.Add(New SqlClient.SqlParameter("Title", "%" & keyword & "%"))
      Using _da As New SqlDataAdapter
        _da.SelectCommand = _cmd
        _da.Fill(ds, "TitleList")
        ds.Tables("TitleList").PrimaryKey =
          New DataColumn() {ds.Tables("TitleList").Columns("title_id")}
      End Using
    End Using
  End Using
  Return ds

End Function
[WebMethod]
public DataSet GetTitleDs(String userID, String password, String keyword)
{
  DataSet ds = new DataSet();
  using (SqlConnection _cn = new SqlConnection())
  {
    _cn.ConnectionString =
      String.Format(WebsSQLCs.Properties.Settings.Default.ConnectonString,
                    userID,
                    password);
    _cn.Open();
    using (SqlCommand _cmd = new SqlCommand())
    {
      _cmd.Connection = _cn;
      _cmd.CommandText = "SELECT * " +
                         "FROM titles " +
                         "WHERE title LIKE @Title";
      _cmd.Parameters.Add(new SqlParameter("Title", "%" + keyword + "%"));
      using (SqlDataAdapter _da = new SqlDataAdapter())
      {
        _da.SelectCommand = _cmd;
        _da.Fill(ds, "TitleList");
        ds.Tables["TitleList"].PrimaryKey =
          new DataColumn[] { ds.Tables["TitleList"].Columns["title_id"] };
      }
    }
  }
  return ds;
}
リスト2 タイトル一覧を取得するWebサービス(GetTitleDsメソッド)のコード例(上:VB、下:C#)

 前回はWindowsフォームからSQL Serverに接続してデータを取得した。そのとき、データ・アクセス部分は別のクラス・ファイルに分離したが、リスト2を見てもらえば分かるように、その別のクラス・ファイルの中に記述した内容と同じコードで、ASP.NET Webサービスからもデータが取得できている。1つだけ違う点はWebMethod属性を付けたことだ。

データ入出力サービス ― 1レコード取得

 SQL Serverから1レコード分のデータを取得するコードを、Titles.asmxファイルにGetTitleDsItemメソッドとして記述する。

 1レコードを取得するためのコード(リスト 3)は、SELECT文のWHERE句としてPK(=主キー)であるtitle_idフィールドの値を指定して検索するという点が異なるだけで、前述の「リスト2 タイトル一覧を取得するWebサービスのコード例」と変わらない。

<WebMethod()> _
Public Function GetTitleDsItem(ByVal userID As String,
                               ByVal password As String,
                               ByVal titleID As String) As DataSet

  Dim ds As New DataSet
  Using _cn As New SqlConnection
    _cn.ConnectionString = String.Format(My.Settings.ConnectonString,
                                         userID,
                                         password)
    _cn.Open()
    Using _cmd As New SqlCommand
      _cmd.Connection = _cn
      _cmd.CommandText = "SELECT * " &
                         "FROM titles " &
                         "WHERE title_id=@TitleID"
      _cmd.Parameters.Add(New SqlClient.SqlParameter("TitleID", titleID))
      Using _da As New SqlDataAdapter
        _da.SelectCommand = _cmd
        _da.Fill(ds, "EditTitle")
        ds.Tables("EditTitle").PrimaryKey =
          New DataColumn() {ds.Tables("EditTitle").Columns("title_id")}
      End Using
    End Using
  End Using
  Return ds

End Function
[WebMethod]
public DataSet GetTitleDsItem(String userID, String password, String titleID)
{
  DataSet ds = new DataSet();
  using (SqlConnection _cn = new SqlConnection())
  {
    _cn.ConnectionString =
      String.Format(WebsSQLCs.Properties.Settings.Default.ConnectonString,
                    userID,
                    password);
    _cn.Open();
    using (SqlCommand _cmd = new SqlCommand())
    {
      _cmd.Connection = _cn;
      _cmd.CommandText = "SELECT * " +
                         "FROM titles " +
                         "WHERE title_id=@TitleID";
      _cmd.Parameters.Add(new SqlParameter("TitleID", titleID));
      using (SqlDataAdapter _da = new SqlDataAdapter())
      {
        _da.SelectCommand = _cmd;
        _da.Fill(ds, "EditTitle");
        ds.Tables["EditTitle"].PrimaryKey =
          new DataColumn[] { ds.Tables["EditTitle"].Columns["title_id"] };
      }
    }
  }
  return ds;
}
リスト3 1レコードを取得するWebサービス(GetTitleDsItemメソッド)のコード例(上:VB、下:C#)

データ入出力サービス ― 1レコード更新

 SQL Serverにデータを保存する方法はいくつかあるが、本稿のサンプルではデータセットの内容をデータアダプタ(SqlDataAdapter)のUpdateメソッドを使って保存する方法を採用している。詳しくはリスト4(SetTitleDsItemメソッド)を参照してほしい。

<WebMethod()> _
Public Function SetTitleDsItem(userID As String,
                               password As String,
                               titleID As String,
                               ds As DataSet) As Boolean

  Dim isOK As Boolean = False

  Using _cn As New SqlConnection
    _cn.ConnectionString = String.Format(My.Settings.ConnectonString,
                                         userID,
                                         password)
    _cn.Open()
    Using _tr As SqlTransaction = _cn.BeginTransaction
      Try
        Using _cmd As New SqlCommand
          _cmd.Connection = _cn
          _cmd.Transaction = _tr
          _cmd.CommandText = "SELECT * " &
                             "FROM titles " &
                             "WHERE title_id=@TitleID"
          _cmd.Parameters.Add(New SqlParameter("TitleID", titleID))
          Using _da As New SqlDataAdapter
            _da.SelectCommand = _cmd
            Using _cb As New SqlCommandBuilder(_da)
              _cb.ConflictOption = ConflictOption.OverwriteChanges
              _cb.GetInsertCommand(True).Connection = _cn
              _cb.GetInsertCommand(True).Transaction = _tr
              _cb.GetUpdateCommand(True).Connection = _cn
              _cb.GetUpdateCommand(True).Transaction = _tr
              _cb.GetDeleteCommand(True).Connection = _cn
              _cb.GetDeleteCommand(True).Transaction = _tr
              _da.Update(ds, "EditTitle")
            End Using
            _tr.Commit()
          End Using
          isOK = True
        End Using
      Catch ex As Exception
        _tr.Rollback()
        Throw ex
      End Try
    End Using
  End Using
  Return isOK
End Function
[WebMethod]
public Boolean SetTitleDsItem(String userID, String password, String titleID, DataSet ds)
{
  Boolean isOK = false;
  using (SqlConnection _cn = new SqlConnection())
  {
    _cn.ConnectionString =
      String.Format(WebsSQLCs.Properties.Settings.Default.ConnectonString,
                    userID,
                    password);
    _cn.Open();
    using (SqlTransaction _tr = _cn.BeginTransaction())
    {
      try
      {
        using (SqlCommand _cmd = new SqlCommand())
        {
          _cmd.Connection = _cn;
          _cmd.Transaction = _tr;
          _cmd.CommandText = "SELECT * " +
                             "FROM titles " +
                             "WHERE title_id=@TitleID";
          _cmd.Parameters.Add(new SqlParameter("TitleID", titleID));
          using (SqlDataAdapter _da = new SqlDataAdapter())
          {
            _da.SelectCommand = _cmd;
            using (SqlCommandBuilder _cb = new SqlCommandBuilder(_da))
            {
              _cb.ConflictOption = ConflictOption.OverwriteChanges;
              _cb.GetInsertCommand(true).Connection = _cn;
              _cb.GetInsertCommand(true).Transaction = _tr;
              _cb.GetUpdateCommand(true).Connection = _cn;
              _cb.GetUpdateCommand(true).Transaction = _tr;
              _cb.GetDeleteCommand(true).Connection = _cn;
              _cb.GetDeleteCommand(true).Transaction = _tr;
              _da.Update(ds, "EditTitle");
            }
            _tr.Commit();
          }
          isOK = true;
        }
      }
      catch (Exception ex)
      {
        _tr.Rollback();
        throw ex;
      }
    }
  }
  return isOK;
}
リスト4 1レコードを更新するWebサービス(SetTitleDsItemメソッド)のコード例(上:VB、下:C#)

 SqlDataAdapterのUpdateメソッドは、データセットのデータロウ(DataRow)の状態により内部で自動的にUPDATE文、INSERT文、DELETE文を実行する。そのため、Updateメソッドを実行するときには、下記の2点を忘れずに実施する必要がある。

(1) UPDATE文、INSERT文、DELETE文をSqlDataAdapterに設定する
(2) 明示的にトランザクションを開始し、Updateメソッドが成功したらコミット(Commit)する

 (1)の3つのSQL文はコマンドビルダ(CommandBuilder)を使えばSELECT文から自動生成されるし、(2)の明示的なトランザクションもSqlTransactionクラス(System.Data.SqlClient名前空間)を使えば簡単に実装できる。

 以上でASP.NET Webサービスが完成したので、続いて、そのWebサービスをクライアント・プログラムから利用する処理を実装する。


 INDEX
  [連載]Windowsフォーム開発入門【Visual Studio 2010対応】
  リモート・データ活用術〜ASP.NET Webサービス編〜
  1.SQL ServerにアクセスするASP.NET Webサービスの作成
    2.プログラムからのASP.NET Webサービスの利用

インデックス・ページヘ  「Windowsフォーム開発入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)
- PR -

注目のテーマ

業務アプリInsider 記事ランキング

本日 月間
ソリューションFLASH