Web Api – Media Type Formatter – Notlar
Merhabalar ,
Media Type Formatter verimizi kullanıcılara hangi formatta sunacağımızı belirleyeceğimiz sanal bir sınıftır , yani bütün media typpe formatırlar bu sanal sınıftan miras alarak türemiştir
- JsonMediaTypeFormatter
- XmlMediaTypeFormatter
- FormUrlEncodeMediaTypeFormatter
Default olarak Asp.Net Web Api de gelmektedir , istersek kendimizde yeni bir Media Type Formatter tanımlayabiliriz.
Örneğin Api mizde xml desteğini kaldırmak istesek App_Start kalsöründe bulunan WebApiConfig.cs dosyamızda aşşağıdaki kod satısını eklemeliyiz.
using : using System.Net.Http.Formatting;
code : config.Formatters.Remove(config.Formatters.XmlFormatter);
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Net.Http.Formatting; namespace WebApiApp { 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}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Formatters.Remove(config.Formatters.XmlFormatter); } } }
Web apimize text/html tipinde bir accept istek olduğunda json formatında response dönmesi için config ayarı ekleme.
config satırımız : config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue(“text/html”));
json formatımızın desteklediği media type header değerlerine text/html eklemiş olduk
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Net.Http.Formatting; namespace WebApiApp { 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}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/html")); } } }
fakat bu şekilde bir kullanımda text/html olarak gelen bir accept te response olarak json döncektir ama header bilgisinin content-type kısmı application/json olması gerekirken text/html yazacaktır.
Bunun önüne geçmek için kendi MediaTypeFormatter ımız yazıp config ayarlarırında tanımlayacağız.
Öncelikle projemize MyJsonFormatter adında bir class ekledim :
kodlar:
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Web; namespace WebApiApp { public class MyJsonFormatter : JsonMediaTypeFormatter { public MyJsonFormatter() { this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); } public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) { base.SetDefaultContentHeaders(type, headers, mediaType); headers.ContentType = new MediaTypeHeaderValue("application/json"); } } }
oluşturduğumuz class a JsonMediaTypeFormatter sınıfını implement ettik , sonrasında constructor ımızda bi önceki örneğimizde yaptığımız gibi text/html content-type ına destek verdiğimizi tanımladık.
sonrasında JsonMediaTypeFormatter a ait olan SetDefaultContentHeaders methodunu override ederek header content-type ını her zaman application/json olarak dönmesini sağladık.
bu işlemlerden sonra oluşturduğumuz MediaTypeFormat sınıfımız WebApiConfig.cs dosyamıza tanımlamamız kaldı.
config.Formatters.Add(new MyJsonFormatter());
şeklinde kodumuzu eklememiz yeterli olacaktır .
WebApiConfig.cs :
using System; using System.Collections.Generic; using System.Linq; using System.Web.Http; using System.Net.Http.Formatting; namespace WebApiApp { 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}/{id}", defaults: new { id = RouteParameter.Optional } ); config.Formatters.Add(new MyJsonFormatter()); } } }
Artık Accept : “text/html” olarak gelen requestler de json olarak sonucumuz döncek ve header content-type bilgisinde “application/json” olacaktır.
Örnek: CSV Formater :
Apimizde response olarak csv formatın sonucu almak için örnek csv formater ve kullanımı :
CSVFormatter.cs
using Egitim_ContentNavigation.Entity; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Threading; using System.Threading.Tasks; using System.Web; namespace WebApiApp { public class CSVFormatter : MediaTypeFormatter { public CSVFormatter() { this.SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/csv")); } public CSVFormatter(MediaTypeMapping mediaTypeMapping):this() { this.MediaTypeMappings.Add(mediaTypeMapping); } public override bool CanReadType(Type type) { return false; } public override bool CanWriteType(Type type) { //List mi ? return type.GetInterfaces().Any(x => x == typeof(IEnumerable)); } public override void SetDefaultContentHeaders(Type type, HttpContentHeaders headers, MediaTypeHeaderValue mediaType) { base.SetDefaultContentHeaders(type, headers, mediaType); headers.Add("Content-Disposition", "attachment; filename=" + Guid.NewGuid().ToString() + ".csv"); } public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext, CancellationToken cancellationToken) { myWriteStream(type, value, writeStream); var task = new TaskCompletionSource<int>(); task.SetResult(0); return task.Task; } private void myWriteStream(Type type, object value, Stream stream) { Type itemType = type.GetGenericArguments()[0]; StringWriter _stringWriter = new StringWriter(); _stringWriter.WriteLine( string.Join<string>( ",", itemType.GetProperties().Select(x => x.Name) ) ); foreach (var obj in (IEnumerable<object>)value) { var vals = obj.GetType().GetProperties().Select( pi => new { Value = pi.GetValue(obj, null) } ); string _valueLine = string.Empty; foreach (var val in vals) { if (val.Value != null) { var _val = val.Value.ToString(); if (_val.Contains("\r")) _val = _val.Replace("\r", " "); if (_val.Contains("\n")) _val = _val.Replace("\n", " "); _valueLine = string.Concat(_valueLine, _val, ","); } else { _valueLine = string.Concat(_valueLine, string.Empty, ","); } } _stringWriter.WriteLine(_valueLine.TrimEnd(',')); } var streamWriter = new StreamWriter(stream); streamWriter.Write(_stringWriter.ToString()); streamWriter.Close(); } } }
sonrasında formatter tanımlamasını yapmamız gerekce , WebApiConfgi.cs te yapabileceğimiz gibi Global.asax dosyasında da bu tanımlamayı yapabiliriz.
Global.asax :
using System; using System.Collections.Generic; using System.Linq; using System.Net.Http.Formatting; using System.Web; using System.Web.Http; using System.Web.Routing; namespace Egitim_ContentNavigation { public class WebApiApplication : System.Web.HttpApplication { protected void Application_Start() { GlobalConfiguration.Configure(WebApiConfig.Register); GlobalConfiguration.Configuration.Formatters.Add(new CSVFormatter(new QueryStringMapping("format", "csv","text/csv"))); //url?format=csv } } }
kullanımı : wepapi url parametre olarak format=csv yazdığımızda dönen sonuç eğer IEnumerable ise csv formatında sonuç verecektir. (IEnumerable kontrolü CSVFormatter.cs dosyasında CanWriteType metodunda yapılmıştır. )
Bu şekilde csv formatında response alınabilir.