zoukankan      html  css  js  c++  java
  • [转载]返璞归真 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(0, 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>
    复制代码
  • 相关阅读:
    css3学习笔记之效果
    css3学习笔记之2D转换
    css3学习笔记之文本效果
    css3学习笔记之渐变
    css3学习笔记之背景
    css3学习笔记之边框
    AngularJs 入门参考代码
    环形矩阵
    Qt编写串口通信程序全程图文讲解[转]
    Qt操作Sqlite数据库
  • 原文地址:https://www.cnblogs.com/fx2008/p/2817967.html
Copyright © 2011-2022 走看看