asp.net mvc 增加WebApi

标签: asp.net mvc

新建项目的时候可以直接勾选

勾选,“确定”后你会发现,项目多了这些文件

一、App_Start文件夹多了WebApiConfig.cs文件

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace HaoSiJiaWeb
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

              config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );  
        }
    }
}

 

 config.MapHttpAttributeRoutes();

 

这行代码的意思是开启的特性路由

之前写MVC的时候介绍过特性路由,感兴趣的可以点击下面链接进行查看

asp.net mvc 控制器和视图的花式玩法

https://blog.csdn.net/cplvfx/article/details/102455928

 

二、Global.asax多了一行代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace HaoSiJiaWeb
{
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            GlobalConfiguration.Configure(WebApiConfig.Register);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
}
  GlobalConfiguration.Configure(WebApiConfig.Register);

 

如果你想在你的现有MVC项目增加WebApi可以根据这个格式(步骤)加进去就行了

 

增加WebApi控制器

第一步:新建文件夹

在网站根目录新建文件夹“API”

第二步:增加控制器文件

在“API”文件夹右键》添加》Web API 控制器类

输入名称“TestController”

会生成下面代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace HaoSiJiaWeb.Api
{
    public class TestController : ApiController
    {
        // GET api/<controller>
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/<controller>/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/<controller>
        public void Post([FromBody]string value)
        {
        }

        // PUT api/<controller>/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/<controller>/5
        public void Delete(int id)
        {
        }
    }
}

访问

访问地址:http://localhost:58088/api/Test

目前访问的是第一个action的Get方法

注意:

直接输入地址访问的http请求都属于Get请求。

我们在提交表单的时候会有许多提交请求的方式,API会先判断你请求的方式,再根据你的请求方式去找到控制器里对应的action方法

在Web API里还有个特性,就是action方法开头如果是Get,他就会判定这个action是用来处理get请求的,

如果POST开头,他就会判定这个action是用来处理post请求的,

像put和delete也都类似

 

代码升级

升级TestController 控制器文件

在文件里增加下面方法

    public class TestController : ApiController
    {
      
        public string TestString()
        {
          return "TestString()";
        } 
    }

我这里把所有生成的方法都删了,只留我自己写的 

升级路由文件WebApiConfig

 public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API 配置和服务

            // Web API 路由
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
              name: "DefaultApi",
              routeTemplate: "api/{controller}/{id}",
              defaults: new { id = RouteParameter.Optional }
          );

            config.Routes.MapHttpRoute(
            name: "DefaultApi2",
            routeTemplate: "api/{controller}/{action}/{id}",
            defaults: new { id = RouteParameter.Optional }
            );
        }
    }

我这里在下面增加了一条新的路由状态

访问

url:http://localhost:58088/api/Test/TestString/

理论上,我们这样访问是没有错的,可惜,只是理论上

运行报错

<Error>

<Message>请求的资源不支持 http 方法“GET”。</Message>

</Error>

根据,上面我们讲的

在Web API里还有个特性,就是action方法开头如果是Get,他就会判定这个action是用来处理get请求的,

如果POST开头,他就会判定这个action是用来处理post请求的,

像put和delete也都类似

我们把方法改成这样的

 public string GetTestString()
{
          return "GetTestString()";
} 

在名字前面增加Get

访问url:http://localhost:58088/api/Test/TestString/

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">GetTestString()</string>

已经访问成功了

那么,有没有另一种方法呢?

答案是“有”,在方法上面增加特性

[HttpGet]
public string TestString()
{
  return "[HttpGet]TestString()";
} 

特性有:[HttpGet]、[HttpPost]、[HttpPut]、[HttpDelete] 你可以根据你的需求使用

访问URL:http://localhost:58088/api/Test/TestString/

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">[HttpGet]TestString()</string>

你还可以给方法匿名

[ActionName("TS")]
[HttpGet]
public string TestString()
{
  return [email protected]"[ActionName(TS)]+[HttpGet]TestString()";
}

这样你就可以用TS来代替方法名了

访问URL:http://localhost:58088/api/Test/TS/

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">[ActionName(TS)]+[HttpGet]TestString()</string>

还有一种就更神奇了,就是特性路由


Web API 特性路由

上面我们讲到过在App_Start文件夹下的WebApiConfig.cs文件里面有这么一行代码

 config.MapHttpAttributeRoutes();

这个就是开启特性路由的意思,系统默认开启

升级TestController控制器

[Route("api/Test/TestRoute")]
[HttpGet]
public string TestRoute()
{
   return [email protected]"使用特性路由+[HttpGet]TestRoute()";
}

访问URL:http://localhost:58088/api/Test/TestRoute/

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用特性路由+[HttpGet]TestRoute()</string>

当然,依旧可以匿名

[Route("api/Test/TR")]
[HttpGet]
public string TestRoute()
{
    return [email protected]"使用特性路由---匿名+[HttpGet]TR/TestRoute()";
}

访问URL:http://localhost:58088/api/Test/TR/

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用特性路由---匿名+[HttpGet]TR/TestRoute()</string>

