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的自动序列化后的结果不是我们想要的该 ...
随机推荐
- Sage Crm 权限原理分析
文字是11年写的,贴出来共享一下,先来一张表结构图: 一.区域.表名:[territories] 1.我们先来看看区域表的结构. 从图中前面都是不能为空的字段,都是很重要的.来介绍一下这些字段: Te ...
- 报文解析及CRC类
/// <summary> /// 报文解析转换类 /// </summary> public class DatagramConvert { public static En ...
- 用Fmx调用Bass.dll
先上图 帮亲戚做个小软件,选用FMX,因为画面不会像vcl那样在图片多的时候闪烁.还能添加动画 但是MediaPlayer播放音乐视频真是不给力,视频没想到好办法.音频方面想到之前万一的Bass.ll ...
- CSDN:你认为一名优秀的技术人应该具备怎样的素质?
CSDN:你认为一名优秀的技术人应该具备怎样的素质? 王晶昱:我个人认为,符合这个世界要求的就是优秀的.在目前这个时代,我认为一个优秀的技术人员的特质可能是: 兴趣驱动,兴趣是最好的老师,写程序本身就 ...
- WiFi流量劫持—— JS脚本缓存投毒
在上一篇<WiFi流量劫持—— 浏览任意页面即可中毒>构思了一个时光机原型,让我们的脚本通过HTTP缓存机制,在未来的某个时刻被执行,因此我们可以实现超大范围的入侵了. 基于此原理,我们用 ...
- 《R in Action》读书笔记(3) 数据变换
MindMapper 原文件
- dofile执行ANDROID APK里面的文件
我使用dofile执行APK文件是不行的,比如 dofile("assets/res/flist")只能先拷贝到writablePath然后再dofile拿到数据后再清除这个临时文 ...
- 京东招聘Java开发人员
软件开发工程师(JAVA) 岗位职责: 1. 负责京东核心业务系统的需求分析.设计.开发工作 2. 负责相关技术文档编写工作 3. 解决系统中的关键问题和技术难题 任职要求: 1. 踏实诚恳.责任心强 ...
- xamarin UWP自定义圆角按钮
uwp自带的button本身不支持圆角属性,所以要通过自定义控件实现. 通过设置Button的Background=“{x:Null}”设置为Null使背景为空,再设置Button.Content中的 ...
- 2013 duilib入门简明教程 -- 事件处理和消息响应 (17)
界面的显示方面就都讲完啦,下面来介绍下控件的响应. 前面的教程只讲了按钮和Tab的响应,即在Notify函数里处理.其实duilib还提供了另外一种响应的方法,即消息映射DUI_BEG ...