2012-07-20 39 views
4

长时间的lurcher,第一次海报在这里。 我一直在努力解决这个问题几天了,并会感谢任何提示。 我在下面讨论这个问题。WCF RESTful Web服务与JSON.Net:避免双重序列化

我想要实现:
我想成立一​​个JSON WCF的Web服务,但我想用JSON.net串行而不是带有WCF的一个。为什么?因为我发现序列化使用WCF自带的集合(我将在下面展示一个我的意思的例子)。该服务的最终用户将成为一个JavaScript客户端,所以我不想让客户端在浏览JSON时做额外的麻烦。

我想出了一个简单的例子,我想要什么,并着手尝试使它在C#中工作。我必须承认很长一段时间没有使用.NET,这可能会导致我的缓慢。无论如何,我已经有了耐心等待它。

所以,我想要一个接受用户名的服务,并返回一个带有用户信息的JSON对象。 我所设想的服务被称为是这样的:

http://someHostName/whoareyou?username=paul 

,并与该服务响应:

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

,我可以很容易地使用在JavaScript或PHP上述反应的JSON对象和感觉真的对我自己很好。

经过一些Google搜索后,我发现一些帖子提示在.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响应汤头发的结果是字典对象的JSON响应“有效载荷”被映射的出路。它是一个对象数组,而我期待的是一个JSON对象没有这个“Key”,“Value”业务。不是我想要的。关闭,但很挑剔在客户端处理。没有人喜欢膨胀和不必要的工作,所以大拇指向下。

做一些更多的解决方案我读了一些SO帖子,建议这里发生的事情是该服务使用内置的串行器 ,并且不会以任何其他方式序列化“字典”。需要一些额外的工作才能以我期待的格式获得它。 所以,我想,如何使用另一个序列化器? 按照这个想法,我发现了这个坏男孩在这里:http://james.newtonking.com/projects/json-net.aspx

这导致我下面的第二次尝试。

尝试采取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方法的返回类型,如JSON对象。 有没有办法告诉WCF使用JSON.NET序列化器,或者其他一些解决方案?

指针非常感谢。

回答

6

据我所知,您正在从头开始创建服务,对于REST服务的实施方式没有限制。那么我建议你使用ASP.NET的WebAPI

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

不要使用传统的Web服务技术,因为在newers大量的样板代码,您已经完成。

使用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 Rester Kit, Wcf 4 REST)的经验,它可以以更困难的方式完成。

+0

太棒了!感谢Regfor。是的,我从头开始创建这项服务,并有自由选择它的实施方式。我开始看看你提供的链接,他们看起来似乎比我想的要简单得多。我没有时间阅读和遵循教程,但很快就会把我之前发布的代码放在“我从中学到了东西,但改变了方向”的篮子。谢谢! – coderigo 2012-07-22 06:34:36