在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相关推荐
- 如何在Excel中自动创建报告 Excel中自动创建报告的方法
如何在Excel中自动创建报告 Excel中自动创建报告的方法,Excel工作表中存储的数据,可以使用宏来一键创建报告并导出为不同的文件类型.Excel自带步骤记录器,因此你不需要自己编写宏.小编在这 ...
- 如何在SQL Server Reporting Services中自动创建KPI
关键绩效指标(KPI) (Key Performance Indicator (KPI)) A Key Performance Indicator aka KPI is a metric which ...
- Eclipse中自动创建set、get方法
先创建类的属性 菜单栏:Source - Generate Getters and Setters 勾选需要创建的方法
- 性能优化——统计信息——SQLServer自动更新和自动创建统计信息选项
原文: 性能优化--统计信息--SQLServer自动更新和自动创建统计信息选项 原文译自:http://www.mssqltips.com/sqlservertip/2766/sql-server- ...
- Spring Data Jpa 实体类自动创建数据库表失败解决
先说一下我遇到的这个问题,首先我是通过maven创建了一个spring boot的工程,引入了Spring data jpa,结果实体类创建好之后,运行工程却没有在数据库中自动创建数据表. 找了半天发 ...
- 实体类自动创建数据库表失败解决
先说一下我遇到的这个问题,首先我是通过maven创建了一个spring boot的工程,引入了Spring data jpa,结果实体类创建好之后,运行工程却没有在数据库中自动创建数据表. 找了半天发 ...
- docker 是否自动创建主机挂载目录(先看粗体字)
volume :需要注意的是,与bind mount不同的是,如果volume是空的而container中的目录有内容,那么docker会将container目录中的内容拷贝到volume中,但是如果 ...
- aws iam_使用策略哨兵在AWS IAM中自动执行Salesforce云安全性的最小特权
aws iam 介绍 (Intro) The Salesforce Security Assurance team would like to share a tool that we recentl ...
- 如何在驱动代码中中/dev目录内自动创建
在<linux /dev>文章中指出,一般驱动加载之后,需要根据申请到的字符设备号通过使用mknod命令将相对应使用到的字符驱动挂载到/dev目录内,这套方法使用起来非常麻烦,因为每次挂载 ...
最新文章
- Android开发者值得深入思考的几个问题,大厂面经合集
- 数学--数论-- HDU6298 Maximum Multiple 打表找规律
- 数据库-Oracle【Oracle数据库设置默认表空间问题及Oracle,SQL,MySQL的自增变量设置】...
- Java中抽象类和接口的区别?
- 新风口?人造肉第一股表现强劲 股价累计上涨近600%
- 为什么将iostream :: eof放在循环条件(即`while(!stream.eof())`)内?
- uni.request在接口状态码403等还是走success
- 视频防泄密安全解决方案
- 数据恢复工具(minitool power data recovery 8) v8.8(含64位32位)
- leaflet地图鼠标移动画线
- linux环境下删除包含特殊字符的文件或目录
- 访问网站提示:您未被授权查看该页恢复办法
- 今天看了了一下手册,先弄清楚芯片脚功能
- 英特尔i5 1240H
- 网易云信智码超清转码技术实践
- PDF转TXT免费脚本
- 【已解决】联想小新14无线图标消失 | 网络适配器有感叹号 | Windows仍在设置此设备的类配置(代码56)的解决方法
- Android:玩转ADB命令(ADB命令使用大全)
- 为win11家庭中文版开启组策编辑器
- asp.net夜话之八:数据绑定控件(上)
热门文章
- CodeBlocks集成Objective-C开发 Windows下学习Objective-C
- [Object-C语言随笔之二] 《NSLog》常用的打印调试语句与自动排版
- 自适应分辨率可扩展二层JS下拉菜单
- WebSocket的故事(六)—— Springboot中,实现更灵活的WebSocket
- Office 2016 for Mac 15.24已推送至Office Insider慢速更新通道
- No Database Selected
- netty io.netty.buffer简介
- 实用jQuery代码段
- 刚刚入手一台G11,发短信是老是出现“发送自HTC手机”字样
- 浅谈Java的输入输出流