ASP.NET MVC – Create easy REST API with JSON and XML(转)

转载 2011年01月19日 18:11:00

ASP.NET MVC – Create easy REST API with JSON and XML

From: http://aleembawany.com/2009/03/27/aspnet-mvc-create-easy-rest-api-with-json-and-xml/

 

Mar 27th, 2009

So I just hopped on the ASP.NET MVC bandwagon. As my first task, I undertook custom Action Filters for returning either JSON or XML as determined by the HTTP Request. Fortunately Omar AL Zabir did most of the work for creating a RESTful API with ASP.NET MVC.

JSON and XML Action Filter Code

The following is a filter which makes the whole thing much cleaner. The filter looks for Content-Type headers in the HTTP request. If it matches text/xml then Plain Old XML (POX) is returned and if it matches application/json the output is JSON. This eliminates the need to write separate actions for JSON/XML and Views.


using
 
System
;
 
using System . Web ;  
using System . Web . Mvc ;  
using System . IO ;  
using System . Xml ;  
using System . Text ;  
using System . Collections . Generic ;  
using System . Web . Script . Serialization ;  
using System . Runtime . Serialization ;  
using System . Reflection ;  
using System . Reflection . Emit ;  
 
namespace AleemBawany . ActionFilters  
{  
 
public class JsonPox : ActionFilterAttribute  
 
{  
   
private String [] _actionParams ;  
 
   
// for deserialization  
   
public JsonPox ( params String [] parameters )  
   
{  
     
this . _actionParams = parameters ;  
   
}  
 
   
// SERIALIZE  
   
public override void OnActionExecuted ( ActionExecutedContext filterContext )  
   
{  
     
if (!( filterContext . Result is ViewResult )) return ;  
 
     
// SETUP  
      UTF8Encoding utf8
= new UTF8Encoding ( false );  
     
HttpRequestBase request = filterContext . RequestContext . HttpContext . Request ;  
     
String contentType = request . ContentType ?? string . Empty ;  
     
ViewResult view = ( ViewResult )( filterContext . Result );  
     
var data = view . ViewData . Model ;  
 
     
// JSON  
     
if ( contentType . Contains ( "application/json" ) || request . IsAjaxRequest ())  
     
{  
       
using ( var stream = new MemoryStream ())  
       
{  
         
JavaScriptSerializer js = new JavaScriptSerializer ();  
 
         
String content = js . Serialize ( data );  
          filterContext
. Result = new ContentResult  
         
{  
           
ContentType = "application/json" ,  
           
Content = content ,  
           
ContentEncoding = utf8 
         
};  
       
}  
 
     
}  
 
     
// POX  
     
else if ( contentType . Contains ( "text/xml" ))  
     
{  
       
// MemoryStream to encapsulate as UTF-8 (default UTF-16)  
       
// http://stackoverflow.com/questions/427725/  
       
//  
       
// MemoryStream also used for atomicity but not here  
       
// http://stackoverflow.com/questions/486843/  
       
using ( MemoryStream stream = new MemoryStream ( 500 ))  
       
{  
         
using ( var xmlWriter =  
           
XmlTextWriter . Create ( stream ,  
             
new XmlWriterSettings ()  
             
{  
               
OmitXmlDeclaration = true ,  
               
Encoding = utf8 ,  
               
Indent = true  
             
}))  
         
{  
 
           
new DataContractSerializer (  
              data
. GetType (),  
             
null , // knownTypes  
             
65536 , // maxItemsInObjectGraph  
             
false , // ignoreExtensionDataObject  
             
true , // preserveObjectReference - overcomes cyclical reference issues  
             
null // dataContractSurrogate  
             
). WriteObject ( stream , data );  
         
}  
 
          filterContext
. Result = new ContentResult  
         
{  
           
ContentType = "text/xml" ,  
           
Content = utf8 . GetString ( stream . ToArray ()),  
           
ContentEncoding = utf8 
         
};  
       
}  
     
}  
   
}  
 
   
// DESERIALIZE  
   
public override void OnActionExecuting ( ActionExecutingContext filterContext )  
   
{  
 
     
if ( _actionParams == null || _actionParams . Length == 0 ) return ;  
 
     
HttpRequestBase request = filterContext . RequestContext . HttpContext . Request ;  
     
String contentType = request . ContentType ?? string . Empty ;  
     
Boolean isJson = contentType . Contains ( "application/json" );  
 
     
if (! isJson ) return ;  
     
//@@todo Deserialize POX  
 
     
// JavascriptSerialier expects a single type to deserialize  
     
// so if the response contains multiple disparate objects to deserialize  
     
// we dynamically build a new wrapper class with fields representing those  
     
// object types, deserialize and then unwrap  
     
ParameterDescriptor [] paramDescriptors =  
          filterContext
. ActionDescriptor . GetParameters ();  
     
Boolean complexType = paramDescriptors . Length > 1 ;  
 
     
Type wrapperClass ;  
     
if ( complexType )  
     
{  
       
Dictionary parameterInfo = new Dictionary ();  
       
foreach ( ParameterDescriptor p in paramDescriptors )  
       
{  
          parameterInfo
. Add ( p . ParameterName , p . ParameterType );  
       
}  
        wrapperClass
= BuildWrapperClass ( parameterInfo );  
     
}  
     
else  
     
{  
        wrapperClass
= paramDescriptors [ 0 ]. ParameterType ;  
     
}  
 
     
String json ;  
     
using ( var sr = new StreamReader ( request . InputStream ))  
     
{  
        json
= sr . ReadToEnd ();  
     
}  
 
     
// then deserialize json as instance of dynamically created wrapper class  
     
JavaScriptSerializer serializer = new JavaScriptSerializer ();  
     
var result = typeof ( JavaScriptSerializer )  
             
. GetMethod ( "Deserialize" )  
             
. MakeGenericMethod ( wrapperClass )  
             
. Invoke ( serializer , new object [] { json });  
 
     
// then get fields from wrapper class assign the values back to the action params  
     
if ( complexType )  
     
{  
       
for ( Int32 i = 0 ; i < paramDescriptors . Length ; i ++)  
       
{  
         
ParameterDescriptor pd = paramDescriptors [ i ];  
          filterContext
. ActionParameters [ pd . ParameterName ] =  
              wrapperClass
. GetField ( pd . ParameterName ). GetValue ( result );  
 
       
}  
     
}  
     
else  
     
{  
       
ParameterDescriptor pd = paramDescriptors [ 0 ];  
        filterContext
. ActionParameters [ pd . ParameterName ] = result ;  
     
}  
   
}  
 
   
private Type BuildWrapperClass ( Dictionary parameterInfo )  
   
{  
     
AssemblyName assemblyName = new AssemblyName ();  
      assemblyName
. Name = "DynamicAssembly" ;  
     
AppDomain appDomain = AppDomain . CurrentDomain ;  
     
AssemblyBuilder assemblyBuilder =  
          appDomain
. DefineDynamicAssembly ( assemblyName , AssemblyBuilderAccess . Run );  
     
ModuleBuilder moduleBuilder =  
          assemblyBuilder
. DefineDynamicModule ( "DynamicModule" );  
     
TypeBuilder typeBuilder =  
          moduleBuilder
. DefineType ( "DynamicClass" ,  
         
TypeAttributes . Public | TypeAttributes . Class );  
 
     
foreach ( KeyValuePair entry in parameterInfo )  
     
{  
       
String paramName = entry . Key ;  
       
Type paramType = entry . Value ;  
       
FieldBuilder field = typeBuilder . DefineField ( paramName ,  
                    paramType
, FieldAttributes . Public );  
     
}  
 
     
Type generatedType = typeBuilder . CreateType ();  
     
// object generatedObject = Activator.CreateInstance(generatedType);  
 
     
return generatedType ;  
   
}  
 
 
}  
}  

