原文:返璞归真 asp.net mvc (10) - asp.net mvc 4.0 新特性之 Web API

[索引页]
[源码下载]

返璞归真 asp.net mvc (10) - asp.net mvc 4.0 新特性之 Web API

作者:webabcd

介绍
asp.net mvc 之 asp.net mvc 4.0 新特性之 Web API

  • 开发一个 CRUD 的 Demo,服务端用 Web API,并使其支持 jsonp 协议,客户端用 jQuery

示例
1、自定义一个 JsonMediaTypeFormatter,以支持 jsonp 协议
MyJsonFormatter.cs

/*
* 自定义一个 JsonMediaTypeFormatter,以支持 jsonp 协议
*/ using System;
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.Tasks;
using System.Web; namespace MVC40.Controllers
{
public class MyJsonFormatter : JsonMediaTypeFormatter
{
// jsonp 回调的函数名称
private string JsonpCallbackFunction; public MyJsonFormatter()
{ } public override bool CanWriteType(Type type)
{
return true;
} // 每个请求都先来这里
public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, System.Net.Http.HttpRequestMessage request, MediaTypeHeaderValue mediaType)
{
var formatter = new MyJsonFormatter()
{
JsonpCallbackFunction = GetJsonCallbackFunction(request)
}; // 增加一个转换器,以便枚举值与枚举名间的转换
formatter.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter()); // 增加一个转换器,以方便时间格式的序列化和饭序列化
var dateTimeConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter();
dateTimeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
formatter.SerializerSettings.Converters.Add(dateTimeConverter); // 排版返回的 json 数据,使其具有缩进格式,以方便裸眼查看
formatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; return formatter;
} // 序列化的实现
public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext)
{
if (string.IsNullOrEmpty(JsonpCallbackFunction))
return base.WriteToStreamAsync(type, value, stream, content, transportContext); StreamWriter writer = null; try
{
writer = new StreamWriter(stream);
writer.Write(JsonpCallbackFunction + "(");
writer.Flush();
}
catch (Exception ex)
{
try
{
if (writer != null)
writer.Dispose();
}
catch { } var tcs = new TaskCompletionSource<object>();
tcs.SetException(ex);
return tcs.Task;
} return base.WriteToStreamAsync(type, value, stream, content, transportContext)
.ContinueWith(innerTask =>
{
if (innerTask.Status == TaskStatus.RanToCompletion)
{
writer.Write(")");
writer.Flush();
} }, TaskContinuationOptions.ExecuteSynchronously)
.ContinueWith(innerTask =>
{
writer.Dispose();
return innerTask; }, TaskContinuationOptions.ExecuteSynchronously)
.Unwrap();
} // 从请求 url 中获取其参数 callback 的值
private string GetJsonCallbackFunction(HttpRequestMessage request)
{
if (request.Method != HttpMethod.Get)
return null; var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
var queryVal = query["callback"]; if (string.IsNullOrEmpty(queryVal))
return null; return queryVal;
}
}
}

2、在 Global 中做的一些配置
Global.asax.cs

using MVC40.Controllers;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing; namespace MVC40
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles); // 添加一个转换器 IsoDateTimeConverter,其用于日期数据的序列化和反序列化
var dateTimeConverter = new IsoDateTimeConverter();
dateTimeConverter.DateTimeFormat = "yyyy-MM-dd HH:mm:ss";
JsonSerializerSettings serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(dateTimeConverter); // 清除全部 Formatter(默认有 4 个,分别是:JsonMediaTypeFormatter, XmlMediaTypeFormatter, FormUrlEncodedMediaTypeFormatter, JQueryMvcFormUrlEncodedFormatter)
// GlobalConfiguration.Configuration.Formatters.Clear(); // 如果请求 header 中有 accept: text/html 则返回这个新建的 JsonMediaTypeFormatter 数据
var jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings = serializerSettings;
// jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
jsonFormatter.MediaTypeMappings.Add(new RequestHeaderMapping("accept", "text/html", StringComparison.InvariantCultureIgnoreCase, true, new MediaTypeHeaderValue("text/html")));
GlobalConfiguration.Configuration.Formatters.Insert(, jsonFormatter); // 请求 url 中如果带有参数 xml=true,则返回 xml 数据
GlobalConfiguration.Configuration.Formatters.XmlFormatter.MediaTypeMappings.Add(new QueryStringMapping("xml", "true", "application/xml")); // 请求 url 中如果带有参数 jsonp=true,则返回支持 jsonp 协议的数据(具体实现参见 MyJsonFormatter.cs)
MyJsonFormatter formatter = new MyJsonFormatter();
formatter.MediaTypeMappings.Add(new QueryStringMapping("jsonp", "true", "application/javascript"));
GlobalConfiguration.Configuration.Formatters.Add(formatter);
}
}
}

