2011-11-17 5 views
5

VS2010に組み込まれたWebサービスが稼働しています。basicHttpBindingを使用してWCFサービスを拡張し、JSONと通信するRESTサービスを許可する良い方法はありますか?

運用契約のいくつかは、次のようになります。

[OperationContract] 
    ITicket Login(string userName, byte[] passwordHash, string softwareVersion); 

すなわち、それらのブースは複雑な議論と複雑なリターン・タイプ、あるいは複数のリターンを持っています。

私たちは最近、アウトソーシングされたiPhoneプロジェクトを開始し、このサービスを使って私たちのサーバーと通信できるようにしています。 私は彼らから学んだことから、これはiPhoneへの通信のための良い習慣ではないことを理解しました(例えば、WSDLを使う良い方法がない)。したがって、JSONと通信するRESTサービスとしてこのサービスを公開する可能性を検討し始めました。

私はwebHttpBindingを使用して、新しいエンドポイントを追加した、このような契約を飾ら:

[OperationContract] 
    [WebGet(UriTemplate = "/login?username={userName}&password={password}&softwareVersion={softwareVersion}", ResponseFormat=WebMessageFormat.Json)] 
    ITicket Login(string userName, string password, string softwareVersion); 

意図したとおり、この方法は機能するようになりました。

私は、このような別の方法を飾るしようとした:私は今、これをアクセスしようとすると、私は、次のエラーが表示さ

[OperationContract] 
    [WebGet(UriTemplate = "/GetMetaData?ticket={ticket}",RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] 
    IMetaData GetMetaData(ITicket ticket); 

:私だけOperationContractを構築するために管理している

Server Error in '/Jetas5MobileService' Application. Operation 'GetMetaData' in contract 'IJetas5MobileService2' has a query variable named 'ticket' of type 'Jetas.MobileService.DataContracts.ITicket', but type 'Jetas.MobileService.DataContracts.ITicket' is not convertible by 'QueryStringConverter'. Variables for UriTemplate query values must have types that can be converted by 'QueryStringConverter'.

を引数として文字列をとり、DataContractJsonSerializerを使用してバックエンドのシンセを解析しますが、これは醜いハックのように感じます。

これを解決する方法はありますか? WCFとRESTについては初心者ですので、そこにある可能性のある初心者のチュートリアルを指摘するのを恐れません。私はそれらを検索しようとしましたが、膨大な量のソースが良いものを見つけるのを難しくしています。

+0

WCFのどのバージョンをお使いですか? –

+0

私は.net4とVS2010を使用していますが、その質問に答えますか?それ以外は私がどのように見えるか教えてください。 –

答えて

2

From what I have learnt from them I understood that this is not a good practice for communicating to the iPhone (lack of good ways to consume the WSDL for example).

最大の問題は、優れた「ツール」の欠如ではなく、WSDLとWebサービスの仕組みの理解の欠如です。開発者向けのサービススタブを生成するこれらのツールはすべて、開発者が何がそのフードの下にあるのか理解できないようにしました。基本的なシナリオでは、すべての魔法が実行されますが、開発者が問題を追跡するか、「ツール」に追加機能を追加する必要があると、大きな問題が発生します(通常は悪い解決策になります)。正直なところ、SW開発は基本的なシナリオではありません。

RESTは「マジック」ツールを提供しないため、開発者にとって大きな課題です。 RESTはHTTPプロトコルの正しい使い方であり、既存のHTTPインフラストラクチャを最大限に活用します。 HTTPプロトコルの基本を理解することなく、良いRESTサービスを作成することはできません。それはあなたが始めるべきところです。ここで

は間違った使い方のいくつかの例です:

[OperationContract] 
[WebGet(UriTemplate = "/login?username={userName}&password={password}&softwareVersion={softwareVersion}", ResponseFormat=WebMessageFormat.Json)] 
ITicket Login(string userName, string password, string softwareVersion); 

Login方法は、明らかに何らかのアクションを実行するものです - 私はそれがチケットを作成すると思います。 GET HTTPリクエストにはまったく適していません。これは間違いなく、各呼び出しのために新しいITicket表現を返すログインリソースへのPOSTリクエストになるはずです。どうして? GETリクエストは安全であり、冪等であると考えられているからです。

  • 安全:要求は副作用を起こしてはいけません=リソースに何も変更すべきではありませんが、あなたのケースではおそらく新しいリソースが作成されます。
  • Idempotent:すでに安全ルールに違反しているが、リソースへのリクエストを再現可能にする必要があるため、この例ではあまり重要ではありません。つまり、同じユーザー名、パスワード、およびバージョンを持つ最初のリクエストで新しいリソースを作成できますが、リクエストが再度実行されたときに新しいリソースを作成してはいけません。これは、リソースがサーバー上で永続/維持されている場合にはより意味があります。

HTTP GET要求は、HTTPインフラストラクチャによるもので、安全で冪等であると考えられるため、別の方法で処理されます。例えば、GETリクエストはリダイレクトされてキャッシュされます。リクエストが安全で冪等でないときは、POSTメソッドを使うべきです。正しい定義は

[OperationContract] 
[WebInvoke(UriTemplate = "/login?username={userName}&password={password}&softwareVersion={softwareVersion}", ResponseFormat=WebMessageFormat.Json)] 
ITicket Login(string userName, string password, string softwareVersion); 

です.WebInvokeはデフォルトでPOSTメソッドになっているためです。これは、すべてのプロトコルトンネリング(たとえばSOAP)が通常はすべての要求に対してPOST HTTPメソッドを使用する理由です。

前の例のもう1つの問題は、HTTPインフラストラクチャをフルに活用したRESTアプローチです。 HTTPベースの認証(ログイン)= Basic、Digest、OAuthなどを使用する必要があります。類似のリソースを持つことはできませんが、まず標準のHTTP方法を検討する必要があります。

2番目の例は実際にははるかに優れていますが、WCFの制限に問題があります。 WCFはURLから基本型だけを読み込むことができます(btw。URLにオブジェクトをどのように渡しますか?)。他のパラメータ型では、カスタムWCF動作が必要です。あなたはJSONデータをポストする必要があり

[OperationContract] 
[WebInvoke(UriTemplate = "/GetMetaData",RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)] 
IMetaData GetMetaData(ITicket ticket); 
+0

偉大なフィードバックをありがとう!私はHTTPプロトコルについてさらに読むつもりです。私はすでに一つの質問があります。 GetMetaDataは基本的に、チケットに応じてデータを返すクエリです。 http://www.w3.org/2001/tag/doc/whenToUseGet.html#checklistを読むと、これはGETがこの操作に最も適していると解釈します。つまり、サーバーの状態は同じです。 POSTが好まれるという複雑なタイプの議論のためでしょうか? –

+0

はい、GETには適していますが、WCFのデフォルト機能セットのために、メソッド定義では複雑な型を受け入れるPOSTが必要です。 –

2

WCFレストスターターキットを使用して同様の問題に直面しました。

正しく覚えていれば、パス内のUriTemplate変数は、WebGetまたはWebInvokeを使用しているときに常に文字列に解決されます。 UriTemplate変数は、UriTemplateのクエリ部分にあるときにint、longなどにバインドすることしかできません。 したがって、に複雑なオブジェクトを渡す手段はありません。

私はそれを行うためのクリーンな方法はないと思う。私はちょうどあなたが行うように解析ソリューションを使用しました。

ここで、WCF Web ApiというWCFでRESTを実行するための新しいスタックをチェックアウトすることができます。メソッドのパラメータとして複雑な型を非常にうまく扱います。

+0

ありがとう!私はそれを見てみましょう。 –

1

: - あなたはデータコントラクトを受け入れる方法を公開する必要がある場合は、再び体内にパラメータを受け入れるHTTPメソッドを使用する必要があり、再びリクエストのボディにPOSTと場所JSONシリアライズされたチケットを使用しますあなただけの新しいJSONエンドポイントを追加し、新しいされ、それが立って仕方、既存のエンドポイントと設定を残して(次のように

[OperationContract] 
    [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, 
     UriTemplate = "/login", BodyStyle = WebMessageBodyStyle.Wrapped)] 
    ITicket Login(string userName, string password, string softwareVersion); 

次に、あなたの設定に新しいエンドポイントを追加します。方法へとセットアップのような宣言ができます行動):

