在WebAPI中自动创建Controller
在MIS系统中,大部分的操作都是基本的CRUD,并且这样的Controller非常多。
为了复用代码,我们常常写一个泛型的基类。
public class EntityController<T> : ApiController
{
public
IQueryable<T> GetAll()
{
...
}
public
T Get(int id)
{
...
}
public
T Put(int id, Ink ink)
{
...
}
public
T Post(Ink ink)
{
...
}
public
void Delete(int id)
{
...
}
}
当增加一种类型的时候,我们需要手动增加一个子类:
public
class
InkController : EntityController<Ink>
{
}
public
class
PenController : EntityController<Pen>
{
}
当实体模型比较多的时候仍然就存在繁琐和难以维护的问题。因此我们也需要一种自动创建的机制,
要实现自动创建Controller,首先得把现在这种静态创建Controller的方式改成动态创建的方式。在WebAPI中,我们可以通过替换IHttpControllerSelector来实现动态创建Controller。
首先我们实现自己的IHttpControllerSelector。
public
class
MyControllerSelector : DefaultHttpControllerSelector
{
private
readonly
HttpConfiguration _configuration;
public MyControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
_configuration = configuration;
}
public
override
HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var controllerName = base.GetControllerName(request);
return
new
HttpControllerDescriptor(_configuration, controllerName, typeof(Controllers.EntityController<Ink>));
}
}
然后在初始化函数中注册我们的ControllerSelector
public
static
class
WebApiConfig
{
public
static
void Register(HttpConfiguration config)
{
// Web API configuration and services
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerSelector), new
MyControllerSelector(GlobalConfiguration.Configuration));
// Web API routes
config.MapHttpAttributeRoutes();
……
}
}
这样一来,即使没有子类InkController,我们同样可以特化泛型控制器EntityController<Ink>实现同样的效果。
到这一步后,还存在一个问题:ControllerSelector只能根据HttpRequest获取ControllerName,并不知道其对应的Model,不知道该如何特化EntityController。解决这个问题的常见的方式就是维护一张Controller名称和实体类型的映射表:
public
class
MyControllerSelector : DefaultHttpControllerSelector
{
static
Dictionary<string, Type> _entityMap;
static MyControllerSelector()
{
_entityMap = new
Dictionary<string, Type>(StringComparer.OrdinalIgnoreCase);
_entityMap["Ink"] = typeof(Ink);
_entityMap["Pen"] = typeof(Pen);
}
private
readonly
HttpConfiguration _configuration;
public MyControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
_configuration = configuration;
}
public
override
HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var controllerName = base.GetControllerName(request);
Type entityType = null;
if (!_entityMap.TryGetValue(controllerName.ToLower(), out entityType))
{
return
base.SelectController(request);
}
return
new
HttpControllerDescriptor(_configuration, controllerName, typeof(Controllers.EntityController<>).MakeGenericType(entityType));
}
}
虽然这样做本身没有什么问题。这种手动维护Controller列表的方式仍然无法达到自动创建Controller的要求,因此我们还需要一种自动生成这种映射表的机制。这里我仍然是采用同前文一样的Attribute+反射的方式。
首先写一个ControllerAttribute,
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public
class
ControllerAttribute : Attribute
{
public
string Name { get; private
set; }
public ControllerAttribute(string name)
{
this.Name = name;
}
}
然后,在数据模型中标记该Attribute
[Controller("Pen")]
public
class
Pen
[Controller("Ink")]
public
class
Ink
最后,根据反射建立Controller名称和类型的关联关系
static
Dictionary<string, Type> _entityMap;
static MyControllerSelector()
{
var assembly = typeof(MyControllerSelector).Assembly;
var entityTypes = from type in assembly.GetTypes()
let controllerAtt = type.GetCustomAttribute<ControllerAttribute>()
where controllerAtt != null
select
new { Type = type, ControllerName = controllerAtt.Name };
_entityMap = entityTypes.ToDictionary(i => i.ControllerName, i => i.Type, StringComparer.OrdinalIgnoreCase);
}
这样基本上就可以用了。最后顺手做一下优化,减少的HttpControllerDescriptor创建操作,最终版本的ControllerSelector如下。
public
class
MyControllerSelector : DefaultHttpControllerSelector
{
private
Dictionary<string, HttpControllerDescriptor> _controllerMap;
public MyControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
var entityTypes = from type in
typeof(MyControllerSelector).Assembly.GetTypes()
let controllerAtt = type.GetCustomAttribute<ControllerAttribute>()
where controllerAtt != null
select
new { Type = type, ControllerName = controllerAtt.Name };
_controllerMap = entityTypes.ToDictionary(
i => i.ControllerName,
i => new
HttpControllerDescriptor(configuration, i.ControllerName,
typeof(Controllers.EntityController<>).MakeGenericType(i.Type)),
StringComparer.OrdinalIgnoreCase);
}
public
override
HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
HttpControllerDescriptor controllerDescriptor = null;
if (!_controllerMap.TryGetValue(base.GetControllerName(request), out controllerDescriptor))
{
return
base.SelectController(request);
}
else
{
return controllerDescriptor;
}
}
}
在WebAPI中自动创建Controller的更多相关文章
- 在Code First中自动创建Entity模型
之前我在博客文章中介绍过如何使用Code First来创建数据库,通过CodeFirst的方式,可以大幅的减少开发人员的工作量,比传统的先创建库再ORM的方式简单了不少.但是,很多时候,特别是一些MI ...
- ExtJS6的中sencha cmd中自动创建案例项目代码分析
在之前的博文中,我们按照sencha cmd的指点,在自己win7虚拟机上创建了一个案例项目,相当于创建了一个固定格式的文档目录结构,然后里面自动创建了一系列js代码.这是使用sencha cmd自动 ...
- Xcode6中如何修改文件中自动创建的Created by和Copyright
转自: http://blog.csdn.net/bjourney/article/details/46832159 在Xcode6创建问的时候,会自动生成注释 // Created byxxx o ...
- 在 Xcode中 修改文件中自动创建的Created by和Copyright
在Xcode里创建的时候,会自动生成注释 // Created byxxx on 15/7/10. // Copyright (c) 2015年 xxxx. All rights reserved ...
- 浅谈ETL架构中ODS的作用以及如何在HaoheDI中自动创建ODS表
什么是ODS表? 在ETL架构中,源数据很少会直接抽取加载到数据仓库EDW,二者之间往往会设置一个源数据的临时存储区域,存储数据在清洗转换前的原始形态,通常被大家称做操作型数据存储,简称ODS,在Ki ...
- 013_使用 user.txt 文件中的人员名单,在计算机中自动创建对应的账户并配置初始密码
for i in `cat user.txt`do useradd $i echo "123456" | passwd --stdin $idone
- 转载:性能优化——统计信息——SQLServer自动更新和自动创建统计信息选项
这段时间AX查询变得非常慢,每天都有很多锁. 最后发现是数据库统计信息需要更新. ----------------------------------------------------------- ...
- 性能优化——统计信息——SQLServer自动更新和自动创建统计信息选项
原文:性能优化--统计信息--SQLServer自动更新和自动创建统计信息选项 原文译自:http://www.mssqltips.com/sqlservertip/2766/sql-server-a ...
- [.NET] WebApi 生成帮助文档及顺便自动创建简单的测试工具
==========最终的效果图========== ==========下面开始干活:生成帮助文档========== 一.创建 WebApi 项目 二.找到 HelpPageConfig.cs 并 ...
随机推荐
- chrome49 新特性 chrome.org转载
Transitioning from SPDY to HTTP/2 Thursday, February 11, 2016 Last year we announced our intent to e ...
- AppStore 内购验证的方法
AppStore增加了验证内购(In App Purchasement)的方法, 就是苹果提供一个url地址, 开发测试用: https://sandbox.itunes.apple.com/veri ...
- TCP状态变迁流程
主动建立TCP链接情况: 被动建立TCP链接情况 主动断开链接的情况 被动断开连接的情况 在TIME_WAIT阶段需要停留2倍的MSL,MSL即Maximum Segment Lifetime,表示任 ...
- set的应用
头文件 ;#include <set> 简单应用: begin() 返回set容器的第一个元素 end() 返回set容器的最后一个元素 clear() 删除se ...
- 【NOIP2005】过河
感觉这题好玄--最后看了chty的代码才过,我现在这样必须看题解才能A题怎么办嘛qaq 原题: 在河上有一座独木桥,一只青蛙想沿着独木桥从河的一侧跳到另一侧.在桥上有一些石子,青蛙很讨厌踩在这些石子上 ...
- 组合模式(Composite Pattern)
组合模式主要用来处理一类具有“容器特征”的对象——即它们在充当对象的同时,又可以作为容器包含其他多个对象. 组合模式实现的最关键的地方是——简单对象和复合对象必须实现相同的接口.这就是组合模式能够将组 ...
- Android Studio IDE 简单学习和介绍
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- 设计模式-UML类图的各符号含义(转)
UML类图的各符号含义 类图基本符号可拆分为虚线,箭头,实线,空心右三角,实心右三角,空心菱形和实心菱形.由这些基本的图形进行组合构成了类图的基本符号.这里要注意这几个符号的顺序,代表了类与类之间关系 ...
- mac osx 制作安装u盘
制作OS X El Capitan 原版安装U盘:sudo /Applications/Install\ OS\ X\ El\ Capitan.app/Contents/Resources/creat ...
- 如何理解andriod中的View和framelayout两个概念
View 和 FrameLayout 是包含关系,FrameLayout 继承自ViewGroup,然后继承自View. FrameLayout是一种 ViewGroup,可以在里面放其它的View, ...