WebApi Controller 分类
前言
写这篇WebApi Controller分类一是把Contrller分类的解决方法说一说,再顺便把遇到的问题和解决方法聊一聊。 说实话第一次在项目中使用WebApi感觉非常的不顺手。
遇到的问题和解决方法
1、多个Get方法。
Get请求方式是用的最多,而且多处需要重载,很好解决,只需根据参数重载方法即可,如果比较懒的话连路由规则都不需要定义了,直接Get?a=XXX&b=XXX。
2、多个Post方法。
如果按照WebApi官方的规则,那么一个WebApi是不能包含多个Post请求的, 至今我也没找到类似Get重载处理Post重载一样的方法,后来我发现有人建议直接用Action
名称区分(eg. InsertPerson InsertProduct),然后添加HttpPost属性,在前台直接调用,那么我考虑如果这样用的话是不是又违背Restful的设计思想呢?
3、当遇到Delete请求时调用Delete接口始终没有调成功。
一开始我定义Delete接口让前端调用(ajax发送delete请求),一直报405,后来查了一把,说是需要Web.config配置,又是开启IIS DELETE和PUT请求,几种方法全试了最后还是没搞定,无奈之下我改用了POST请求, PUT请求压根没有用。 在群里询问了一把原来他们是在cs中用HttpClient中调用。
4、Post多个参数。
官方建议是使用FromBody标签,多个参数用Dto封装。 自定义Post参数绑定类,继承HttpParameterBinding。然后在Application_Start()中注册:GlobalConfiguration.Configuration.ParameterBindingRules.Insert(0, SimplePostVariableParameterBinding.HookupParameterBinding);
Controller分类
Controller分类主要是为了解决项目过大以后Controller只有一级编目,项目结构上会显的非常凌乱,而且会遇到 ApiController文件同名无法解决的问题,提起Controller分类的话大家首先会想到Area, 但实际应用你会发现那真的是为MVC量身打造的,丝毫没有提WebApi考虑,比如新建Area时文件夹会自动创建Controller、Model、 View, 这些都是不需要的。 那么解决方法就是自己根据项目业务逻辑需要创建Controller编目,最重要的就是自定义Controller Select让WebApi框架找到你定义的文件结构和ApiController【后面会附带代码】。
1、这是我Demo里的Controller结构,包含一个一级编目和二级编目(怎么样,看起来结构一下就清晰多了?)

