LoginSignup
2
2

More than 5 years have passed since last update.

Hello! ServiceStack [Web Service編]

Last updated at Posted at 2013-08-09

ServiceStackってなんぞや?

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

ServiceStack
ServiceStack(GitHub)

ただ、ちょっと癖があったり、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を用意しよう。

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とする。

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

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プロジェクトの中に書く。

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 アプリケーション ファイル ]を作っておく。

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に以下の記述を追加する。

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は・・・

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は・・・

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

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2