在web api中,我们可以通过给Cotroller类添加RoutePrefixAttribute来定义url与Controller之间的映射,但是有时候有一些特殊情况下,我们需要做一些特殊处理来将某些即时满足某一url prefix的请求映射到另一个Controller.这种情况下,我们就需要自定义Controller的Selector逻辑了。

看一下这个如下两个Controller:

[RoutePrefix("Order")]
public class OrderController : ApiController
{
[HttpGet]
[Route("~/Product/Order")]
public List<string> GetOrder()
{
return new List<string>() { "p1", "p2" };
}
} [RoutePrefix("Product")]
public class ProductController : ApiController
{
[HttpPost]
[Route("{id}")]
public string Get(string id,[FromBody]string product)
{
return "pbyid";
}
}

当用户访问/Product/Order这个url时,系统会产生错误,因为OrderController中的GetOrder action和ProductController 中的Get action都与该url匹配(即使这两个Action对应的Method是不一样的,但是当选择Controller的时候只会根据Url中与Controller中Route的匹配情况来选择,具体Controller选择算法参考官方文档)。其实根据我们对id规则的定义,Order这个字符不会是一个合法的id,因此这个Url肯定是应该映射到OrderController中的GetOrder action。(这里仅仅为了演示自定义Controller的选择,实际情况有更好的解决该问题的方法)

这个种情况下我们就需要自定义Controller的选择逻辑了。

首先我们看一下Web Api消息处理的整个流程图:

从这张图可以看到,处理请求时,web api会先根据url找到匹配的Controller,然后在创建的controller对象中去调用匹配的action方法。在上面的例子中,ProductController和OrderController都匹配请求url,所以会发生错误。我们在这个过程中加入自定义逻辑选择OrderController作为/Product/Order的Controller.问题就解决了。

从图中可以看到Controller的选择是通过IHttpControllerSelector这个接口来实现的。

Name Description
GetControllerMapping()

Returns a map, keyed by controller string, of all HttpControllerDescriptor that the selector can select. This is primarily called by IApiExplorer to discover all the possible controllers in the system.

SelectController(HttpRequestMessage)

Selects a HttpControllerDescriptor for the given HttpRequestMessage.

web api框架提供了这个接口的默认实现DefaultHttpControllerSelector.我们可以通过派生出自己的selector,然后重写SelectorController方法来自定义controller的选择逻辑。

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
//string controllerName = GetControllerName(request);
if (request.RequestUri.PathAndQuery.StartsWith("/Product/Order"))
{
if (_orderControllerDescriptor == null)
{
_orderControllerDescriptor = new HttpControllerDescriptor()
{
Configuration = _configuration,
ControllerName = typeof(OrderController).FullName,
ControllerType = typeof(OrderController)
};
} //return _orderControllerDescriptor;
} return base.SelectController(request);
}

然后在将自定义的selector注册到web api的对象容器中.

config.Services.Replace(typeof(IHttpControllerSelector), new CustomControllerSelector(config));

这样我们就将请求GET /Product/Order映射到了OrderController上,后续的Action Seletion会选择OrderController中的GetOrder方法来处理该请求。

采用相同的办法,我们也可以从默认的ActionSelector:ApiControllerActionSelector派生出自己的ActionSelector,然后重写SelectAction来自定义action选择逻辑。

