JSON API






4.90/5 (101投票s)
简单介绍如何将JSON API共享给Web和桌面。
目录
引言
大家好,好久不见,是吧?嗯,我没有闲着,实际上我正在为一个大型的开源开发者工具工作;它是一个组织工具,占用了我所有的时间。事实上,不仅是我,它也占用了 fellow CodeProjecter Pete O'Hanlon 的不少时间,他愚蠢地、呃,好心地自愿帮助我创建这个工具。
这个工具进展顺利,它实际上是一个 ASP MVC 3 网站,并且我认为其中一些东西非常有用,所以我将创建几篇文章介绍它使用的一些内容,当然我也会写一两篇关于它是如何工作的文章。
那么这篇文章是关于什么的呢?嗯,Pete O'Hanlon 和我正在开发的这个工具需要做的一件事就是公开一个 JSON(Java Script Object Notation)API,供人们使用。这个相同的 API 也需要能够从标准的 .NET 应用程序中调用。这实际上就是这篇文章要讲的。它展示了一种(有很多种方法,这只是一种)方法,你可以用它来公开一个 JSON API,既可以从 Web 调用,也可以通过基于 Web 的 API 从标准的桌面 .NET 客户端应用调用,而且麻烦最少,没有配置,除了 .NET 安装自带的标准配置。
不过,它确实使用了 ASP MVC 3,所以这是假定的,.NET 4 和 VS2010 也是如此。
可用框架
乍一看,你可能会认为这个问题非常适合某种 WCF 服务,这种服务可以同时被 JavaScript 和标准的 .NET 代码调用。所以这给了我们两种选择:
RESTful WCF
这个功能在 .NET 3.5 SP1 中出现,它允许你编写一个普通的 WCF 服务,你可以用特殊的 Web 属性进行标记,例如:
[ServiceContract]
public interface ICalculator
{
[OperationContract]
[WebInvoke(UriTemplate = "add?x={x}&y={y}")]
long Add(long x, long y);
[OperationContract]
[WebInvoke(UriTemplate = "sub?x={x}&y={y}")]
long Subtract(long x, long y);
[OperationContract]
[WebInvoke(UriTemplate = "mult?x={x}&y={y}")]
long Multiply(long x, long y);
[OperationContract]
[WebInvoke(UriTemplate = "div?x={x}&y={y}")]
long Divide(long x, long y);
[OperationContract]
[WebGet(UriTemplate = "hello?name={name}")]
string SayHello(string name);
}
public class CalcService : ICalculator
{
public long Add(long x, long y)
{
return x + y;
}
public long Subtract(long x, long y)
{
return x - y;
}
public long Multiply(long x, long y)
{
return x * y;
}
public long Divide(long x, long y)
{
return x / y;
}
public string SayHello(string name)
{
return "Hello " + name;
}
}
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("https://:8000/");
WebServiceHost svcHost =
new WebServiceHost(typeof(CalcService), baseAddress);
try
{
svcHost.Open();
Console.WriteLine("Service is running");
Console.WriteLine("Press enter to quit...");
Console.ReadLine();
svcHost.Close();
}
catch (CommunicationException cex)
{
Console.WriteLine("An exception occurred: {0}", cex.Message);
svcHost.Abort();
}
}
}
但是你还需要使用一个新的 WebServiceHost
来托管这个服务,并且你还必须为服务使用一个特定的端口。
我很久以前就写过一篇关于这个的相当不错的文章;如果你感兴趣,可以在 https://codeproject.org.cn/KB/smart/GeoPlaces.aspx 阅读。
WCF Web API
.NET 开发者可以选择的第二个选项是使用 WCF Web API,这是我最喜欢的微软开发人员之一 Glenn Block 团队在推广的。它可以被看作是 RESTful WCF 的一种进步。它相当新,并且(还没有)包含在 .NET Framework 中。
下面是一个关于如何使用 WCF Web API 配置服务的简单示例,这通常会放在一个网站中(例如 ASP MVC 网站):
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Net;
using System.Net.Http;
using Microsoft.ApplicationServer.Http.Dispatcher;
namespace RESTFul_WCF
{
/// <summary>
/// Demo service using the new WEB WCF APIs
/// </summary>
[ServiceContract]
public class EFResource
{
int dummyCounter = 0;
[WebGet(UriTemplate = "",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
public IQueryable<Models.Author> Get()
{
//dummy code, this would hit database normally
List<Models.Author> authors = new List<Models.Author>();
for (int i = 0; i < 5; i++)
{
authors.Add(new Models.Author(
i,string.Format("Some Author_{0}", i.ToString())));
}
return authors.AsQueryable();
}
[WebInvoke(UriTemplate = "", Method = "POST",
RequestFormat = WebMessageFormat.Json,
ResponseFormat = WebMessageFormat.Json)]
public Models.Author Post(Models.Author author)
{
if (author == null)
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
//dummy code, this would hit database normally
author.Id = dummyCounter++;
return author;
}
}
}
你可能会在你的 Global.asax.cs 文件中看到这个(这是 ASP MVC 特有的,我确信如果没有使用 ASP MVC,也会有等效的设置)
private void Application_Start(object sender, EventArgs e)
{
// setting up contacts services
RouteTable.Routes.MapServiceRoute<EFResource>("ef");
}
注意:文章的一位读者实际上指出,你可以让 WCF Web API 与 ASP MVC 及其路由功能良好配合。虽然这没有包含在附加的演示应用中,但你可以这样做。
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.Add(new ServiceRoute("api/resource",
new HttpServiceHostFactory(), typeof(EFResource)));
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
}
这就是服务部分的一切(好吧,还有一小部分配置,但比旧版本的 WCF 少了很多)。
那么消费客户端呢?它看起来会是什么样子?嗯,它看起来就像这样,这是它的全部内容,完全不需要配置
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Xml.Serialization;
using Microsoft.ApplicationServer.Http;
using Models;
namespace RestFul_Test
{
class Program
{
private enum MimeFormat { JSON, Xml };
static void Main(string[] args)
{
string uri = "https://:8300/ef";
//GET Using JSON
HttpClient client = GetClient(uri, MimeFormat.JSON);
var response = client.Get(uri);
Console.WriteLine("=========GET==============");
foreach (Author author in response.Content.ReadAs<List<Author>>())
{
LogAuthorResultToConsole(author);
}
//POST using JSON
Console.WriteLine("\r\n");
Console.WriteLine("=========POST==============");
var newAuthor = new Author { Name = "Xml Barber" };
var request = new HttpRequestMessage(HttpMethod.Post, new Uri(uri));
request.Content = new ObjectContent<Author>(newAuthor, "application/json");
request.Headers.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
response = client.Send(request);
var receivedAuthor = response.Content.ReadAs<Author>();
LogAuthorResultToConsole(receivedAuthor);
Console.ReadLine();
}
private static void LogAuthorResultToConsole(Author author)
{
Console.WriteLine(string.Format(CultureInfo.InvariantCulture,
"\r\n Author Name: {0}, Author Id: {1}", author.Name, author.Id));
}
private static HttpClient GetClient(string uri, MimeFormat format)
{
var client = new HttpClient(new Uri(uri));
switch (format)
{
case MimeFormat.Xml:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/xml"));
break;
case MimeFormat.JSON:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
break;
}
return client;
}
}
}
我很喜欢这个,但它需要使用很多额外的 DLL,即使是客户端也需要一些额外的 DLL。
注意:我在文章的开头包含了一个小的演示应用,因为我认为它可能会引起一些人的兴趣。
这些框架存在的问题
有几个问题需要考虑,我将逐一在下面介绍
RESTful WCF
使用 RESTful WCF(在 .NET 3.5 SP1 中可用)本可以奏效,但有几个障碍
- 它需要使用额外的端口。现在,由于这是网站的一部分,我已经为实际的网站使用了一个端口。使用 RESTful WCF 之后,我将需要维护另一个端口。
- .NET 客户端需要 WCF DLL 以及一些特殊的 REST WCF DLL。
- 需要创建客户端代理。
- 为客户端和服务器维护一个 App.Config 用于所有的 WCF 配置。
- 如果正确操作,则使用 eTags。
- 也许需要深入 MessageInspector 来更改
HttpRequest
的ContextType
;JSON 是支持的,所以那应该是可以的,但你明白我的意思吗?
WCF Web API
我非常喜欢 Glenn Block 和他的团队正在开发的 WCF Web API;然而,对我来说,它也有一些问题,即:
- 阻止我使用 WCF Web API 的原因是服务器上需要大量的额外 DLL;当我安装 WCF Web API 的 nuget 包时,我感到非常震惊。
- 即使是客户端也需要额外的 DLL(
HttpClient
等)。
好处是无需任何配置,它就能工作。好吧,你确实需要一些额外的 WCF Contrib 东西才能让它与 DataContract
序列化良好工作,但这还可以容忍。
尽管如此,ASP MVC 对 WCF Web API 有相当好的支持,你可以在这里阅读:http://wcf.codeplex.com/wikipage?title=Getting%20started:%20Building%20a%20simple%20web%20api。正如我所说,我真的很喜欢 WCF Web API,如果不是因为需要那么多 DLL,我可能就会选择它了。
一个可能的解决方案(至少对我来说是有效的)
现在我已经概述了现有解决方案中让我不满的地方,我真的还有什么别的选择吗?我真正想要的是没有额外的端口需要维护/打开,没有配置,没有额外的 DLL,代码应该在通过 JavaScript 调用时工作,例如通过 jQuery 调用,并且从标准的 .NET 客户端应用程序使用标准的 .NET Web API 调用。
使用 ASP MVC
我得出的逻辑结论是直接使用 ASP MVC。这有很多好处,即:
- ASP MVC 控制器可以被任何 JavaScript 调用,包括 jQuery,当然。
- ASP MVC 的路由已经存在。
- 网站已经在一个端口上可用,不需要再开放另一个端口。
- ASP MVC 控制器就是一个 URL,因此可以轻松地被标准的 .NET Web API 调用。
- ASP MVC 3(我正在使用的是这个)实际上自带了某些
ValueProviderFactory
对象,其中JsonValueProviderFactory
是其中之一。
基本上,ASP MVC 为你做了很多工作。
那么这通常会是什么样子呢?好吧,我们来看看,好吗?
这是一个完整的 ASP MVC 3 控制器,它接受 JSON 并返回 JSON。那里有三个不同的操作,我们将在本文后面讨论它们。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Common;
using System.IO;
using System.Text;
using System.Runtime.Serialization.Json;
using CodeStash.Filters;
using System.Json;
using RestfulWebSite.ModelBinders;
namespace RestfulWebSite.Controllers
{
/// <summary>
/// This controller shows 3 different methods of accepting JSON values
/// 1. Accepts JSON from JavaScript in the browser,
/// and also from .NET client app using standard web APIs
/// 2. Accepts JSON from JavaScript in the browser
/// 3. Uses JSONValue API to accept JSON as dynamic object
/// </summary>
public class RestController : Controller
{
/// <summary>
/// Uses special ActionFilter to convert desktop JSON data
/// into acceptable action value. Returns standard JSON result
/// </summary>
[JSONFilter(Param = "person", RootType = typeof(Person))]
public ActionResult Index(Person person)
{
int age = person.Age;
List<Person> people = new List<Person>();
for (int i = 0; i < 5; i++)
{
string s = string.Format("{0}_{1}", "hardCoded", i.ToString());
people.Add(new Person(i, s, new Parent(1, "parent")));
}
return Json(people);
}
/// <summary>
/// Accepts standard JSON, from JavaScript call.
/// Returns standard JSON result
/// </summary>
public ActionResult NoFilterJSON(Person person)
{
int age = person.Age;
List<Person> people = new List<Person>();
for (int i = 0; i < 5; i++)
{
string s = string.Format("{0}_{1}", "hardCoded", i.ToString());
people.Add(new Person(i, s, new Parent(1, "parent")));
}
return Json(people);
}
/// <summary>
/// Uses JSONValue to convert to dynamic object.
/// Returns standard JSON result
/// </summary>
public ActionResult JsonValue(
[DynamicJson(typeof(Person))]
JsonValue person
)
{
var x = person.AsDynamic();
int age = x.Age;
List<Person> people = new List<Person>();
for (int i = 0; i < 5; i++)
{
string s = string.Format("{0}_{1}", "hardCoded", i.ToString());
people.Add(new Person(i, s, new Parent(1, "parent")));
}
return Json(people);
}
}
}
自定义 MVC 行为
对于上面显示的第一种操作,当直接从标准的 .NET 客户端(至少是本文附带的客户端代码)调用此 ASP MVC 控制器代码时,必须执行的一件事是使用自定义的 ActionFilterAttribute
来提供控制器操作模型数据。
下面展示了这一点
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Json;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Text;
using System.Json;
namespace CodeStash.Filters
{
public class JSONFilter : ActionFilterAttribute
{
public string Param { get; set; }
public Type RootType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
string json = filterContext.HttpContext.Request.Form[Param];
string contentType = filterContext.HttpContext.Request.ContentType;
switch (contentType)
{
//Which is what you get if you use the WebClient in your code.
//Which is what the .NET client code is using
case "application/x-www-form-urlencoded":
if (json == "[]" || json == "\",\"" || String.IsNullOrEmpty(json))
{
filterContext.ActionParameters[Param] = null;
}
else
{
using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
{
filterContext.ActionParameters[Param] =
new DataContractJsonSerializer(RootType).ReadObject(ms);
}
}
break;
case "application/json":
//allow standard Controller/ASP MVC JSONValueProvider to do its work
//we can't do a better job than it, so let it deal with it
return;
default:
filterContext.ActionParameters[Param] = null;
break;
}
}
catch
{
filterContext.ActionParameters[Param] = null;
}
}
}
}
这段代码运行,这要归功于我们如下在附件的演示应用中使用这个专门的 ActionFilterAttribute
。
[JSONFilter(Param = "person", RootType = typeof(Person))]
public ActionResult Index(Person person)
{
.....
}
一些更有眼光的你会注意到我们在这里做了两件事:
- 如果 HTTP ContentType 是 "application/x-www-form-urlencoded",我们会尝试使用
DataContractJsonSerializer
来为控制器操作模型提供数据。为什么要这样做?嗯,在附件的演示代码中,.NET 客户端应用程序使用WebClient
Web 类,它使用 "application/x-www-form-urlencoded
" HTTP ContentType。它不允许你更改,这很公平,因为WebClient
暴露了一个值集合,可以接受任何东西,所以它必须使用这个 ContentType。你将在本文后面看到更多关于这一点的内容。 - 如果 HTTP ContentType 是 "
application/json
",我们允许 ASP MVC 提供 JSON 数据,因为它内置了对这个的支持,这要归功于内置的JsonValueProviderFactory
。它做得很好,所以让它去做吧。
JSONValue
在继续查看 .NET 客户端和 jQuery 演示之前,我想稍微偏离一下主题,谈谈一个有趣的 API,它来自于 WCF Web API 工作,但也可以作为独立的 nuget 包使用。
这个独立包名为 JSONValue
,可以通过在 Visual Studio 中添加包引用来获得。
演示控制器操作的第三个使用了 JSONValue
。
JSONValue
带来的好处是它提供了一些 JavaScript 对象周围的包装器/转换器,它还支持动态属性。我认为最好的方式之一就是看看它的例子。
所以,就像我们之前通过自定义 ActionFilterAttribute
扩展 ASP MVC 一样,ASP MVC 也通过使用专门的模型绑定器来支持可扩展性,所以让我们看一个例子,好吗?
所以,在我们的控制器中,我们有这个,看它是如何简单地接受一个 JsonValue
,并且在实际控制器的操作中,它能够使用 AsDynamic()
方法来获取接收到的类型的正确属性值。
public ActionResult JsonValue(
[DynamicJson(typeof(Person))]
JsonValue person
)
{
var x = person.AsDynamic();
int age = x.Age;
}
在这里可以看到我正在使用一个特殊的 DynamicJsonAttribute
,它看起来像这样:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace RestfulWebSite.ModelBinders
{
public class DynamicJsonAttribute : CustomModelBinderAttribute
{
private Type rootType;
public DynamicJsonAttribute(Type rootType)
{
this.rootType = rootType;
}
public override IModelBinder GetBinder()
{
return new DynamicJsonBinder(rootType);
}
}
}
这个属性负责创建作为被标记对象模型值的数据。它通过使用一个 DynamicJsonBinder
类的内部实例来做到这一点,该实例看起来像这样:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.IO;
using System.Json;
using System.Runtime.Serialization.Json;
using System.Text;
namespace RestfulWebSite.ModelBinders
{
public class DynamicJsonBinder : IModelBinder
{
private Type rootType;
public DynamicJsonBinder(Type rootType)
{
this.rootType = rootType;
}
public object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
try
{
var inpStream = controllerContext.HttpContext.Request.InputStream;
inpStream.Seek(0, SeekOrigin.Begin);
string bodyText;
using (StreamReader reader = new StreamReader(
controllerContext.HttpContext.Request.InputStream))
{
bodyText = reader.ReadToEnd();
}
string contentType = controllerContext.HttpContext.Request.ContentType;
object result=null;
switch(contentType)
{
case "application/json":
case "application/json; charset=UTF-8":
if (!String.IsNullOrEmpty(bodyText))
{
result= JsonValue.Parse(bodyText);
}
break;
default:
result= null;
break;
}
return result;
}
catch(Exception ex)
{
return null;
}
}
}
}
现在这可能听起来有点多,但希望当你看到调用代码时,一切都会变得清晰。让我们继续看看吧,好吗?
演示:浏览器支持
演示控制器操作中的所有三个都接受由以下三个 jQuery 片段生成的 JSON,它们实际上都相同,除了它们调用的实际 ASP MVC 控制器操作之外。
$(document).ready(function () {
var person = { Age: 1, Name: "person1" };
$("#btnActionFilter").click(function () {
$.ajax({
url: "/Rest/Index",
type: "POST",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(person),
success: function (response) {
alert(response);
$("#personContainer").empty()
$("#personTemplate").tmpl(response).appendTo("#personContainer");
}
});
});
$("#btnNoFilterJSON").click(function () {
$.ajax({
url: "/Rest/NoFilterJSON",
type: "POST",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(person),
success: function (response) {
alert(response);
$("#personContainer").empty()
$("#personTemplate").tmpl(response).appendTo("#personContainer");
}
});
});
$("#btnJSONValue").click(function () {
$.ajax({
url: "/Rest/JsonValue",
type: "POST",
dataType: "json",
contentType: 'application/json',
data: JSON.stringify(person),
success: function (response) {
alert(response);
$("#personContainer").empty()
$("#personTemplate").tmpl(response).appendTo("#personContainer");
}
});
});
});
我还包含了一些(纯粹为了好玩)——使用 jQuery Templates,它允许你重复使用带有占位符的 HTML 片段,占位符将使用 JSON 对象填充。
这是演示代码中的一个 jQuery Template。
<div>
<h1>Results</h1>
<div id="personContainer"></div>
</div>
<script id="personTemplate" type="text/x-jQuery-tmpl">
<div>
<p><strong>Person</strong>
<br/>
Age:${Age}
<br/>
Name:${Name}
<br/>
TimeStamp:${TimeStamp}
<br/>
</div>
</script>
这基本上就是用来显示控制器操作方法调用结果的。很不错,对吧?jQuery Template 还有更多功能,如果你有时间,值得深入研究。
演示:桌面 .NET 客户端支持
剩下要做的就是向你展示如何使用一个标准的 .NET 客户端来调用 ASP MVC 控制器,该客户端使用标准的 .NET Web API。
对于演示应用程序,客户端代码看起来像这样(我们从这段代码中调用 REST 控制器的 Index
操作)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Collections.Specialized;
using System.Web.Script.Serialization;
using Common;
using System.Runtime.Serialization.Json;
using System.Runtime.Serialization;
using System.IO;
using System.Xml;
namespace ConsoleApplication1
{
class Program
{
internal static DataContractJsonSerializer jss;
private static WebClient client = new WebClient();
private static NameValueCollection values =
new System.Collections.Specialized.NameValueCollection();
static void Main(string[] args)
{
//Use ModelBinding in WebSite to resolve types to Controller Actions
Person pers = new Person(1, "name", null);
AddValue(values,"person", pers);
//NOTE : WebClient doesn't allow you to set ContentType header to "application/json" when using the UploadValues() method
// which is a shame as it would be very nice. But since the WebClient allows
// you to add anything to its collection of values, it makes sense to restrict the
// WebClient ContentType header to "application/x-www-form-urlencoded" (the default)
// as you can't really know what data you are sending, could be anything being sent up
// in one go, so what ContentType could be reasonably provided except
// "application/x-www-form-urlencoded"
// Also the WebClient is kind of a dumbed down HttpRequest,
// so its more limited, but also more convenient
Byte[] results = client.UploadValues("https://:8300/Rest/Index", values);
//get results
List<Person> people = GetValue<List<Person>>(results);
Console.ReadLine();
}
internal static T GetValue<T>(Byte[] results) where T : class
{
using (MemoryStream ms = new MemoryStream(results))
{
jss = new DataContractJsonSerializer(typeof(T));
return (T)jss.ReadObject(ms);
}
}
internal static void AddValue(NameValueCollection values, string key, object value)
{
jss = new DataContractJsonSerializer(value.GetType());
using (MemoryStream ms = new MemoryStream())
{
jss.WriteObject(ms, value);
string json = Encoding.UTF8.GetString(ms.ToArray());
values.Add(key, json);
}
}
}
}
这都是相当简单的事情。我们只需要使用 WebClient
和 DataContractJsonSerializer
来形成我们的 NameValueCollection
并向网站发出请求。所有都是标准操作,但要让所有这些部分协同工作确实花了我不少时间,所以我认为这篇文章可能会让其他人受益。
正如我一直在强调的,这只需要标准的 .NET 类,零配置,没有特定于调用的端口,只需要网站 URL,我们就自己进行非常精简的序列化。实际上,使用 JSON 作为序列化格式相当不错,因为它与其他序列化格式相比非常轻量,而且也非常易于人类阅读,这是 SOAP 格式有点受苦的地方,我觉得。
更多
自 1. 我写这篇文章以来,一位 codeproject 用户“Simonotti Paolo”也在做和我同样的事情,我们都经历了一个顿悟的时刻,哇,我们不孤单。无论如何,Simonotti 展示了一种可以使用 ContentType application/json
和 WebClient
的方法,他好心地同意我在这里包含它。所以如果你真的想使用 ContentType application/json
。方法如下:
你的桌面客户端代码将如下所示,而不是我之前的代码:
public static class JsonExtensionMethods
{
public static T JsonInvoke<T>(this WebClient client, string methodUri, object argument) where T : class
{
T res = default(T);
client.Headers.Add("Content-Type", "application/json");
byte[] jsonRequest = Encoding.UTF8.GetBytes(argument.ToJson());
byte[] jsonResponse = client.UploadData(methodUri, jsonRequest);
res = jsonResponse.JsonDeserializeTo<T>();
return res;
}
public static string ToJson(this object obj)
{
JavaScriptSerializer jss = new JavaScriptSerializer();
return jss.Serialize(obj);
}
public static T JsonDeserializeTo<T>(this byte[] bytes) where T:class
{
T res = null;
DataContractJsonSerializer jss = new DataContractJsonSerializer(typeof(T));
using (MemoryStream ms = new MemoryStream(bytes))
{
res=(T)jss.ReadObject(ms);
}
return res;
}
}
你将在你的桌面应用程序中这样使用它:
string uri="https://:8300/Rest/NoFilterJSON";
Person pers1 = new Person(1, "àèìòù", null);
Person pers2 = new Person(2, "àèìòù2", null);
Dictionary<string, object> values = new Dictionary<string, object>()
{
{ "person", pers1 },
{ "person2", pers2 }
};
//with dictionary
List<Person> people1 = client.JsonInvoke<List<Person>>(uri, values);
//with anonymous type
List<Person> people2 = client.JsonInvoke<List<Person>>(uri, new { person=pers1, person2=pers2 } );
我认为这两种方法都有其优点,我将让你选择,你拥有工具,尽情享受吧。
就这样
总之,这就是我现在想说的全部内容。我意识到这不是我通常的 WPF 类型文章,但我认为它仍然有用,并且向你展示了如何创建一些可以从 Web/桌面调用、零配置且代码量很少的代码。
如果你喜欢这篇文章,请花点时间给我一个投票/评论,我将不胜感激。