Web API 入门 二 媒体类型
2017-11-03 14:51 糯米粥 阅读(409) 评论(0) 编辑 收藏 举报还是拿上面 那篇 Web API 入门 一 的那个来讲
在product类中加一个时间属性
初始化的时候。赋值为当前时间
然后通过浏览器访问,我这里是FF
当然。通过HttpClient也一样
你会发现。时间不是标准的时间格式,这里稍后讲。
这里还有一个问题。FF和后台代码。返回的数据。FF是xml格式。但HttpClient返回的是json格式
因为在HttpClient我设置了媒体格式
StringContent content = new StringContent(json); content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
当一条HTTP消息含有一个实体时,Content-Type(内容类型)报头指定消息体的格式。这是告诉接收器如何解析消息体的内容。
WebClient这样设置
WebClient client = new WebClient(); //设置请求头是json格式 client.Headers.Add("Content-Type", "application/json");
当客户端发送一条请求消息时,它可能包括一个Accept报头。Accept报头是告诉服务器,客户端希望从服务器得到哪种媒体类型。例如:
Accept: text/html,application/xhtml+xml,application/xml
该报头告诉服务器,客户端希望得到的是HTML、XHTML,或XML。
看看刚用FF访问API时候的报头信息
WebAPI默认是xml格式,上面可以看到
对于XML、JSON,以及URL编码的表单数据,已有了内建的支持
所以。在后台请求的时候。设置了媒体类型
client.Headers.Add("Content-Type", "application/json");
如果通过ajax请求的时候,希望也得到json格式的。那么需要设置 Media Formatter
代码有参考网络,注意。下面的方式一,方式二都可以,但只能用一个,不能同时用,包括JsonContentNegotiator类一样
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Web.Http; namespace WebApiDemo { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); #region 设置API返回数据格式 方式一 var json = config.Formatters.JsonFormatter; //设置格式化格式为:json格式 json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; //在管道中移除xml格式,其实就是统一用json格式化 config.Formatters.Remove(config.Formatters.XmlFormatter); #endregion #region 设置API返回数据格式 方式二 //清空默认xml、设置json //GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); //GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add( // new QueryStringMapping("datatype", "json", "application/json")); #endregion ConfigureApi(config); } public static void ConfigureApi(HttpConfiguration config) { var jsonFormatter = new JsonMediaTypeFormatter(); var settings = jsonFormatter.SerializerSettings; IsoDateTimeConverter timeConverter = new IsoDateTimeConverter(); //这里使用自定义日期格式 timeConverter.DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss"; settings.Converters.Add(timeConverter); settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter)); } public class JsonContentNegotiator : IContentNegotiator { private readonly JsonMediaTypeFormatter _jsonFormatter; public JsonContentNegotiator(JsonMediaTypeFormatter formatter) { _jsonFormatter = formatter; } public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters) { var result = new ContentNegotiationResult(_jsonFormatter, new MediaTypeHeaderValue("application/json")); return result; } } } }
现在FF运行看看效果
发现已经是json格式了
FF发送的Accept格式是,Accept报头是告诉服务器,客户端希望从服务器得到哪种媒体类型
Accept :text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
但API后台移除了XML格式。然后指定了application/json 媒体格式
仔细看。你会发现。是不是时间也正常了
这是因为。也做了时间格式化
如果直接在Register中这样注册。也是可以的。只是要移除XML格式,然后设置为json格式
因为这是针对json的格式化器
var settings = config.Formatters.JsonFormatter.SerializerSettings; IsoDateTimeConverter timeConverter = new IsoDateTimeConverter(); timeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; settings.Converters.Add(timeConverter); var j = GlobalConfiguration.Configuration.Formatters.JsonFormatter; j.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local; j.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd' 'HH':'mm':'ss"; j.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss" }); config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss" });
自定义媒体格式化器
就是将媒体类型格式化器添加到Web API管线,要使用HttpConfiguration对象上的Formatters属性。
演示:将Product对象序列化成一个逗号分隔的值(CSV)格式,
类还是上面那个prduct类
为了实现CSV格式化器,要定义一个派生于BufferedMediaTypeFormater的类:ProductCsvFormatter
既然是BufferedMediaTypeFormatter的派生类。显然要继承自:BufferedMediaTypeFormatter
ProductCsvFormatter类如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.IO; using System.Net.Http.Formatting; using System.Net.Http.Headers; using WebApiDemo.Models; using System.Net.Http; namespace WebApiDemo.Formatters { /// <summary> /// 自定义媒体类型格式化器 /// </summary> public class ProductCsvFormatter : BufferedMediaTypeFormatter { public ProductCsvFormatter() { // 添加所支持的媒体类型 SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/csv")); //SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); } /// <summary> /// 查询此 System.Net.Http.Formatting.MediaTypeFormatter 是否可以序列化指定类型的对象。 /// </summary> /// <param name="type"> 要序列化的类型。</param> /// <returns></returns> public override bool CanWriteType(Type type) { /* 格式化器可以序列化单个Product对象,以及Product对象集合。 */ if (type == typeof(Product)) { return true; } else { Type enumerableType = typeof(IEnumerable<Product>); return enumerableType.IsAssignableFrom(type); } //throw new NotImplementedException(); } /// <summary> /// 如果 System.Net.Http.Formatting.MediaTypeFormatter 可以反序列化该类型,则为 true;否则为 false。 /// </summary> /// <param name="type"> 要反序列化的类型。。</param> /// <returns></returns> public override bool CanReadType(Type type) { /* 重写CanReadType方法,以指示该格式化器可以解序列化哪种类型。 * 在此例中,格式化器不支持解序列化,因此该方法简单地返回false。 */ return false; } //public override void WriteToStream(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content) //{ // base.WriteToStream(type, value, writeStream, content); //} //public override void WriteToStream(Type type, object value, Stream writeStream, System.Net.Http.HttpContent content, System.Threading.CancellationToken cancellationToken) //{ // base.WriteToStream(type, value, writeStream, content, cancellationToken); //} /// <summary> /// 同步写入到缓冲流。 /// 重写WriteToStream方法。通过将一种类型写成一个流, /// 该方法对该类型进行序列化。如果你的格式化器要支持解序列化,也可以重写ReadFromStream方法。 /// </summary> /// <param name="type">要序列化的对象的类型</param> /// <param name="value"> 要写入的对象值。可以为 null。</param> /// <param name="stream"> 要写入到的流。</param> /// <param name="contentHeaders"> System.Net.Http.HttpContent(如果可用)。可以为 null。</param> public override void WriteToStream( Type type, object value, Stream stream, HttpContent content) { using (var writer = new StreamWriter(stream)) { var products = value as IEnumerable<Product>; if (products != null) { foreach (var product in products) { WriteItem(product, writer); } } else { var singleProduct = value as Product; if (singleProduct == null) { throw new InvalidOperationException("Cannot serialize type"); } WriteItem(singleProduct, writer); } } stream.Close(); } // 将Product序列化成CSV格式的辅助器方法 private void WriteItem(Product product, StreamWriter writer) { writer.WriteLine("{0},{1},{2},{3}", Escape(product.Id), Escape(product.Name), Escape(product.Category), Escape(product.Price)); } static char[] _specialChars = new char[] { ',', '\n', '\r', '"' }; private string Escape(object o) { if (o == null) { return ""; } string field = o.ToString(); if (field.IndexOfAny(_specialChars) != -1) { return String.Format("\"{0}\"", field.Replace("\"", "\"\"")); } else return field; } } }
WebApi的代码我修改了下。不用ConfigureApi(HttpConfiguration config) 方法
在WebApiConfig 中的Register方法中注册对象
config.Formatters.Add(new ProductCsvFormatter());
这里直接放源码
using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using System; using System.Collections.Generic; using System.Linq; using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Web.Http; using WebApiDemo.Formatters; namespace WebApiDemo { public static class WebApiConfig { public static void Register(HttpConfiguration config) { // Web API configuration and services //要使用HttpConfiguration对象上的Formatters属性。 config.Formatters.Add(new ProductCsvFormatter()); // Web API routes config.MapHttpAttributeRoutes(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{action}/{id}", defaults: new { id = RouteParameter.Optional } ); //var settings = config.Formatters.JsonFormatter.SerializerSettings; //IsoDateTimeConverter timeConverter = new IsoDateTimeConverter(); //timeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss"; //settings.Converters.Add(timeConverter); //var j = GlobalConfiguration.Configuration.Formatters.JsonFormatter; //j.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Local; //j.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd' 'HH':'mm':'ss"; //j.SerializerSettings.DateFormatHandling = Newtonsoft.Json.DateFormatHandling.MicrosoftDateFormat; //GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter //{ // DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss" //}); config.Formatters.JsonFormatter.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss" }); #region 设置API返回数据格式 方式一 //var json = config.Formatters.JsonFormatter; //设置格式化格式为:json格式 /* * 该序列化不要。否则会出现 * {"$id":"1","Id":1,"Name":"Tomato soup"} * 因为重复引用 */ //json.SerializerSettings.PreserveReferencesHandling = // Newtonsoft.Json.PreserveReferencesHandling.Objects; ////在管道中移除xml格式,其实就是统一用json格式化 //config.Formatters.Remove(config.Formatters.XmlFormatter); #endregion #region 设置API返回数据格式 方式二 //清空默认xml、设置json GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear(); GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add( new QueryStringMapping("datatype", "json", "application/json")); //GlobalConfiguration.Configuration.Formatters.JsonFormatter.MediaTypeMappings.Add( // new QueryStringMapping("datatype", "text", "text/csv")); #endregion //ConfigureApi(config); } public static void ConfigureApi(HttpConfiguration config) { var jsonFormatter = new JsonMediaTypeFormatter(); var settings = jsonFormatter.SerializerSettings; IsoDateTimeConverter timeConverter = new IsoDateTimeConverter(); //这里使用自定义日期格式 timeConverter.DateTimeFormat = "yyyy'-'MM'-'dd' 'HH':'mm':'ss"; settings.Converters.Add(timeConverter); settings.ContractResolver = new CamelCasePropertyNamesContractResolver(); config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter)); //为了将媒体类型格式化器添加到Web API管线, //要使用HttpConfiguration对象上的Formatters属性。 config.Formatters.Add(new ProductCsvFormatter()); } public class JsonContentNegotiator : IContentNegotiator { private readonly JsonMediaTypeFormatter _jsonFormatter; public JsonContentNegotiator(JsonMediaTypeFormatter formatter) { _jsonFormatter = formatter; } public ContentNegotiationResult Negotiate(Type type, HttpRequestMessage request, IEnumerable<MediaTypeFormatter> formatters) { var result = new ContentNegotiationResult(_jsonFormatter, new MediaTypeHeaderValue("application/json")); return result; } } } }
好了AP写好了。那么我们来测试下,为了测试多种情况。所有我测试自定义的text/csv外,还测试json格式
static void Main(string[] args) { HttpClient client1 = new HttpClient(); // 添加Accept报头 client1.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("text/csv")); string result1 = client1.GetStringAsync("http://127.0.0.1:8081/api/product/getAllWeb").Result; WebClient client = new WebClient(); //设置请求头是json格式 client.Headers.Add("Content-Type", "application/json"); byte[] responseData = null; //get 方式请求 responseData = client.DownloadData("http://127.0.0.1:8081/api/product/getAllWeb"); string result = Encoding.UTF8.GetString(responseData); //把结果写入csv System.IO.File.WriteAllText("products.csv", result1); }
最后测试可以看出。结果是正确的。根据不同的请求头。获取了不同的效果
看看 products.csv文件
因为在api中移除了xml格式
GlobalConfiguration.Configuration.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
那我们试试用 application/json 是否可以请求到
Web API提供了用于JSON和XML的媒体类型格式化器。框架已默认将这些格式化器插入到消息处理管线之中。
客户端在HTTP请求的Accept报头中可以请求JSON或XML。当没有xml格式。就返回json格式
在API中。我是没有指定json格式的,所有已经判断WEB api已经集成了json格式
当启用xml格式的结果
获取时间戳 时间戳转换 http://www.cnblogs.com/godbell/p/5975366.html
var a = (long)(DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")).Subtract(new DateTime(1970, 1, 1, 0, 0, 0)).TotalMilliseconds); TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0); var b = Convert.ToInt64(ts.TotalSeconds).ToString();
我也是根据网上的资料学习。实践。有错误的地方还请见谅。挺幸运的。站在了巨人的肩膀上
现在大部分问题前辈基本上都遇到过。都能找到答案和学习参考的资料。但那不是自己。所以自己必须得实践!!
以下源码包含了本篇和上篇的内容
参考:
http://www.cnblogs.com/r01cn/p/3155653.html
http://www.cnblogs.com/r01cn/archive/2013/05/17/3083400.html