是不是很简单  o(∩_∩)o 哈哈

使用带参数的特性路由

[Route("api/Test/TestRoute/{id}")]
[HttpGet]
public string TestRoute(int id)
{
    return [email protected]"使用带参数的特性路由+[HttpGet]TestRoute(int id)传参为:{id}";
}

访问URL:http://localhost:58088/api/Test/TestRoute/5

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用带参数的特性路由+[HttpGet]TestRoute(int id)传参为:5</string>

 

使用带参数类型约束的特性路由

[Route("api/Test/TestRoute/{id:int=5}")]
[HttpGet]
public string TestRoute(int id)
{
    return [email protected]"使用带参数类型约束的特性路由+[HttpGet]TestRoute(int id)传参为:{id}";
}

这里约束可变部分{id}的取值必须是int类型。并且默认值是5.

访问:http://localhost:58088/api/Test/TestRoute/

结果:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用带参数类型约束的特性路由+[HttpGet]TestRoute(int id)传参为:5</string>

访问:http://localhost:58088/api/Test/TestRoute/7

结果:

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">使用带参数类型约束的特性路由+[HttpGet]TestRoute(int id)传参为:7</string>

访问:http://localhost:58088/api/Test/TestRoute/a

结果:

<Error>
<Message>
找不到与请求 URI“http://localhost:58088/api/Test/TestRoute/a”匹配的 HTTP 资源。
</Message>
<MessageDetail>在控制器“Test”上找不到与名称“TestRoute”匹配的操作。</MessageDetail>
</Error>

这里之所以会报错,是因为我们特性约束了id必须为int类型

使用多参数的特性路由

[Route("api/Test/TestRoute/{name}/{age:int=1}")]
[HttpGet]
public string TestRoute(string name,int age)
{
    return [email protected]"使用多参数的特性路由+[HttpGet]TestRoute(string name,int id){name}的年龄是{age}岁";
}

访问:http://localhost:58088/api/Test/TestRoute/Peter/25

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
使用多参数的特性路由+[HttpGet]TestRoute(string name,int id)Peter的年龄是25岁
</string>

访问:localhost:58088/api/Test/TestRoute/老吴/25

结果

<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">
使用多参数的特性路由+[HttpGet]TestRoute(string name,int id)老吴的年龄是25岁
</string>

TestController.cs完整代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace HaoSiJiaWeb.Api
{
    public class TestController : ApiController
    {

        /// <summary>
        /// 方法名字前面增加处理请求的类型
        /// 访问url:http://localhost:58088/api/Test/TestString/
        /// </summary>

        //public string GetTestString()
        //{
        //  return "GetTestString()";
        //} 


        /// <summary>
        /// 方法上面增加特性说明[HttpGet]
        /// 访问url:http://localhost:58088/api/Test/TestString/
        /// </summary>
        //[HttpGet]
        // public string TestString()
        //{
        //  return "[HttpGet]TestString()";
        //} 


        /// <summary>
        /// 使用匿名特性[ActionName("TS")]
        /// 访问url:http://localhost:58088/api/Test/TS/
        /// </summary>
        [ActionName("TS")]
        [HttpGet]
        public string TestString()
        {
            return [email protected]"[ActionName(TS)]+[HttpGet]TestString()";
        }

        /// <summary>
        /// 使用特性路由
        /// 访问URL:http://localhost:58088/api/Test/TestRoute/
        /// </summary> 
        //[Route("api/Test/TestRoute")]
        //[HttpGet]
        //public string TestRoute()
        //{
        //    return [email protected]"使用特性路由+[HttpGet]TestRoute()";
        //}



        /// <summary>
        /// 使用特性路由---匿名
        /// 访问URL:http://localhost:58088/api/Test/TR/
        /// </summary> 
        [Route("api/Test/TR")]
        [HttpGet]
        public string TestRoute()
        {
            return [email protected]"使用特性路由---匿名+[HttpGet]TR/TestRoute()";
        }

        /// <summary>
        /// 使用带参数的特性路由
        /// 访问URL:http://localhost:58088/api/Test/TestRoute/5
        /// </summary> 
        //[Route("api/Test/TestRoute/{id}")]
        //[HttpGet]
        //public string TestRoute(int id)
        //{
        //    return [email protected]"使用带参数的特性路由+[HttpGet]TestRoute(int id)传参为:{id}";
        //}


        /// <summary>
        /// 使用带参数类型约束的特性路由
        /// 访问URL:http://localhost:58088/api/Test/TestRoute/5
        /// </summary> 
        [Route("api/Test/TestRoute/{id:int=5}")]
        [HttpGet]
        public string TestRoute(int id)
        {
            return [email protected]"使用带参数类型约束的特性路由+[HttpGet]TestRoute(int id)传参为:{id}";
        }

        /// <summary>
        /// 使用多参数的特性路由
        /// 访问URL:http://localhost:58088/api/Test/TestRoute/Peter/25
        /// </summary> 
        [Route("api/Test/TestRoute/{name}/{age:int=1}")]
        [HttpGet]
        public string TestRoute(string name, int age)
        {
            return [email protected]"使用多参数的特性路由+[HttpGet]TestRoute(string name,int id){name}的年龄是{age}岁";
        }

    }
}

 

 


