在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. centos、linux关机与重启命令详解

    Linux centos关机与重启命令详解与实战 Linux centos重启命令: 1.reboot 2.shutdown -r now 立刻重启(root用户使用) 3.shutdown -r 1 ...

  2. jq限制字符个数

    <script> $(document).ready(function () { //限制字符个数 $(".box-right .title a").each(func ...

  3. spark学习13(spark RDD)

    RDD及其特点 1)RDD(Resillient Distributed Dataset)弹性分布式数据集,是spark提供的核心抽象.它代表一个不可变.可分区.里面的元素可并行计算的集合 2)RDD ...

  4. JavaScript tips —— 搞定闰年

    前言 处理时间时,常常要考虑用户的输入是否合法,其中一个很典型的场景就是平闰年的判断,网上其实有很多类似的算法,但是其实不必那么麻烦,下面我讲讲的我的思路. 规则 公元年数可被4整除为闰年,但是整百( ...

  5. resultType没有指定就会报错

    报错如下: 改正方式就是添加resultType. org.apache.ibatis.executor.ExecutorException: A query was run and no Resul ...

  6. mysql数据库优化课程---10、mysql数据库分组聚合

    mysql数据库优化课程---10.mysql数据库分组聚合 一.总结 一句话总结:select concat(class,' 班') 班级,concat(count(*),' 人') 人数 from ...

  7. Spring 自定义标签配置

    前景:经常使用一些依赖于Spring的组件时,发现可以通过自定义配置Spring的标签来实现插件的注入,例如数据库源的配置,Mybatis的配置等.那么这些Spring标签是如何自定义配置的?学习Sp ...

  8. shell awk命令

    语法: awk '{command}' filename  多个命令以分号分隔. awk 'BEGIN {command1} {command2} END{command3}'  注意:BEGIN , ...

  9. Redis 命令,键(key),字符串(String),哈希(Hash),列表(List),集合(Set)(二)

      Redis 命令 Redis 命令用于在 redis 服务上执行操作. 要在 redis 服务上执行命令需要一个 redis 客户端.Redis 客户端在我们之前下载的的 redis 的安装包中. ...

  10. GAN作用——在我做安全的看来,就是做数据拟合、数据增强

    from:https://www.zhihu.com/question/56171002/answer/155777359 GAN的作用,也就是为什么GAN会火了(有部分原因可能是因为Lecun的赞赏 ...