关于项目模版生成的代码的简短说明

<p>
项目模板更新了,原来堆在 Global.asax.cs 中的配置都分出去了
<br />
在 App_Start 文件夹里自动生成的 BundleConfig.cs 用于对多个 css 或 js 做打包和压缩
<br />
在 App_Start 文件夹里自动生成的 FilterConfig.cs 用于配置全局的 Action Filter
<br />
在 App_Start 文件夹里自动生成的 RouteConfig.cs 用于配置路由
<br />
在 App_Start 文件夹里自动生成的 WebApiConfig.cs 用于为 web api 配置路由
</p>

web api 的路由配置
WebApiConfig.cs

/*
* web api 的路由配置
*/ using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http; namespace MVC40
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// 此配置为默认生成的配置
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); // 由于默认为 web api 生成的路由配置,无 action 配置,所以只能通过 http 方法来匹配 action
// 如果需要带 action 的路由则使用以下配置即可
/*
routes.MapHttpRoute(
name: "ActionApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
*/
}
}
}

3、提供 Web API 服务的 Controller(数据层用 Entity Framework 5.0 来实现)
ProductsController.cs

/*
* ASP.NET Web API
*
* c - POST - 创建
* r - GET - 读取
* u - PUT - 更新
* d - DELETE - 删除
*
* 注:win8 的 iis 默认不会安装 asp.net,需要在“程序和功能”中手动添加
*/ using MVC40.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http; namespace MVC40.Controllers
{
/*
* Web API 的 Controller 要从 ApiController 继承
*
* 默认:http get 找 controller 的 get(), http post 找 controller 的 post(), http put 找 controller 的 put(), http delete 找 controller 的 delete()
*/
public class ProductsController : ApiController
{
// 获取全部 Product 数据:get http://localhost:17612/api/products
public IEnumerable<Product> Get()
{
NorthwindEntities db = new NorthwindEntities(); var products = from p in db.Products
orderby p.ProductID descending
select p; return products.ToList();
} // 根据 ProductId 获取指定的 Product 数据:get http://localhost:17612/api/products/3
public Product Get(int id)
{
NorthwindEntities db = new NorthwindEntities(); var product = db.Products.SingleOrDefault(p => p.ProductID == id); return product;
} // 新建 Product:post 一个 product 到 http://localhost:17612/api/products
public void Post(Product product)
{
NorthwindEntities db = new NorthwindEntities(); db.Products.Add(product); db.SaveChanges(); } // 更新 Product:put 一个 product 到 http://localhost:17612/api/products
public void Put(Product product)
{
NorthwindEntities db = new NorthwindEntities(); db.Products.Attach(product);
var entry = db.Entry(product);
entry.State = EntityState.Modified; db.SaveChanges();
} // 根据 ProductId 删除指定的 Product 数据:delete http://localhost:17612/api/products/3
public void Delete(int id)
{
NorthwindEntities db = new NorthwindEntities(); var product = db.Products.SingleOrDefault(p => p.ProductID == id);
db.Products.Remove(product); db.SaveChanges();
}
}
}

4、调用 Web API 的客户端(用 jQuery 实现)
CRUDDemo.cshtml