特性路由-进阶篇

在同一个控制器里,我们为了保证URL前面的路径一致,我们需要这样做

 

新建MoveRouteController.cs

我们新建一个MoveRouteController.cs的Web API控制器

在正式项目中,同一个控制器的所有的action的所有特性路由标识一个相同的前缀,这种做法并非必须,但这样能够增加url的可读性。一般的做法是在控制器上面使用特性[RoutePrefix]来标识。

完整代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace HaoSiJiaWeb.Api
{
    [RoutePrefix("api/MoveRoute")]
    public class MoveRouteController : ApiController
    { 
        /// <summary>
        /// 使用带参数类型约束的特性路由
        /// 访问URL:http://localhost:58088/api/MoveRoute/MRoute
        /// </summary> 
        [HttpGet]
        public string MRoute()
        {
            return [email protected]" MRoute()";
        }

        /// <summary>
        /// 使用带参数类型约束的特性路由
        /// 访问URL:http://localhost:58088/api/MoveRoute/TestRoute
        /// </summary> 
        [Route("TestRoute/{id:int=5}")]
        [HttpGet]
        public string TestRoute(int id)
        {
            return [email protected]"使用带参数类型约束的特性路由+[HttpGet]TestRoute(int id)传参为:{id}";
        }
    }
}

我们在控制器顶部用[RoutePrefix("")]约束好URL开头后,后面的[Route("")]直接写action名称即可,

请仔细看上面代码标注里的URL,你就会发现他的神奇


延伸阅读

WebApiConfig.cs的路由配置说明

面我们提到了,新建一个WebApi服务的时候,会自动在WebApiConfig.cs文件里面生成一个默认路由:

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

将MapHttpRoute()方法转到定义可以,它有四个重载方法:

分别来看看各个参数的作用:

  • name:"DefaultApi"→表示此路由的名称,这里只需要保证路由名称不重复就OK了。
  • routeTemplate: "api/{controller}/{id}"→表示路由的url规则,“api”是固定部分,主要用来标识当前请求的url是一个api服务的接口,区别MVC的路由,当然,这里并不是一定要写成“api”,如果你改成“apiserver”,那么你请求的url里面也需要写成“apiserver”;“{controller}”是控制器的占位符部分,在真实的url里面,该部分对应的是具体的控制器的名称,这个和MVC里面一致;“{id}”是参数的占位符部分,表示参数,一般这个参数都会在default里面设置可选。有了这个路由模板约束请求的url,比如:我们请求的url写成http://localhost:21528/Order,那么肯定是找不到对应的路由的,因为“api”这个参数必选。如果请求的url匹配不到对应的路由,则会向客户端返回一个404的状态码。
  • defaults: new { id = RouteParameter.Optional }→表示路由的默认值,比如上面的routeTemplate,{controller}和{id}部分都可以设置默认值,比如:defaults改成new { controller="Order", id = RouteParameter.Optional },那么我们请求http://localhost:21528/api这个url仍然能访问到GetAll()方法。
  • constraints→表示路由约束,一般是一个约束路由模板的正则表达式。比如:我们加入约束条件 constraints: new { id = @"\d+" } ,这就约束必须要匹配一到多个参数id,那么,我们在OrderController里面加入另一个方法
public class OrderController : ApiController
    {

        [HttpGet]
        public object GetAll()
        {
            return "Success";
        }

        [HttpGet]
        public object GetById(int id)
        {
            return "Success" + id ;
        }
    }

WebApiConfig.cs文件再增加一个路由

   config.Routes.MapHttpRoute(
           name: "DefaultApi3",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints:new { id = @"\d+" } 
            );

我们加入约束条件 constraints: new { id = @"\d+" } ,这就约束必须要匹配一到多个参数id

我们通过http://localhost:58088/api2/Order/1来访问,得到结果:

 

 

我们再通过http://localhost:58088/api2/Order/a来访问,得到结果:

这个是很好理解的,id的值不匹配正则表达式。

而我们访问http://localhost:58088/api2/Order/。结果:

竟然连GetAll()方法都找不到了。这是为什么呢?原来就是这个约束在作怪,正则\d+表示匹配一个或多个数字,所以如果请求的url里面没有传数字,则自动匹配不到。所以,如果需要匹配无参的方法,我们把约束改成这样: constraints: new { id = @"\d*" } ,这个表示匹配0个或多个数字,再来试试

   config.Routes.MapHttpRoute(
           name: "DefaultApi3",
            routeTemplate: "api2/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional },
            constraints:new { id = @"\d*" } 
            );

http://localhost:58088/api2/Order/

这样就OK了。

上述说了那么多都是约束id的,其实你也可以使用表达式去约束controller、action等等,但一般不常用,我们就不做过多讲解。


参考:

C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

https://www.cnblogs.com/landeanfen/p/5501490.html

 

版权声明:本文为cplvfx原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/cplvfx/article/details/106493333