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を用意しよう。
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もお忘れ無く。
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プロジェクトの中に書く。
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 アプリケーション ファイル ]を作っておく。
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に以下の記述を追加する。
<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は・・・
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStackHelloSample.Interface")]
[assembly: ContractNamespace("http://schemas.servicestack.net/types", ClrNamespace = "ServiceStackHelloSample.Interface.Types")]
ServiceModelプロジェクトの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