前言

写这篇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 分类的更多相关文章

  1. 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 ...

  2. [.NET WebAPI系列03] WebAPI Controller 中标准CRUD方法

    [因] WebAPI的Controller中,一般都是下面四种方法: 对应于数据操作是我们通常所说的CRUD. C对应post,R对应Get,U对应Put,D对应Delete. 直接模仿VS 2012 ...

  3. WebAPI增加Area以支持无限层级同名Controller

    原文:WebAPI增加Area以支持无限层级同名Controller 微软的WebAPI默认实现逻辑 默认实现中不支持同名Controller,否则在访问时会报HttpError,在网上找到了各种路由 ...

  4. Node.js Express 路由文件分类

    前言 基于上一篇Web Api Controller分类,在MVC中我们通常要按自己的业务来划分Controller层, 好处多多,那么Express框架作为Node.js的一款MVC框架,那么自然也 ...

  5. ABP源码分析三十五:ABP中动态WebAPI原理解析

    动态WebAPI应该算是ABP中最Magic的功能之一了吧.开发人员无须定义继承自ApiController的类,只须重用Application Service中的类就可以对外提供WebAPI的功能, ...

  6. webapi post 请求多个参数

    Some programmers are tring to get or post multiple parameters on a WebApi controller, then they will ...

  7. 给现有MVC 项目添加 WebAPI

    1. 增加一个WebApi Controller, VS 会自动添加相关的引用,主要有System.Web.Http,System.Web.Http.WebHost,System.Net.Http 2 ...

  8. mvc4中的 webapi 的使用方式

    目录 一:简单介绍什么是Web api 二:怎么定义的 Post Get Put 和 Delete 三:简单使用,直接从前台传递一个类到后台接收 四:其他获取值的方式 一:简单介绍什么是Web api ...

  9. ASP.NET MVC WebApi 返回数据类型序列化控制(json,xml)

    我们都知道在使用WebApi的时候Controller会自动将Action的返回值自动进行各种序列化处理(序列化为json,xml等),但是如果Controller的自动序列化后的结果不是我们想要的该 ...

随机推荐

  1. CentOS6.5安装中文输入法

    首先进入命令形式的客户端 切换成root用户,输入命令"su root"即可,接着输入 yum install "@Chinese Support" 命令按en ...

  2. jquery 购物车飞入效果

    github https://github.com/amibug/fly demo https://github.com/amibug/fly

  3. GDB调试汇编分析

    GDB调试汇编分析 代码 本次实践我参照了许多先做了的同学的博客,有卢肖明,高其,张梓靖同学.代码借用的是卢肖明同学的代码进行调试运行. GCC编译 使用gcc -g gdbtest.c -o gdb ...

  4. 关于HTML是什么,能做什么

    HTML(Hyper Text Mark-up Language )即超文本标记语言,是 WWW 的描述语言,由 Tim Berners-lee提出.设计 HTML 语言的目的是为了能把存放在一台电脑 ...

  5. .NET面试题系列[9] - IEnumerable

    .NET面试题系列目录 什么是IEnumerable? IEnumerable及IEnumerable的泛型版本IEnumerable<T>是一个接口,它只含有一个方法GetEnumera ...

  6. 剑指Offer面试题:9.二进制中1的个数

    一.题目:二进制中1的个数 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数.例如把9表示成二进制是1001,有2位是1.因此如果输入9,该函数输出2. 二.可能引起死循环的解法 一个 ...

  7. MySQL 清空慢查询文件

    标签:配置慢查询 概述 本章主要写当慢查询文件很大的时候怎样在线生成一个新的慢查询文件. 测试环境:mysql 5.6.21 步骤 配置慢查询 默认的my.cnf文件在/etc/目录下 vim /et ...

  8. Win7&Ubuntu12.04 双系统引导问题

    周末的时候手贱,重装系统,导致原来的ubuntu12.04和win7双系统的引导不见了,所以在此进行一下说明,如何修复. 1. win7和ubuntu12.04双系统引导修复 问题描述:    在重装 ...

  9. 【VC++技术杂谈004】使用微软TTS语音引擎实现文本朗读

    本文主要介绍如何使用微软TTS语音引擎实现文本朗读,以及生成wav格式的声音文件. 1.语音引擎及语音库的安装 TTS(Text-To-Speech)是指文本语音的简称,即通过TTS引擎把文本转化为语 ...

  10. [译]libev和libevent的设计差异

    本文译自what's the difference between libev and libevent? 作者是libev作者 [问]两个库都是为异步io调度而设计,在Linux上都是使用epoll ...