4

長年のラーチャー、初めてのポスターはこちら。私はこの問題に数日間取り組んできましたが、ヒントをいただければ幸いです。私はここで問題を以下に分解します。

達成しようとしていること:
JSON WCF Webサービスをセットアップしたいのですが、WCFに付属しているシリアライザーの代わりにJSON.netシリアライザーを使用したいと思います。なんで?WCFに付属しているものを使用してシリアル化すると、コレクションが肥大化することがわかったためです(以下に意味の例を示します)。サービスのエンドコンシューマーはJavaScriptクライアントになるので、JSONをナビゲートするためにクライアントに余分な操作を行わせたくありません。

私は自分が欲しいものの簡単な例を思いつき、それをC#で機能させることを試みました。長い間.NETを使用していなかったことを認めなければなりません。これは、おそらく私の速度低下の一因となっています。とにかく、私はそれで忍耐力などを在庫に持っています。

そのため、ユーザー名を受け入れ、ユーザーに関する情報を含むJSONオブジェクトを返すサービスが必要です。私はこのサービスを次のように呼ぶことを想定しました。

http://someHostName/whoareyou?username=paul

そして、サービスにこれで応答させます:

{
    "errorCode": 0,
    "payLoad"  :  {
        "userFullName": "Paul The Octopus",
        "userLevel"        : "Administrator"
    }
}

上記の応答のJSONオブジェクトをJavaScriptまたはPHPで簡単に使用でき、自分自身にとても満足しています。

いくつかのグーグルの後で、これは.NET Framework 4のWCFで簡単に実行できることを示唆するいくつかの投稿に出くわしました。しばらく前にコースでWCFをいじったことがありましたが、99%を長い間忘れていたので、見つけてフォローしました。私の目標に適応するためのこの投稿:http: //www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide#

試行1:
上記の投稿に続いて、希望どおりのWCFサービス(以下に示すコード)をセットアップできましたが、以下に示すように、結果のJSON出力は少し肥大化しました。

RestServiceImpl.svc.csファイル

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Newtonsoft.Json;
using System.Collections.Specialized;
//Based on this psot: http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide

namespace RestService
{
    public class RestServiceImpl : IRestServiceImpl
    {
        #region IRestService Members

        public WhoAreYouResponse whoareyou(string username)
        {
            var payLoad = new Dictionary<string, string>
            {
                {"userFullName", "Paul The Octopus"},
                {"userLevel", "Administrator"}
            };

            WhoAreYouResponse whoAreYouResponse = new WhoAreYouResponse
            {
                errorCode = 0,
                payLoad   = payLoad
            };

            return whoAreYouResponse;
        }

        #endregion
    }

    //Helper bits to be used in service implementation
    public class WhoAreYouResponse
    {
        public int errorCode { get; set; }
        public Dictionary<string,string> payLoad { get; set; }
    }
}

IRestServiceImpl.csファイル

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestService
{
    [ServiceContract]
    public interface IRestServiceImpl
    {
        [OperationContract]
        [WebInvoke(Method = "GET", 
            ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Bare, 
            UriTemplate = "json/whoareyou?username={username}")]
        WhoAreYouResponse whoareyou(string username);
    }
}

Web.configファイル

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <services>
      <service name="RestService.RestServiceImpl" behaviorConfiguration="ServiceBehavior">
        <endpoint address="" binding="webHttpBinding" contract="RestService.IRestServiceImpl" behaviorConfiguration="web">
        </endpoint>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ServiceBehavior">
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
      <endpointBehaviors>
        <behavior name="web">
          <webHttp/>
        </behavior>
      </endpointBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

*このようなブラウザからサービスを呼び出した結果http://192.168.0.84/TestRestService/RestServiceImpl.svc/json/whoareyou?username=paul*

{
    "errorCode":0,
    "payLoad"   : [
        {"Key":"userFullName", "Value":"Paul The Octopus"},
        {"Key":"userLevel","Value":"Administrator"}
    ]
}

JSON応答のスープの髪の毛は、Dictionaryオブジェクトが「payLoad」へのJSON応答でマップされた方法です。これはオブジェクトの配列ですが、JSONオブジェクトにはこの「キー」、「値」のビジネスがないと予想していました。私が欲しかったものではありません。近いですが、クライアント側で処理するにはかなり厄介です。肥大化や不要な作業が好きな人はいないので、これに賛成です。