Last Updated: 28 March, 2010

Usage Example

To use this code in your Controller Action, you simply need to decorate it with the [JsonPox] attribute:

// Depending on HTTP Content-Type header
 
// this returns JSON, XML or the default View  
 
[ JsonPox ]  
public ActionResult Index ()  
{  
       
ArrayList stuff = new ArrayList ();  
        stuff
. Add ( "Hello World" );  
        stuff
. Add ( 999 );  
        stuff
. Add ( 1.0001 );  
       
ViewData . Model = stuff ;  
       
return View ();  
}  

Sample Output

If Content-Type: text/xml HTTP header is present the output is:


<
A
rrayOfAnyType
 
xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema-instance"
 
xmlns:xsd
=
"http://www.w3.org/2001/XMLSchema"
>
 
 
<anyType xsi:type = "xsd:string" > Hello World </anyType>  
 
<anyType xsi:type = "xsd:int" > 999 </anyType>  
 
<anyType xsi:type = "xsd:double" > 1.0001 </anyType>  
</ A rrayOfAnyType >  

For the HTTP header Content-Type: application/json the output is:

[
"Hello World"
,
999
,
1.0001
]
 

And if neither of those headers are present, the default View is returned.

Latest version: If you intend to use it, get the latest bits for JsonPoxFilter.cs here . The source is open so feel free to fork it or ping me if you want to get write access to the repo.

相关文章推荐

REST on ASP.Net MVC (and Future)

MVC和REST是两种不同的世界观. 前者更多的是对行为的建模,后者则更强调数据(状态及状态的变迁). 前者给出的是内部实现方面的指导, 把程序结构分离为Model, View及Controller....

ASP.NET MVC 3: Layouts and Sections with Razor

[转自] http://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor...

Server-Side Paging with the Entity Framework and ASP.NET MVC 3

Julie Lerman Download the Code Sample In my February Data Points column, I showed off the jQuer...

Upload files in ASP.NET MVC with JavaScript and C#

GOOGLE的地址被封了,转过来,方便需要的人 https://cmatskas.com/upload-files-in-asp-net-mvc-with-javascript-and-c/ ...
  • Ani
  • Ani
  • 2016-05-18 21:05
  • 392

Consuming ASP.NET WEB API using ASP.NET MVC4 and RestSharp

原文:http://www.codeproject.com/Articles/826359/Consuming-ASP-NET-WEB-API-using-ASP-NET-MVC-and-Re 相关...
  • Joyhen
  • Joyhen
  • 2015-03-16 02:21
  • 1565

AngularJS ,ASP.NET MVC – 新Web模块化开发

快速浏览标题便了解到本文要谈到公开资源平台,该平台允许快速,轻松地创建一个管理网络,并不需要在风格,导航,解决方案架构和其它跟主要任务无关的琐事上花费过多的时间。 平台视觉图和其中一块模板: 很长一...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)