連載:実践! WCFプログラミング

第2回 WCFでASP.NET Webサービスを作成する

デジタルアドバンテージ 岸本 真二郎
2008/08/01
Page1 Page2

独自のサービスの記述

 肝心のサービスの内容だが、ここまで説明したように、インターフェイスの定義とサービス・クラスの記述さえ追加すれば、特にほかに何もしなくてもプロジェクトはWebサービスとして機能する。

 そこで今回は、前回で使用した、RSSフィード情報が格納されたデータベースを利用して、RSSのアイテムIDを指定すると、アイテムの内容を返すWebサービスを作成してみる。サービス・クラス名は「RssItemService」とし(インターフェイス名は「IRssItemService」)、アイテムを取得するメソッドは「GetItem」とした。

■インターフェイスに公開メソッドを追加

 公開するGetItemメソッドは、アイテムID(itemID)をパラメータとして取得し、それに対応するコンテンツ(フィード情報)をクラスに格納してクライアントに返す。まずインターフェイス定義(IRssItemService)で、次のようなメソッドの宣言を行う。

[ServiceContract]
public interface IRssItemService
{
  [OperationContract]
  ItemInfo GetItem( int itemID );
}
<ServiceContract()> _
Public Interface IRssItemService

  <OperationContract()> _
  Function GetItem(ByVal itemID As Integer) As ItemInfo