@{
Layout = null;
} <!DOCTYPE html> <html>
<head>
<title>演示如何通过 jQuery 调用 asp.net web api 做 crud 操作</title>
<script src="../Scripts/jquery-1.7.1.js" type="text/javascript"></script>
</head>
<body>
<table id="tblProducts" border="1">
<tr>
<th>Product Id</th>
<th>Product Name</th>
<th>Unit Price</th>
<th>Actions</th>
</tr>
<tr>
<td>
<input type="text" id="txtProductId" size="5" disabled /></td>
<td>
<input type="text" id="txtProductName" /></td>
<td>
<input type="text" id="txtUnitPrice" /></td>
<td>
<input type="button" name="btnInsert" value="Insert" /></td>
</tr>
</table> <script type="text/javascript">
$(document).ready(function () {
loadProductsAsync();
}); // 异步获取全部 Product 数据
function loadProductsAsync() {
$.getJSON("/api/products?jsonp=true&callback=?", loadProductsCompleted).error(function () { alert('error') });
} // 显示获取到的 Product 数据
function loadProductsCompleted(data) {
$("#tblProducts").find("tr:gt(1)").remove();
$.each(data, function (key, val) {
var tableRow = '<tr>' +
'<td>' + val.ProductID + '</td>' +
'<td><input type="text" value="' + val.ProductName + '"/></td>' +
'<td><input type="text" value="' + val.UnitPrice + '"/></td>' +
'<td><input type="button" name="btnUpdate" value="Update" /> <input type="button" name="btnDelete" value="Delete" /></td>' +
'</tr>';
$('#tblProducts').append(tableRow);
}); $("input[name='btnInsert']").click(onInsert);
$("input[name='btnUpdate']").click(onUpdate);
$("input[name='btnDelete']").click(onDelete);
} // 新增 Product 数据
function onInsert(evt) {
var productName = $("#txtProductName").val();
var unitPrice = $("#txtUnitPrice").val(); // 构建需要 post 的数据,即需要添加的数据
var data = '{"ProductName":"' + productName + '","UnitPrice":' + unitPrice + '}'; $.ajax({
type: 'POST',
url: '/api/products/',
data: data,
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (results) {
$("#txtProductName").val('');
$("#txtUnitPrice").val(''); alert('Product Added'); loadProductsAsync();
}
})
} // 更新 Product 数据
function onUpdate(evt) {
var productId = $(this).parent().parent().children().get(0).innerHTML; var cell = $(this).parent().parent().children().get(1);
var productName = $(cell).find('input').val(); cell = $(this).parent().parent().children().get(2);
var unitPrice = $(cell).find('input').val(); // 构建需要 put 的数据,即需要更新的数据
var data = '{"ProductID":"' + productId + '","ProductName":"' + productName + '","UnitPrice":' + unitPrice + '}'; $.ajax({
type: 'PUT',
url: '/api/products/',
data: data,
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (results) {
alert('Product Updated');
}
})
} // 删除指定的 Product 数据
function onDelete(evt) {
var productId = $(this).parent().parent().children().get(0).innerHTML; $.ajax({
type: 'DELETE',
url: '/api/products/' + productId,
contentType: "application/json; charset=utf-8",
dataType: 'json',
success: function (results) {
alert('Product Deleted'); loadProductsAsync();
}
}) }
</script>
</body>
</html>

OK
[源码下载]

