Hello! ServiceStack [Web Service編]

#ServiceStackってなんぞや？#
Web ServiceのFrameworkです。NuGetから参照追加出来るスグレモノ。
Frameworkなのでコーディングする部分が大幅に減る上に、Exceptionとか勝手にやってくれるので便利この上なし。

[ServiceStack](http://www.servicestack.net/)
[ServiceStack(GitHub)](https://github.com/ServiceStack)

ただ、ちょっと癖があったり、OHPのサンプルのままじゃSOAPが上手く使えなかったり、はたまたサービスの参照で転けるなどいろいろ苦労があるので、ちゃんと参照できるモノを残しておこうと思うのです・・・。

今回はWeb Service部分だけでーす。

##ソリューション構成##
まずソリューション構成は以下の通り
**Interface**
Serviceを書くところ。

**ServiceModel**
Request / Response DTOを書くところ。なんで分けてるのか？それはこのプロジェクトをクライアントの方でも参照するからだ・・・。これに気がつくまで3日かかったょ・・・(´・ω・｀)
Operationsというフォルダを作って、その中にクラスを作っていった方がわかりやすい。
>というか、公式のサンプルがそうやってるだけなんだけどね・・・

**Web**
Serviceを呼び出すだけ。

事前に、全てのプロジェクトに対して、PMコンソールからServiceStackをインストールしておく。

`PM>Install-Package ServiceStack`


#実際に書いてみよう！#

##ServiceModelプロジェクト##
ではまずServiceModelプロジェクトの中でnamespace用のConfig.csを用意しよう。

```csharp:HelloConfig.cs
using ServiceStack.Common.Utils;
using ServiceStack.Configuration;

namespace ServiceStackHelloSample.ServiceModel
{
    public class HelloConfig
    {
        public const string DefaultNamespace = "http://schemas.servicestack.net/types";
        public HelloConfig() {}
    }
}
```

次にRequest / Response DTOを書く。この時の注意は、Response DTOのNamingルールがあるってこと。
必ずResuest DTOに＋Responseでなければならない。
>例：HogeってRequest DTOを作ったなら、HogeResponseとする。

またこの２つは対で同じNamingSpaceにいないとダメだそうな。
さらに、[DataContract]と[DataMember]のAttributeもお忘れ無く。

```csharp:Hello.cs
using System.Runtime.Serialization;
using ServiceStack.ServiceHost;

namespace ServiceStackHelloSample.ServiceModel.Operations
{
    /// <summary>
    /// Request DTO
    /// </summary>
    [Route("/hello")]
    [Route("/hello/{name]")]
    [DataContract(Namespace = HelloConfig.DefaultNamespace)]
    public class Hello : IReturn<HelloResponse>
    {
        [DataMember]
        public string Name { get; set; }
    }

    /// <summary>
    /// Response DTO
    /// </summary>
    [DataContract(Namespace = HelloConfig.DefaultNamespace)]
    public class HelloResponse
    {
        [DataMember]
        public string Result { get; set; }
    }
}
```

##Interfaceプロジェクト##
次にRequest / Response DTOを参照するServiceをInterfaceプロジェクトの中に書く。

```csharp:HelloService.cs
using ServiceStack.ServiceInterface;
using ServiceStackHelloSample.ServiceModel.Operations;

namespace ServiceStackHelloSample.Interface
{
    public class HelloService : Service
    {
        public HelloResponse Any(Hello request)
        {
            string name = request.Name ?? "lainzero";
            return new HelloResponse { Result = "Hello, " + name };
        }
    }
}
```

##Webプロジェクト##
ラストでServiceをWeb Serviceとして動作するようにWebプロジェクトの中に書く！
この時、Visual Studio 2012のデフォルトではGlobal.asaxが自動で作られていないので、ファイルの追加で[ **ASP.NET アプリケーション ファイル** ]を作っておく。

```csharp:Global.asax.cs
using System;
using Funq;
using System.Web;
using ServiceStack.WebHost.Endpoints;
using ServiceStackHelloSample.Interface;

namespace ServiceStackHelloSample.Web
{
    public class Global : HttpApplication
    {
        public class AppHost : AppHostBase
        {
            public AppHost() : base("ServiceStack Hello Web Service", typeof(HelloService).Assembly) { }
            public override void Configure(Container container)
            {
            }
        }

        protected void Application_Start(object sender, EventArgs e)
        {
            (new AppHost()).Init();
        }
    }
}
```

このままではまだ動かない。
WebプロジェクトにあるWeb.configに以下の記述を追加する。

```xml:Web.config
    <system.web>
      <httpHandlers>
        <add path="*" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*"/>
      </httpHandlers>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
    </system.web>
    <!-- Required for IIS7 -->
    <system.webServer>
      <modules runAllManagedModulesForAllRequests="true"/>
      <validation validateIntegratedModeConfiguration="false" />
      <handlers>
        <add path="*" name="ServiceStack.Factory" type="ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack" verb="*" preCondition="integratedMode" resourceType="Unspecified" allowPathInfo="true" />
      </handlers>
    </system.webServer>
```

ここまで来れば、もうWebで動作確認が取れるまでには動くようになっている。
しかし待って欲しい。まぁドクペでも飲んで一息入れようじゃないか・・・。

このまま、クライアント側でサービスの参照をすれば、これまたいろいろWarningやらErrorやらでまともに参照できない。
クライアントをJavaScriptや、C#以外の言語で作るなら問題ないかもしれないけど、今回はクライアントもC#で組むので、あと少し、ほんの少しだけ味付けが必要。

それは・・・・
**InterfaceプロジェクトとServiceModelプロジェクトのAssemblyInfo.csにContractNamespaceを記入する！**
これが無いと「 *参照がおかしいぞバカ野郎！* 」って怒られるのよね・・・うぐぅ。
冒頭にお伝えした"癖"ってのがここにあったりする。

とりま、それぞれ以下のように書く。あ、System.Runtime.Serializationを忘れずに！
InterfaceプロジェクトのAssemblyInfo.csは・・・

```csharp:AssemblyInfo.cs
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStackHelloSample.Interface")]
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStackHelloSample.Interface.Types")]
```

ServiceModelプロジェクトのAssemblyInfo.csは・・・

```csharp:AssemblyInfo.cs
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStackHelloSample.ServiceModel.Operations")]
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStackHelloSample.ServiceModel.Types")]
```

_**お気付きになられただろうか？**_
両方とも **Types** っていうのを書いておかなければならない。これ重要。
ここまで来てやっと！クライアントでサービス参照が出来るWeb Serviceのできあがりです。わー88888

#まとめ#
ポイントは以下の通り。

* Request / Response DTOはプロジェクトを分けて書く。クライアントで使うから！
* Request / Response DTOのNamingルールに気をつける！
* [DataContract]と[DataMember]をRequest / Response DTOに付け忘れるな！
* InterfaceとServiceModelのAssemblyInfo.csにもContractNamespaceを忘れない！
* AssemblyInfo.csのContractNamespaceには実体は無くてもTypesを付け加えておく！

以上、5点を忘れないようにすれば無問題。
おつかれさまでした～　（CV：武部沙織）

次回、クライアント編でございます～。

*****

今回のソースコードはこちらからドウゾ＞　[GitHub : https://github.com/LainZero/ServiceStackHelloSample](https://github.com/LainZero/ServiceStackHelloSample)