いろいろ備忘録日記

主に .NET と Python絡みのメモを公開しています。

WCF入門-008 (基本的なサンプル, データコントラクト)


今回は、データコントラクトの基本について。


WCFでは、ユーザ定義型などをサービスでやり取りするには
データコントラクトとして定義します。


WCFでは、DataContractSerializerを利用してデータをシリアライズ/デシリアライズします。
データコントラクトとして定義するには、以下のようにします。

  • クラスにDataContract属性を付与
  • 公開したいデータに対して、DataMember属性を付与


DataContractSerializerは、WCFが内部で利用する
通常は開発者が意識する必要はありません。


DataContractSerializerには、以下の決まり事があります。

  • DataContract属性が付与されている場合はマークされているメンバーが対象となる。
  • DataContract属性が付与されていない場合は公開されているメンバーが全て対象となる。


以下の型に関しては、暗黙でデータコントラクトとして利用できます。

  1. パラメータを持たないコンストラクタを持つ型
  2. コレクション型
    1. CollectionDataContract属性を付与できるが必須ではない。
  3. 列挙型
  4. プリミティブ型


上記の事から、普通にクラス定義し、内部でプロパティとして
宣言しているデータの型がstringとかDateTimeとかの場合は
DataContract属性を付与しなくても利用できるということになります。


以下、サンプルです。
サンプルでは、サービスメソッドを2つ定義し
一つはDataContractを付与したクラス。もう一つはDataContractを付与していないクラスを
利用しています。


まず、サービス定義。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    [ServiceContract]
    public interface IMyService
    {
        /// <summary>
        ///  DataContract属性を付与したクラスを利用.
        /// </summary>
        [OperationContract]
        MyData GetMyData();

        /// <summary>
        /// DataContract属性を付与していないクラスを利用.
        /// </summary>
        [OperationContract]
        MyData2 GetMyData2();
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace Gsf.Samples.WCF
{
    public class MyService : IMyService
    {
        public MyData GetMyData()
        {
            return new MyData
            {
                 Value1 = "MyData Value1"
                ,Value2 = 999
                ,Items = new List<MyItem>
                 {
                     new MyItem { Value3 = DateTime.Now }
                    ,new MyItem { Value3 = DateTime.Now.AddMonths(-1) }
                 }
            };
        }
        public MyData2 GetMyData2()
        {
            return new MyData2
            {
                 Value1 = "MyData2 Value1"
                ,Value2 = 998
                ,Items = new List<MyItem2>
                 {
                     new MyItem2 { Value3 = DateTime.Now }
                    ,new MyItem2 { Value3 = DateTime.Now.AddMonths(-1) }
                 }
            };
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace Gsf.Samples.WCF
{
    [DataContract]
    public class MyData
    {
        [DataMember]
        public string Value1 { get; set; }
        [DataMember]
        public int Value2 { get; set; }
        [DataMember]
        public IEnumerable<MyItem> Items { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;

namespace Gsf.Samples.WCF
{
    [DataContract]
    public class MyItem
    {
        [DataMember]
        public DateTime Value3 { get; set; }        
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

namespace Gsf.Samples.WCF
{
    public class MyData2
    {
        public string Value1 { get; set; }
        public int Value2 { get; set; }

        public IEnumerable<MyItem2> Items { get; set; }
    }
}

using System;
using System.Collections.Generic;
using System.Linq;

namespace Gsf.Samples.WCF
{
    public class MyItem2
    {
        public DateTime Value3 { get; set; }     
    }
}


次にホストアプリ。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace Gsf.Samples.WCF
{
    class Program
    {
        static void Main()
        {
            using (var host = new ServiceHost(typeof(MyService)))
            {
                host.Open();

                Console.WriteLine("サービスが開始されました。");
                Console.WriteLine("press <ENTER> to exit...");
                Console.ReadLine();

                host.Close();
            }
        }
    }
}

ホスト側のアプリケーション構成ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service name="Gsf.Samples.WCF.MyService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8088/WCFSample008/MyService"/>
          </baseAddresses>
        </host>
        <endpoint address=""
                  binding="basicHttpBinding"
                  contract="Gsf.Samples.WCF.IMyService" />
      </service>
    </services>
  </system.serviceModel>
</configuration>


次にクライアントアプリ。
クライアント側ではPropertyGridが2枚配置してあり
それぞれのデータを表示するようになっています。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Gsf.Samples.WCF.MyServiceRef;

namespace Gsf.Samples.WCF
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            prpMyData.SelectedObject = null;
            prpMyData2.SelectedObject = null;
            ActiveControl = btnCallServiceMethod;
        }

        private void btnCallServiceMethod_Click(object sender, EventArgs e)
        {
            using (var client = new MyServiceRef.MyServiceClient())
            {
                // DataContract属性を付与したデータを取得.
                MyData data = client.GetMyData();
                prpMyData.SelectedObject = data;

                // DataContract属性を付与していないデータを取得.
                MyData2 data2 = client.GetMyData2();
                prpMyData2.SelectedObject = data2;
            }
        }
    }
}

クライアント側のアプリケーション構成ファイル。

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <system.serviceModel>
        <client>
          <endpoint address="http://localhost:8088/WCFSample008/MyService"
                    binding="basicHttpBinding"
                    contract="MyServiceRef.IMyService" />
        </client>
    </system.serviceModel>
</configuration>


実行すると以下のようになります。どちらの場合にもデータが取得できています。



サンプルは以下の場所にアップしてあります。
https://sites.google.com/site/gsfzero1/Home/WCFSample-008.zip?attredirects=0&d=1


================================
過去の記事については、以下のページからご参照下さい。