<service behaviorConfiguration="Your.ServiceBehavior.Here" name="Your.Stuff.Here"> 
     <endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicBindingSettings" behaviorConfiguration="basic" contract="Your.Contract.Here"> 
     </endpoint> 
     <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> 
     <endpoint address="json" binding="webHttpBinding" contract="Your.Contract.Here" behaviorConfiguration="web"></endpoint> 
     </service> 
<behaviors> 
     <endpointBehaviors> 
     <behavior name="web"> 
      <webHttp /> 
     </behavior> 
    </behaviors> 

次に、URL「https://yourdomain.com/service.svc/json/login」に「{"userName": "testuser"、 "password": "testpass"、 "softwareVersion": "1.0.0"}」などを投稿できます。

複雑な型を渡す場合は、カスタムオブジェクトと一致するJSONを渡すだけで済みます。したがって、色とサイズのプロパティを持つ動物オブジェクトがある場合、JSONは "{" animal ":{" Color ":" red "、" Size ":" Large "}}"のようになります。

これについてはこれを行う必要があり、メソッドの実装を変更する必要はありません。 WCFは、上記の方法でJSONエンドポイントに対して呼び出されると、JSON形式のデータを返します。既存のSOAPメソッドは引き続き正常に動作します。

+0

私のエンドポイントとメソッド "login"の両方が私に適しています。より複雑な型を試してみると、エラーが始まります。 –

+0

私は既にあなたの投稿にいくつかのものが含まれていることを理解していますが、他の誰かがこの問題を抱えている場合に備えて、完全性のために上から下へステップを進んでいました。私が説明したシナリオの複雑な型のキーは、RequestFormat = WebMessageFormat.Jsonを設定してJSON要求を適切にフォーマットすることです。 – GCaiazzo

関連する問題