• MVC4 WebAPI(一)


    不管是因为什么原因,结果是在新出的MVC中,增加了WebAPI,用于提供REST风格的WebService,个人比较喜欢REST风格的WebService,感觉比SOAP要轻量级一些,而且对客户端的要求也更少,更符合网络数据传输的一般模式,客户端完全摆脱了代理和管道来直接和WebService进行交互,具体的区别可以参见Web 服务编程,REST 与 SOAP

    (一)环境准备

    本机的环境是XP+VS2010,需要安装VS2010 SP1升级包,MVC4升级包,Vs2010安装SP1后会影响SQLServer2008的自动提示功能,需要在安装补丁或插件,安装成功后可以新建如下的 MVC WebAPI 项目

    (二)概览

    新生成的WebAPI项目和典型的MVC项目一样,包含主要的Models,Views,Controllers等文件夹和Global.asax文件


    Views对于WebAPI来说没有太大的用途,Models中的Model主要用于保存Service和Client交互的对象,这些对象默认情况下会被转换为Json格式的数据进行传输,Controllers中的Controller对应于WebService来说是一个Resource,用于提供服务。和普通的MVC一样,Global.asax用于配置路由规则

    (三)Models

    和WCF中的数据契约形成鲜明对比的是,MVC WebAPI中的Model就是简单的POCO,没有任何别的东西,如,你可以创建如下的Model

    复制代码
        public class TestUseMode
        {
            public string ModeKey{get;set;}
            public string ModeValue { get; set; }
            
        }
    复制代码

    注意:Model必须提供public的属性,用于json或xml反序列化时的赋值

    (四)Controllers

    MVC WebAPI中的Controllers和普通MVC的Controllers类似,不过不再继承于Controller,而改为继承API的ApiController,一个Controller可以包含多个Action,这些Action响应请求的方法与Global中配置的路由规则有关,在后面结束Global时统一说明

    (五)Global

    默认情况下,模板自带了两个路由规则,分别对应于WebAPI和普通MVC的Web请求,默认的WebAPI路由规则如下

    1             routes.MapHttpRoute(
    2                 name: "DefaultApi",
    3                 routeTemplate: "api/{controller}/{id}",
    4                 defaults: new { id = RouteParameter.Optional }
    5             );

    可以看到,默认路由使用的固定的api作为Uri的先导,按照微软官方的说法,用于区分普通Web请求和WebService的请求路径:

    Note: The reason for using "api" in the route is to avoid collisions with ASP.NET MVC routing. That way, you can have "/contacts" go to an MVC controller, and "/api/contacts" go to a Web API controller. Of course, if you don't like this convention, you can change the default route table.

    可以看到,默认的路由规则只指向了Controller,没有指向具体的Action,因为默认情况下,对于Controller中的Action的匹配是和Action的方法名相关联的:

    具体来说,如果使用上面的路由规则,对应下面的Controller:

    复制代码
        public class TestController : ApiController
        {
            public static List<TestUseMode> allModeList = new List<TestUseMode>();
    
    
    
            public IEnumerable<TestUseMode> GetAll()
            {
                return allModeList;
            }
    
            public IEnumerable<TestUseMode> GetOne(string key)
            {
                return allModeList.FindAll((mode) => { if (mode.ModeKey.Equals(key)) return true; return false; });
            }
    
            public bool PostNew(TestUseMode mode)
            {
                allModeList.Add(mode);
                return true;
            }
    
            public int Delete(string key)
            {
                return allModeList.RemoveAll((mode) => { if (mode.ModeKey == key) return true; return false; });
            }
    
            public int DeleteAll()
            {
                return allModeList.RemoveAll((mode) => { return true; });
            }
    
            public int PutOne(string key, string value)
            {
                List<TestUseMode> upDataList = allModeList.FindAll((mode) => { if (mode.ModeKey == key) return true; return false; });
                foreach(var mode in upDataList)
                {
                    mode.ModeValue = value;
                }
                return upDataList.Count;
            }
        }
    复制代码

     

    则,会有下面的对应关系:

    简单使用JS调用上面提供的数据接口

    复制代码
     1         function getAll() {
     2             $.ajax({
     3                 url: "api/Test/",
     4                 type: 'GET',
     5                 success: function (data) {
     6                     document.getElementById("modes").innerHTML = "";
     7                     $.each(data, function (key, val) {
     8                         var str = val.ModeKey + ': ' + val.ModeValue;
     9                         $('<li/>', { html: str }).appendTo($('#modes'));
    10                     });
    11                 }
    12             }).fail(
    13             function (xhr, textStatus, err) {
    14                 alert('Error: ' + err);
    15             });
    16         }
    17 
    18 
    19 
    20         function add() {
    21 
    22             $.ajax({
    23                 url: "api/Test/",
    24                 type: "POST",
    25                 dataType: "json",
    26                 data: { "ModeKey": document.getElementById("txtKey").value, "ModeValue": document.getElementById("txtValue").value },
    27                 success: function (data) {
    28                     getAll();
    29                 }
    30             }).fail(
    31             function (xhr, textStatus, err) {
    32                 alert('Error: ' + err);
    33             });
    34 
    35         }
    36 
    37         function find() {
    38             
    39             $.ajax({
    40                 url: "api/Test/" + document.getElementById("txtFindKey").value,
    41                 type: 'GET',
    42                 success: function (data) {
    43                     document.getElementById("modes").innerHTML = "";
    44                     $.each(data, function (key, val) {
    45                         var str = val.ModeKey + ': ' + val.ModeValue;
    46                         $('<li/>', { html: str }).appendTo($('#modes'));
    47                     });
    48                 }
    49             }).fail(
    50             function (xhr, textStatus, err) {
    51                 alert('Error: ' + err);
    52             });
    53         }
    54 
    55         function removeAll() {
    56             $.ajax({
    57                 url: "api/Test/",
    58                 type: 'DELETE',
    59                 success: function (data) {
    60                     document.getElementById("modes").innerHTML = "";
    61                     getAll();
    62                 }
    63             }).fail(
    64             function (xhr, textStatus, err) {
    65                 alert('Error: ' + err);
    66             });
    67         }
    68 
    69         function remove() {
    70             $.ajax({
    71                 url: "api/Test/"+document.getElementById("txtRemoveKey").value,
    72                 type: 'DELETE',
    73                 success: function (data) {
    74                     document.getElementById("modes").innerHTML = "";
    75                     getAll();
    76                 }
    77             }).fail(
    78             function (xhr, textStatus, err) {
    79                 alert('Error: ' + err);
    80             });
    81         }
    82 
    83         function update() {
    84             $.ajax({
    85                 url: "api/Test/",
    86                 type: 'PUT',
    87                 dataType: "json",
    88                 data: { "key": document.getElementById("txtUpdateKey").value, "value": document.getElementById("txtUpdateValue").value },
    89                 success: function (data) {
    90                     document.getElementById("modes").innerHTML = "";
    91                     getAll();
    92                 }
    93             }).fail(
    94             function (xhr, textStatus, err) {
    95                 alert('Error: ' + err);
    96             });
    97         }
    复制代码

    这样就实现了最基本的CRUD操作。

    (六)路由规则扩展

    和普通的MVC一样,MVC WebAPI支持自定义的路由规则,如:在上面的操作中,路由规则使用

    "api/{controller}/{id}"

    则限定了使用GET方式利用URL来传值时,controller后面的接收参数名为id,但是在Controller中,GetOne方法的接收参数名为key,是不会被匹配的,这是只需要新增一个新的路由规则,或修改原先的路由规则为:

    "api/{controller}/{key}"

    当然,可以对路由进行更深的扩展,如:扩展成和普通MVC一样的路由:

    "api/{controller}/{action}/{id}"

    这样,就要求同时使用Action和HTTP方法进行匹配
    当然,根据微软的说法,这种使用是不被推荐的,因为这不符合大家对WebService的一般认知:

    For a RESTful API, you should avoid using verbs in the URIs, because a URI should identify a resource, not an action.

    (七)使用Attribute声明HTTP方法

    有没有感觉默认的使用方法名来匹配HTTP Method的做法很傻??或者我有一些方法是自己用的,不想暴露出来,又该怎么办?还是使用attribute做这些工作感觉优雅一些,比如,上面的Action我可以更改为:

    复制代码
            [HttpGet]
            public IEnumerable<TestUseMode> FindAll()
    
            [HttpGet]
            public IEnumerable<TestUseMode> FindByKey(string key)
    
            [HttpPost]
            public bool Add(TestUseMode mode)
    
            [HttpDelete]
            public int RemoveByKey(string key)
    
            [HttpDelete]
            public int RemoveAll()
    
            [HttpPut]
            public int UpdateByKey(string key, string value)
    
           [NonAction]  
           public string GetPrivateData()
    复制代码

    当然,我只列出了方法名,而不是这些方法真的没有方法体...方法体是不变的,NoAction表示这个方法是不接收请求的,即使以GET开头。
    如果感觉常规的GET,POST,DELETE,PUT不够用,还可以使用AcceptVerbs的方式来声明HTTP方法,如:

    复制代码
            [AcceptVerbs("MKCOL", "HEAD")]
            public int UpdateByKey(string key, string value)
            {
                List<TestUseMode> upDataList = allModeList.FindAll((mode) => { if (mode.ModeKey == key) return true; return false; });
                foreach(var mode in upDataList)
                {
                    mode.ModeValue = value;
                }
                return upDataList.Count;
            }
    复制代码

    ******************************************************************************

  • 相关阅读:
    转载--编写高质量代码:改善Java程序的151个建议(第3章:类、对象及方法___建议31~35)
    转载---编写高质量代码:改善Java程序的151个建议(第2章:基本类型___建议26~30)
    转载---编写高质量代码:改善Java程序的151个建议(第2章:基本类型___建议21~25)
    月薪两万不是梦,麻辣隔壁的
    23种设计模式(转)
    因为最近项目用到了shiro,所以转了份笔记研讨
    单例模式(摘)
    aop日志管理(摘)
    理解线程副本类(摘)
    eclipse反编译插件安装
  • 原文地址:https://www.cnblogs.com/huangjihua/p/4125162.html
Copyright © 2020-2023  润新知