博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
给ASP.net Web API的Controller分类
阅读量:7086 次
发布时间:2019-06-28

本文共 5344 字,大约阅读时间需要 17 分钟。

这篇文章讲述了RESTFul Web API的设计思路:《》

接着这篇文章讲述了如何创建一个“纯净”的ASP.net Web API应用程序:《》

本文就讲述如何在这个“纯净”的应用程序上添加些内容。其实关于ASP.net Web API的文章已经不少,但很少讲述如何来给Controller分类的,为什么需要分类?你想如果一个项目稍微大点,Controller一多起来,而所有的Controller都通过“api/controllername”这个URI来访问,那势必带来混乱,你的Controller可能有重名,或觉得结构层次不清晰等。

也许你马上想到了:Area!对,ASP.net MVC不是提供了Area功能么?有了Area我们就可以把功能划分好并很好地组织起来了。遗憾的是:Area真的是MVC的功能,而不是Web API的功能,Web API并不直接支持Area,解决方案是存在的,请参考这篇文章:《》,你可以按照它提供的方法去做,就能解决这个问题,但这次我打算用自己的方法,因为我创建的是纯粹的Web API应用程序,没有网页输出的那种,并且我希望有更加简便的结构。这是我设计的Web API:

这个例子恐怕不是很贴近实际,但比较好理解,我设计的这个“公司门户”提供的接口分成两大块,一是“联系我们”,二是“产品介绍”,而“产品介绍”里面又细分为两类,一是“办公产品”,二是“游戏产品”,简单起见,所有Controller都是默认创建的Web API Controller,没有更具体的功能。

我把所有的URI和Controller列成一张表:

Controller名称 命名空间 URI
AdviseController WebApiRouteDemo.Controllers.ContactUs /apix/ContactUs/Advise
ProductFeedbackController WebApiRouteDemo.Controllers.ContactUs /apix/ContactUs/ProductFeedback
FinancialController WebApiRouteDemo.Controllers.Products.Enterprise /apixx/Products/Enterprise/Financial
OfficeController WebApiRouteDemo.Controllers.Products.Enterprise /apixx/Products/Enterprise/Office
PuzController WebApiRouteDemo.Controllers.Products.Game /apixx/Products/Game/Puz
RpgController WebApiRouteDemo.Controllers.Products.Game /apixx/Products/Game/Rpg
RtsController WebApiRouteDemo.Controllers.Products.Game /apixx/Products/Game/Rts
AllProductsController WebApiRouteDemo.Controllers.Products /apix/Products/AllProducts
AboutController WebApiRouteDemo.Controllers /api/About

URI的前缀“api”、“apix”和“apixx”看起来有些怪异,我想不出什么更好的办法来设计这个URI路由了,只好用这种最笨的方法来区分不同的URI路由规则,apixx表示接下来会带上Area(大类)和Category(小类),apix表示接下来会带上Area,而没有Category,而api则表示接下来直接是controller,没有Area和Category。这是我的路由规则定义:

config.Routes.MapHttpRoute("AreaCategoryApi", "apixx/{area}/{category}/{controller}/{id}",new {id = RouteParameter.Optional});            config.Routes.MapHttpRoute("AreaApi", "apix/{area}/{controller}/{id}", new {id = RouteParameter.Optional});            config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new {id = RouteParameter.Optional});

那么,Web API框架究竟如何最终找到它所需要的Controller呢?其实是根据名称来的,默认情况下,但现在我们除了根据名称,还要根据命名空间,所以你注意到我上面列出的命名空间正好反映了这个Controller所在的位置和它的功能层次。改变默认的选择Controller的行为需要我们重新写一个类来实现IHttpControllerSelector接口,默认的类是“DefaultHttpControllerSelector”,我们可以以它为父类:

public class ClassifiedHttpControllerSelector : DefaultHttpControllerSelector    {        private const string AREA_ROUTE_VARIABLE_NAME = "area";        private const string CATEGORY_ROUTE_VARIABLE_NAME = "category";        private const string THE_FIX_CONTROLLER_FOLDER_NAME = "Controllers";        private readonly HttpConfiguration m_configuration;        private readonly Lazy
> m_apiControllerTypes; public ClassifiedHttpControllerSelector(HttpConfiguration configuration) : base(configuration) { m_configuration = configuration; m_apiControllerTypes = new Lazy
>(GetAllControllerTypes); } public override HttpControllerDescriptor SelectController(HttpRequestMessage request) { return GetApiController(request); } private static string GetRouteValueByName(HttpRequestMessage request, string strRouteName) { IHttpRouteData data = request.GetRouteData(); if (data.Values.ContainsKey(strRouteName)) { return data.Values[strRouteName] as string; } return null; } private static ConcurrentDictionary
GetAllControllerTypes() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); Dictionary
types = assemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && t.Name.EndsWith(ControllerSuffix, StringComparison.OrdinalIgnoreCase) && typeof (IHttpController).IsAssignableFrom(t))).ToDictionary(t => t.FullName, t => t); return new ConcurrentDictionary
(types); } private HttpControllerDescriptor GetApiController(HttpRequestMessage request) { string strAreaName = GetRouteValueByName(request, AREA_ROUTE_VARIABLE_NAME); string strCategoryName = GetRouteValueByName(request, CATEGORY_ROUTE_VARIABLE_NAME); string strControllerName = GetControllerName(request); Type type; try { type = GetControllerType(strAreaName, strCategoryName, strControllerName); } catch (Exception) { return null; } return new HttpControllerDescriptor(m_configuration, strControllerName, type); } private Type GetControllerType(string areaName, string categoryName, string controllerName) { IEnumerable
> query = m_apiControllerTypes.Value.AsEnumerable(); string strControllerSearchingName; if (string.IsNullOrEmpty(areaName)) { strControllerSearchingName = THE_FIX_CONTROLLER_FOLDER_NAME + "." + controllerName; } else { if (string.IsNullOrEmpty(categoryName)) { strControllerSearchingName = THE_FIX_CONTROLLER_FOLDER_NAME + "." + areaName + "." + controllerName; } else { strControllerSearchingName = THE_FIX_CONTROLLER_FOLDER_NAME + "." + areaName + "." + categoryName + "." + controllerName; } } return query.Where(x => x.Key.IndexOf(strControllerSearchingName, StringComparison.OrdinalIgnoreCase) != -1).Select(x => x.Value).Single(); } }

上面这段代码很大程度上是从《》来的,其作用就是根据路由参数(参数中有“Area”、“Category”和“Controller”)从程序集中查找到对应的Controller。

这样我们就完成了对Controller的分类,你也可以调整路由规则设计出更好的出来,不过别忘了来跟我分享下。

最后惯例,附带上:

转载地址:http://ferml.baihongyu.com/

你可能感兴趣的文章
AssetBundle 打包资源
查看>>
HSRP热备份
查看>>
js判断变量数据类型
查看>>
通过思科模拟器CISCO PACKET TRACER学习网络8——RIP路由
查看>>
linux下安装oracle11g实例
查看>>
Centos7搭建OpenNebula云平台
查看>>
Shell流程控制之if语句
查看>>
快过高铁!构建云分布式应用还能这样操作?!
查看>>
ftp服务器的搭建于三种访问途径
查看>>
字节流与字符流的区别及相互转换
查看>>
教你将PDF文件旋转的方法
查看>>
初识 Knative: 跨平台的 Serverless 编排框架
查看>>
字符串匹配
查看>>
yum安装varnish
查看>>
计算机基础超简
查看>>
私有云为什么更得企业青睐?
查看>>
python如何学习(二)
查看>>
移动智能终端能快速及时查询商品
查看>>
快速导入多张CAD图纸文件转换成常见的彩色高清JPG格式如何进行?
查看>>
HTTPS与HTTP协议常见问题,http和是https分别是什么
查看>>