End Interface
リスト6 GetItemメソッドを記述したインターフェイス(上:C#、下:VB)
自動生成されたメソッドを削除して、新たにメソッドを追加する。

 さらに、フィード情報を格納するクラス(ItemInfo)を宣言する。このクラスには、アイテムID、タイトル、公開日付、サマリ(description)を定義している。それぞれのプロパティにはDataMember属性を付加して、これらのプロパティを公開することを指示する。

[DataContract]
public class ItemInfo
{
  private int itemID = 0;
  private string title="";
  private string description = "";
  private DateTime pubDate = DateTime.Now;

  [DataMember]
  public int ItemID
  {
    get { return itemID; }
    set { itemID = value; }
  }

  [DataMember]
  public string Title
  {
    get { return title; }
    set { title = value; }
  }
  [DataMember]
  public string Description
  {
    get { return description; }
    set { description = value; }
  }
  [DataMember]
  public DateTime PubDate
  {
    get { return pubDate; }
    set { pubDate = value; }
  }
}
<DataContract()> _
Public Class ItemInfo

  Private itemIDFld As Integer = 0
  Private _title As String = ""
  Private _description As String = ""
  Private _pubDate As DateTime = DateTime.Now

  <DataMember()> _
  Public Property ItemID() As Integer
    Get
      Return Me.itemIDFld
    End Get
    Set(ByVal value As Integer)
      itemIDFld = value
    End Set
  End Property

  <DataMember()> _
  Public Property Title() As String
    Get
      Return _title
    End Get
    Set(ByVal value As String)
      _title = value
    End Set
  End Property

  <DataMember()> _
  Public Property Description() As String
    Get
      Return _description
    End Get
    Set(ByVal value As String)
      _description = value
    End Set
  End Property

  <DataMember()> _
  Public Property PubDate() As DateTime
    Get
      Return _pubDate
    End Get
    Set(ByVal value As DateTime)
      _pubDate = value
    End Set
  End Property
End Class
リスト7 GetItemメソッドが返すフィード情報を格納するためのクラス(上:C#、下:VB)

■メソッドの実体を追加

 最後に、インターフェイスに追加したGetItemメソッドの実体を、RssItemServiceクラスに記述する。ここではアイテムIDでデータベースを検索し、その結果となるフィード情報をItemInfoオブジェクトに格納して返す。

public ItemInfo GetItem( int itemID )
{
  ItemInfo info = new ItemInfo();
  SqlConnection conn = new SqlConnection(connStr);
  try {
    conn.Open();
    SqlCommand cmd = new SqlCommand("", conn);
    cmd.CommandText = String.Format("SELECT * from Items WHERE itemID={0}", itemID);
    SqlDataReader rdr = cmd.ExecuteReader();

    if (rdr.Read()) {
      info.ItemID = int.Parse(rdr["itemID"].ToString());
      info.Title = rdr["title"].ToString();
      info.Description = rdr["description"].ToString();
      info.PubDate = DateTime.Parse(rdr["pubDate"].ToString());
    }
    rdr.Close();
  } catch(Exception exp) {
    info.Title = exp.Message;
  } finally {
    conn.Close();
  }
  return info;
}
Public Function GetItem(ByVal itemID As Integer) As ItemInfo Implements IRssItemService.GetItem
  Dim info As ItemInfo = New ItemInfo()

  Dim conn As SqlConnection = New SqlConnection(connStr)
  Try
    conn.Open()
    Dim cmd As SqlCommand = New SqlCommand("", conn)
    cmd.CommandText = String.Format("SELECT * from Items WHERE ItemID={0}", itemID)
    Dim rdr As SqlDataReader = cmd.ExecuteReader()

    If (rdr.Read()) Then
      info.ItemID = Integer.Parse(rdr("itemID").ToString())
      info.Title = rdr("title").ToString()
      info.Description = rdr("description").ToString()
      info.PubDate = DateTime.Parse(rdr("pubDate").ToString())
    End If

    rdr.Close()
  Catch ex As Exception
    Info.Title = ex.Message
  Finally
    conn.Close()
  End Try

  Return info
End Function
リスト8 指定されたitemIDのフィード情報を返すGetItemメソッド(上:C#、下:VB)

 以上のコードの追加で、ASP.NET Webサービスと等価なWebサービスが出来上がる。

 作成したプロジェクトはWebアプリケーションなので、統合環境からデバッグ実行すると、デバッグ用のWebサーバが起動し、さらにWebブラウザが起動して該当するページ(RssItemService.svc)が開く。以下の画面のようなページが表示されれば成功だ。


Webサービスをデバッガで実行した様子
ブラウザが起動して、RssItemService.svcをリクエストしている。

 このページに記述されているように、URLに「?wsdl」を付加してアクセスすると、WSDLの内容が表示され、サービスの内容が確認できる。残念ながら、ASP.NET Webサービスのように、公開されているメソッドを実際にブラウザから呼び出して確認することはできないようだ。

クライアントから確認してみる

 デバッグ実行した上記の画面には、「クライアントを使用してサービスを呼び出すにはsvcutil.exeを実行せよ」と記述されている。これを行うと、デバッグ時のURLで公開されているWebサービスを利用するためのプロキシとなるソース・コードが生成されるのだが、Visual Studioから「Web参照の追加」を行っても同じことなので、わざわざコマンドラインからsvcutil.exeを使う必要はない。

 実際にVisual Studio 2005を使って、Web参照の追加からサービスを利用できるか確認してみよう。サンプルとしてWindowsフォーム・アプリケーションを作成する。ボタンが押されたらテキストボックスに入力されたアイテムIDをパラメータにセットしてGetItemメソッドを呼び出し、フィードの内容をフォームに表示するというものだ。


Webサービスのクライアントの画面

 適当なWindowsフォーム・アプリケーションのプロジェクトを新規作成したら、ソリューション・エクスプローラからWeb参照を追加する。Web参照を追加する際のURLには、いま作成した.svcファイルのURLに「?wsdl」を付加する。こうすると、Webサービスが提供するメソッドが一覧表示される。


Web参照の追加(Visual Studio 2005)

 「Web参照名」に適当な名前を付けて(ここでは「wcfService」とした)、[参照の追加]ボタンを押してWeb参照を追加する。これによりWebサービスのプロキシ・クラスが作成される。

 後は、プロキシ・クラスのインスタンスを作成し、GetItemメソッドの呼び出しを記述する。このサンプルでは、ボタンのイベント・ハンドラに次のようなコードを記述する。

private void button1_Click(object sender, EventArgs e)
{
  wcfService.RssItemService svc =
     new WcfWsClient.wcfService.RssItemService();

  svc.Url = "http://localhost/wcfServiceApp/RssItemService.svc";
  int itemID = int.Parse(this.txtItemID.Text);
  wcfService.ItemInfo info = svc.GetItem(itemID, true);
  this.lblPubDate.Text = info.PubDate.ToString();
  this.txtTitle.Text = info.Title;
  this.txtDescription.Text = info.Description;

  svc.Dispose();
}
Private Sub button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles button1.Click
  Dim svc As wcfService.RssItemService = _
       New wcfService.RssItemService()

  svc.Url = "http://localhost/wcfServiceApp/RssItemService.svc"
  Dim itemID As Integer = Integer.Parse(Me.txtItemID.Text)
  Dim info As wcfService.ItemInfo = svc.GetItem(itemID, True)
  Me.lblPubDate.Text = info.PubDate.ToString()
  Me.txtTitle.Text = info.Title
  Me.txtDescription.Text = info.Description
  svc.Dispose()
End Sub
リスト9 ボタンのイベント・ハンドラに記述するコード(上:C#、下:VB)
Webサービスのインスタンスを作成してフィードの内容を取得し、フォームに表示する。

 このリスト9では、サービスに接続するURLを指定しているが、Web参照の追加の際に指定したURLと同じ場合は、このようなURLの指定は不要だ。開発中にWebサービスをデバッグ実行し、そのURLからWeb参照を追加したが、本番ではサービスを提供するサイトが異なるといった場合は、実際にアクセスするURLを、このようにして指定する必要がある。

Webサイトにソース・コードを置きたくない

 Webサイトによっては、C#やVBのソース・ファイルを公開ディレクトリに配置したくない場合もあるだろう。この場合は.svcファイルに含まれる「CodeBehind="Service1.svc.cs"」という記述を削除し、該当するソース・ファイルをフォルダに配置しないようにすればよい。

 なお、Webアプリケーション・プロジェクトを使ってサービスをビルドする場合は、ライブラリ(DLLファイル)が作成されるため、ソース・コードは不要だ。一方、Webサイト・プロジェクトとしてサービスを構築した場合には、DLLファイルは作成されない(ソース・ファイルが動的にコンパイル、実行される)。

 従来のASP.NET Webサービスのクライアントから接続する場合にはバインディングを「basicHttpBinding」に変更するという点に注意しておけば、WCFを使ったWebサービスの作成はとても簡単に行える。

 また、サービス・コントラクトのインターフェイスを作成し、サービスの内容を派生クラスで実装するというスタイルは、前回紹介したRSS/Atomフィードと同じで、WCFではほぼ共通の実装方法である。

 後はWeb.Config(もしくはApp.Config)でサービスの振る舞い(WCFでいうところの「ABC:アドレス、バインディング、コントラクト」)を設定することで、いろいろな状況に対応できる。End of Article

 

 INDEX
  実践! WCFプログラミング
  第2回 WCFでASP.NET Webサービスを作成する
    1.プロジェクトの新規作成/Webサービス・プロジェクトの中身/Web.configの修正
  2.独自のサービスの記述/クライアントから確認してみる
 
インデックス・ページヘ  「実践! WCFプログラミング」


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メールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間