ソリューションを探すためにさらにトローリングを行うと、ここで何が起こっているのかを示唆するいくつかのSO投稿を読みました。これは、サービスが組み込みのシリアライザーを使用しており、「他の方法で辞書」をシリアル化しないことです。私が期待していた形式でそれを取得するには、いくつかの追加の作業が必要になります。では、別のシリアライザーを使ってみませんか?この考えに続いて、私はここでこの悪い男の子について知りました:http: //james.newtonking.com/projects/json-net.aspx

これは、以下の2回目の試みにつながります。

試行2:
JSON.NETシリアライザーをダウンロードして私の小さなプロジェクトにインポートし、次のファイルを次のように変更しました(whoareyouメソッドの戻り値のタイプを文字列に変更します)。

RestServiceImpl.svc.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using Newtonsoft.Json;
using System.Collections.Specialized;
//Based on this psot: http://www.codeproject.com/Articles/105273/Create-RESTful-WCF-Service-API-Step-By-Step-Guide

namespace RestService
{
    public class RestServiceImpl : IRestServiceImpl
    {
        #region IRestService Members

        public string whoareyou(string username)
        {
            var payLoad = new Dictionary<string, string>
            {
                {"userFullName", "Paul The Octopus"},
                {"userLevel", "Administrator"}
            };

            WhoAreYouResponse whoAreYouResponse = new WhoAreYouResponse
            {
                errorCode = 0,
                payLoad   = payLoad
            };

            return JsonConvert.SerializeObject(whoAreYouResponse);
        }

        #endregion
    }

    //Helper bits to be used in service implementation
    public class WhoAreYouResponse
    {
        public int errorCode { get; set; }
        public Dictionary<string,string> payLoad { get; set; }
    }
}

IRestServiceImpl.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace RestService
{
    [ServiceContract]
    public interface IRestServiceImpl
    {
        [OperationContract]
        [WebInvoke(Method = "GET", 
            ResponseFormat = WebMessageFormat.Json, 
            BodyStyle = WebMessageBodyStyle.Bare, 
            UriTemplate = "json/whoareyou?username={username}")]
        string whoareyou(string username);
    }
}

そして、サービスが呼び出されると、次の応答が返されます。

"{
\"errorCode\":0,
\"payLoad\":{
    \"userFullName\":\"Paul The Octopus\",
    \"userLevel\":\"Administrator\"}
}"

勝者!それが私が望んでいたことであり、期待していたことです…。しかし。トラックをバックアップします。JSONオブジェクト全体が二重引用符で囲まれています!?うーん。これは、JSONオブジェクトを含む文字列です。スープから髪の毛を取り出して、ハエが飛び込んできました!

少し頭を悩ませた後、JSON.NETシリアライザーがチャームのように機能し、JSONオブジェクトを文字列に吐き出していることが明らかになりましたが、それはWCFシリアライザーを通過し、本質的に文字列化されます。したがって、返されるのはJSON文字列です。とても近い!実際、私のメソッドwhoareyouは文字列を返すと言っているので、ほとんど私のせいです。

だから、私の質問は、この問題のある子供にこの二重シリアル化ビジネスをやめさせるにはどうすればよいですか?whoareyouメソッドのreturnタイプがJSONオブジェクトのようなものであることがわかりません。代わりにJSON.NETシリアライザーを使用するようにWCFに指示する方法、またはそのようなソリューションはありますか?

ポインタは大歓迎です。

4

1 に答える 1

6

私が理解しているように、あなたはゼロからサービスを作成しており、RESTサービスの実装方法に制限はありません。次に、ASP.NETWebApiを使用することをお勧めします

http://www.asp.net/web-api

新しいWebサービス技術では、多くの定型コードがすでに実行されているため、従来のWebサービス技術を使用しないでください。

Web APIを使用すると、シリアライザー/フォーマッターを簡単に置き換えたり追加したりできます。それを行う方法は、次の記事で説明されています。

http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

私はあなたが説明したシリアル化の問題を経験し、このアプローチでそれらを解決しました。古いWebサービステクノロジ(WCF 3.5 Restスターターキット、Wcf 4 REST)に関する私の経験から、これははるかに難しい方法で実行できます。

于 2012-07-20T07:24:02.783 に答える