好久不见,第一次发帖。几天来我一直在努力解决这个问题,并希望得到任何提示。我在下面分解这个问题。
我想要实现的目标:
我想设置一个 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 对象,并且对自己感觉非常好。
经过一番谷歌搜索后,我发现一些帖子表明在 .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 对象在 JSON 响应中映射到“payLoad”的方式。它是一个对象数组,而我期待一个 JSON 对象没有这个“键”、“值”业务。不完全是我想要的。关闭,但在客户端处理起来非常挑剔。没有人喜欢臃肿和不必要的工作,所以对此表示赞同。
为解决方案做更多的拖钓我读了一些 SO 帖子,表明这里发生的事情是该服务正在使用内置的序列化程序,并且不会以任何其他方式序列化“字典”。需要一些额外的工作才能以我期望的格式获得它。所以,我想,使用另一个序列化程序怎么样?按照这个想法,我在这里发现了这个坏男孩:http: //james.newtonking.com/projects/json-net.aspx
这导致了我在下面的第二次尝试。
尝试 2:
下载 JSON.NET 序列化程序并将其导入我的小项目中,我将以下文件更改为如下所示(将whoareyou方法的返回类型更改为string):
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 序列化程序,或者一些这样的解决方案?
非常感谢指针。