返璞归真 asp.net mvc (10) - asp.net mvc 4.0 新特性之 Web API的更多相关文章

  1. 返璞归真 asp.net mvc (11) - asp.net mvc 4.0 新特性之自宿主 Web API, 在 WebForm 中提供 Web API, 通过 Web API 上传文件, .net 4.5 带来的更方便的异步操作

    原文:返璞归真 asp.net mvc (11) - asp.net mvc 4.0 新特性之自宿主 Web API, 在 WebForm 中提供 Web API, 通过 Web API 上传文件, ...

  2. 返璞归真 asp.net mvc (13) - asp.net mvc 5.0 新特性

    [索引页][源码下载] 返璞归真 asp.net mvc (13) - asp.net mvc 5.0 新特性 作者:webabcd 介绍asp.net mvc 之 asp.net mvc 5.0 新 ...

  3. 返璞归真 asp.net mvc (9) - asp.net mvc 3.0 新特性之 View(Razor)

    原文:返璞归真 asp.net mvc (9) - asp.net mvc 3.0 新特性之 View(Razor) [索引页][源码下载] 返璞归真 asp.net mvc (9) - asp.ne ...

  4. 返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性

    原文:返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性 [索引页][源码下载] 返璞归真 asp.net mvc (6) - asp.net mvc 2.0 新特性 ...

  5. 返璞归真 asp.net mvc (7) - asp.net mvc 3.0 新特性之 Controller

    原文:返璞归真 asp.net mvc (7) - asp.net mvc 3.0 新特性之 Controller [索引页][源码下载] 返璞归真 asp.net mvc (7) - asp.net ...

  6. 返璞归真 asp.net mvc (8) - asp.net mvc 3.0 新特性之 Model

    原文:返璞归真 asp.net mvc (8) - asp.net mvc 3.0 新特性之 Model [索引页][源码下载] 返璞归真 asp.net mvc (8) - asp.net mvc ...

  7. 返璞归真 asp.net mvc (12) - asp.net mvc 4.0 新特性之移动特性

    原文:返璞归真 asp.net mvc (12) - asp.net mvc 4.0 新特性之移动特性 [索引页][源码下载] 返璞归真 asp.net mvc (12) - asp.net mvc ...

  8. asp.net mvc 4.0 新特性之移动特性

    asp.net mvc 4.0 新特性之移动特性 为不同的客户端提供不同的视图 手动重写 UserAgent,从而强制使用对应的视图 示例1.演示如何为不同的客户端提供不同的视图Global.asax ...

  9. ASP.NET4.0新特性

    原文:ASP.NET4.0新特性 在以前试用VS2010的时候已经关注到它在Web开发支持上的一些变化了,为此我还专门做了一个ppt,当初是计划在4月12日那天讲的,结果因为莫名其妙的原因导致没有语音 ...

随机推荐

  1. Oracle GoldenGate for Oracle 11g to PostgreSQL 9.2.4 Configuration

    Installing and setting up Oracle GoldenGate connecting to an Oracle database Also please make sure t ...

  2. 基于Servlet、JSP、JDBC、MySQL的一个简单的用户注冊模块(附完整源代码)

    近期看老罗视频,做了一个简单的用户注冊系统.用户通过网页(JSP)输入用户名.真名和password,Servlet接收后通过JDBC将信息保存到MySQL中.尽管是个简单的不能再简单的东西,但麻雀虽 ...

  3. Linux源文件夹结构呈现

    1.arch文件夹: - 相关的存储在不同平台上的代码,每个平台都采用了不同的文件夹来区分. ******Alpha平台 ******Arm平台 ******Arv32平台 ******X86平台 2 ...

  4. Web工程师的工具箱 | 酷壳 - CoolShell.cn

    Web工程师的工具箱 | 酷壳 - CoolShell.cn Web工程师的工具箱 2012年12月19日 陈皓 发表评论 阅读评论 30,168 人阅读     本文出自Ivan Zuzak 的&l ...

  5. birdnest是什么意思_birdnest在线翻译_英语_读音_用法_例句_海词词典

    birdnest是什么意思_birdnest在线翻译_英语_读音_用法_例句_海词词典 birdnest

  6. C++习题 虚函数-计算图形面积

    C++习题 虚函数-计算图形面积 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 122  Solved: 86 [cid=1143&pid=6 ...

  7. AIX 中以并发模式挂载vg

    要想以并发模式挂载VG 必须要有/usr/sbin/gsclvmd 这个进程,而些进程是安装HACMP 的必要的文件集bos.clvm.enh,同时gsclvmd 也是由HACMP 启动的,多个节点挂 ...

  8. POJ 2299 Ultra-QuickSort (求序列的逆序对数)

    题意:废话了一大堆就是要你去求一个序列冒泡排序所需的交换的次数. 思路:实际上是要你去求一个序列的逆序队数 看案例: 9 1 0 5 4 9后面比它小的的数有4个 1后面有1个 0后面没有 5后面1个 ...

  9. POJ 36666 Making the Grade 简单DP

    题意是: 给出n个数,让你用最小的花费将其改成非递增或非递减的 然后花费就是新序列与原序列各个位置的数的差的绝对值的和 然后可以看到有2000个数,数的范围是10亿 仔细观察可以想象到.其实改变序列中 ...

  10. hdu1869六度分离,spfa实现求最短路

    就是给一个图.假设随意两点之间的距离都不超过7则输出Yes,否则 输出No. 因为之前没写过spfa,无聊的试了一下. 大概说下我对spfa实现的理解. 因为它是bellmanford的优化. 所以之 ...