2、我把用到的Url汇总成一张表格
| Controller名称 | 命名空间 | url |
| AdviseController | MvcApplication4.Controllers.ContractUs | /apix/ContactUs/Advise |
| ProductController | MvcApplication4.Controllers.ContractUs | /apix/ContactUs/Product |
| FinancialController | MvcApplication4.Controllers.Products.Enterprise | /apixx/Products/Enterprise/Financial |
| OfficeController | MvcApplication4.Controllers.Products.Enterprise | /apixx/Products/Enterprise/Office |
| PuzController | MvcApplication4.Controllers.Products.Game | /apixx/Products/Game/Puz |
| RpzController | MvcApplication4.Controllers.Products.Game | /apixx/Products/Game/Rpg |
url里包含前缀apix和apixx,参考博客园一朋友的写法,另外我发现,如果一级编目和二级编目里的前缀如果写成一样是行不通的,会报No Controller was selected to handle this request,所以你需要根据你的编目结构不同而指定不同的前缀,url后就是Area和Category规则。
3、创建完Controller编目结构后就是创建路由规则了(重要)
在这里指定你的接口前缀 apix,apixx
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
); //只有一级编目
config.Routes.MapHttpRoute(
name:"AreaApi",
routeTemplate:"apix/{area}/{controller}/{id}",
defaults:new {id = RouteParameter.Optional}); //包含二级编目
config.Routes.MapHttpRoute(
name: "AreaCategoryApi",
routeTemplate: "apix/{area}/{category}/{controller}/{id}",
defaults: new { id = RouteParameter.Optional });
4、指定完路由规则,如果让WebApi认识你的接口呢? 自定义Controller Selector,继承自DefaultHttpControllerSelector, 对了,创建完自定义Controller Selector后别忘了在Application_Start()中注册,否则也是无效的:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector),new ClassifiedHttpControllerSelector(GlobalConfiguration.Configuration));
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<ConcurrentDictionary<string, Type>> m_apiControllerTypes; public ClassifiedHttpControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
m_configuration = configuration;
m_apiControllerTypes = new Lazy<ConcurrentDictionary<string, Type>>(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<string, Type> GetAllControllerTypes()
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
Dictionary<string, Type> 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<string, Type>(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<KeyValuePair<string, Type>> 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();
}
总结
找到了解决方法后,接下来就是重构项目了,对于Delete和Put请求一直还是想解决,还请大家指点指点。 代码下载 http://pan.baidu.com/s/1bnHQItx
参考资料
1、http://www.cnblogs.com/guogangj/archive/2013/03/11/2950084.html
2、http://blogs.infosupport.com/asp-net-mvc-4-rc-getting-webapi-and-areas-to-play-nicely/
WebApi Controller 分类的更多相关文章
- How to read request body in a asp.net core webapi controller?
原文 How to read request body in a asp.net core webapi controller? A clearer solution, works in ASP.Ne ...
- [.NET WebAPI系列03] WebAPI Controller 中标准CRUD方法
[因] WebAPI的Controller中,一般都是下面四种方法: 对应于数据操作是我们通常所说的CRUD. C对应post,R对应Get,U对应Put,D对应Delete. 直接模仿VS 2012 ...
- WebAPI增加Area以支持无限层级同名Controller
原文:WebAPI增加Area以支持无限层级同名Controller 微软的WebAPI默认实现逻辑 默认实现中不支持同名Controller,否则在访问时会报HttpError,在网上找到了各种路由 ...
- Node.js Express 路由文件分类
前言 基于上一篇Web Api Controller分类,在MVC中我们通常要按自己的业务来划分Controller层, 好处多多,那么Express框架作为Node.js的一款MVC框架,那么自然也 ...
- ABP源码分析三十五:ABP中动态WebAPI原理解析
动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能, ...
- webapi post 请求多个参数
Some programmers are tring to get or post multiple parameters on a WebApi controller, then they will ...
- 给现有MVC 项目添加 WebAPI
1. 增加一个WebApi Controller, VS 会自动添加相关的引用,主要有System.Web.Http,System.Web.Http.WebHost,System.Net.Http 2 ...
- mvc4中的 webapi 的使用方式
目录 一:简单介绍什么是Web api 二:怎么定义的 Post Get Put 和 Delete 三:简单使用,直接从前台传递一个类到后台接收 四:其他获取值的方式 一:简单介绍什么是Web api ...
- ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml)
我们都知道在使用WebApi的时候Controller会自动将Action的返回值自动进行各种序列化处理(序列化为json,xml等),但是如果Controller的自动序列化后的结果不是我们想要的该 ...
随机推荐
- bzoj3631: [JLOI2014]松鼠的新家(LCA+差分)
题目大意:一棵树,以一定顺序走完n个点,求每个点经过多少遍 可以树链剖分,也可以直接在树上做差分序列的标记 后者打起来更舒适一点.. 具体实现: 先求x,y的lca,且dep[x]<dep[y] ...
- AJAX学习随笔
AJAX名为“啊,贾克斯”,听着挺怪的哈. 主要的技术就是XMLHttpRequest对象和Javascript 度娘的解答: AJAX即“AsynchronousJavascriptAndXML”( ...
- Asp.Net Core 发布和部署(Linux + Jexus )
前言 在上篇文章中,主要介绍了 Dotnet Core Run 命令,这篇文章主要是讲解如何在 asp.net core 中对我们的已经完成的程序进行发布和部署. 有关如何使用 Nginx 进行部署, ...
- .NET 4.0 版本号
.NET 4.5.1, .NET 4.5 和 .NET 4.0 均基于 .NET 4.0 CLR,而 .NET 4.5 对 CLR进行了升级和Bug修复. .NET 4.0 - 4.0.30319.1 ...
- Lesson 2 Breakfast or lunch?
Text It was Sunday. I never get up early on Sundays. I sometimes stay in bed until lunchtime. Last S ...
- Python黑帽编程 4.0 网络互连层攻击概述
Python黑帽编程 4.0 网络互连层攻击概述 是时候重新温习下下面这张图了. 图2 本章的内容核心包含上图中的网络层和传输层.TCP/IP是整个网络协议体系中的核心,因为从这里开始,数据传输从局域 ...
- 开始研究web,mark一下
之前想要搞引擎,经过思考之后,定位为webgl方面的引擎,这个决定早就做了,只是没有写下来 做了一些调研之后,确定使用babylon.js 和typescript 和c# 来开发 Babylo ...
- 在浏览器的背后(二) —— HTML语言的语法解析
当你看到这篇文章意味着我辜负了@教主的殷切期望周末木有去约会,以及苏老师@我思故我在北京鼓楼的落井下石成功了…… 本文demo powered by 已经结婚的@老赵的不再维护的wind.js 物是人 ...
- .NET 新标准介绍
本文介绍如何使用 .NET 标准,更容易地实现向 .NET Core 迁移.文中会讨论计划包含的 APIs,跨构架兼容性如何工作以及这对 .NET Core 意味着什么. 如果你对细节感兴趣,这篇文章 ...
- Node.js开发者最常范的10个错误
目录 前言 1 不使用开发工具 1.1 自动重启工具 1.2 浏览器自动刷新工具 2 阻塞event loop 3 频繁调用回调函数 4 圣诞树结构的回调(回调的地狱) 5 创建一个大而完整的应用程序 ...