ASP.NET WebApi通过自定义ControllerSelector来自定义Controller的选择的更多相关文章

  1. 连表查询都用Left Join吧 以Windows服务方式运行.NET Core程序 HTTP和HTTPS的区别 ASP.NET SignalR介绍 asp.net—WebApi跨域 asp.net—自定义轻量级ORM C#之23中设计模式

    连表查询都用Left Join吧   最近看同事的代码,SQL连表查询的时候很多时候用的是Inner Join,而我觉得对我们的业务而言,99.9%都应该使用Left Join(还有0.1%我不知道在 ...

  2. asp.net webapi自定义输出结果类似Response.Write()

    asp.net webapi自定义输出结果类似Response.Write()   [HttpGet] public HttpResponseMessage HelloWorld() { string ...

  3. ASP.NET WebApi OWIN 实现 OAuth 2.0(自定义获取 Token)

    相关文章:ASP.NET WebApi OWIN 实现 OAuth 2.0 之前的项目实现,Token 放在请求头的 Headers 里面,类似于这样: Accept: application/jso ...

  4. ASP.NET WebAPI 08 Message,HttpConfiguration,DependencyResolver

    ASP.NET WebAPI 08 Message,HttpConfiguration,DependencyResolver   Message WebAPI作为通信架构必定包含包含请求与响应两个方法 ...

  5. 重温ASP.NET WebAPI(一)初阶

    重温ASP.NET WebAPI(一)初阶   前言 本文为个人对WebApi的回顾无参考价值.主要简单介绍WEB api和webapi项目的基本结构,并创建简单地webaapi项目实现CRUD操作. ...

  6. 路由其实也可以很简单-------Asp.net WebAPI学习笔记(一) ASP.NET WebApi技术从入门到实战演练 C#面向服务WebService从入门到精通 DataTable与List<T>相互转换

    路由其实也可以很简单-------Asp.net WebAPI学习笔记(一)   MVC也好,WebAPI也好,据我所知,有部分人是因为复杂的路由,而不想去学的.曾经见过一位程序猿,在他MVC程序中, ...

  7. ASP.NET WebApi 文档Swagger深度优化

    本文版权归博客园和作者吴双本人共同所有,转载和爬虫请注明博客园蜗牛原文地址,cnblogs.com/tdws   写在前面 请原谅我这个标题党,写到了第100篇随笔,说是深度优化,其实也并没有什么深度 ...

  8. ASP.NET WEBAPI 的身份验证和授权

    定义 身份验证(Authentication):确定用户是谁. 授权(Authorization):确定用户能做什么,不能做什么. 身份验证 WebApi 假定身份验证发生在宿主程序称中.对于 web ...

  9. OData – the best way to REST–实例讲解ASP.NET WebAPI OData (V4) Service & Client

    一.概念介绍 1.1,什么是OData? 还是看OData官网的简单说明: An open protocol to allow the creation and consumption of quer ...

随机推荐

  1. php读取csv乱码问题解决方法

    <form action="erxian_cy.php" method="post" enctype="multipart/form-data& ...

  2. idea发布到tomcat缺少jar

    主要是需要自己添加jar到artifact,如果单个添加jar,则在右边栏右键选择 如果是把整个lib添加到toamcat发布,则选择下面的提示:

  3. sql行列互换

    出现这个结果: sql如下: end) as erjidu from a GROUP BY y;

  4. Treflection03_getFields_getField

    1. package reflectionZ; import java.lang.reflect.Constructor; import java.lang.reflect.Field; public ...

  5. 使用科大讯飞时碰上的问题(unity调用Android)

    使用科大讯飞的时候公司已经有人配置好了Android项目,由于装机量的限制,所以基本上要更换里面的资源和更改app_id,然而在unity那边调用的时候总是出现各种各样的问题,特此记录下来 1.唤醒未 ...

  6. SmsUtils 发送短信

    import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import j ...

  7. cenOs7安装redis

    1.安装redis redis 目前没有官方 RPM 安装包,我们需要从源代码编译,而为了要编译就需要安装 Make 和 GCC. 如果没有安装过 GCC 和 Make,那么就使用 yum 安装 -- ...

  8. HDU 4531 bfs/康拓展开

    题目链接http://acm.hdu.edu.cn/showproblem.php?pid=4531 吉哥系列故事——乾坤大挪移 Time Limit: 2000/1000 MS (Java/Othe ...

  9. input text 不显示输入的历史记录

    当之前的text框输入了数据后,下次输入有历史记录问题的解决方法 怎么禁止输入框记录输入记录,双击input出现输入过的记录, 有过表单设计经验的朋友肯定知道,当我们在浏览器中输入表单信息的时候,往往 ...

  10. 遍历输出所有子视图(View)

    传入一个View,可以获取传入视图的所有子视图,写入桌面,可以在火狐浏览器下查看 /** * 程序获得了焦点就会自动调用这个方法(只要程序获得了焦点,所有控件才能接收触摸事件) */ - (void) ...