ASP.NET Web API编程——版本控制
版本控制
版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionControllerSelector来选择控制器过滤器,而不是直接选择控制器。
采用此机制来控制版本,应按照如下规则命名控制器:
自定义标识符+版本+Controller
自定义标识符:能体现控制器含义的字符串
版本:表示版本的字符串,例如:V1,V1.0;不建议使用V1.0这样的写法,因为这样控制器名称会相当怪异,如果表示小版本号,那么可以使用V1D0,这种写法,即用一个字母代替句号。
命名空间对应了项目文件的组织形式,控制器的命名空间为:
1 Odata版本控制
扩展DefaultHttpControllerSelector
public class ODataVersionControllerSelector : DefaultHttpControllerSelector
{
public Dictionary<string, string> RouteVersionSuffixMapping { get; set; } public ODataVersionControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
if (RouteVersionSuffixMapping == null)
{
RouteVersionSuffixMapping = new Dictionary<string, string>();
}
} public override string GetControllerName(HttpRequestMessage request)
{
var controllerName = base.GetControllerName(request);
if (string.IsNullOrEmpty(controllerName))
{
return controllerName;
} var routeName = request.ODataProperties().RouteName;
if (string.IsNullOrEmpty(routeName))
{
return controllerName;
} var mapping = GetControllerMapping(); if (!RouteVersionSuffixMapping.ContainsKey(routeName))
{
return controllerName;
} var versionControllerName = controllerName + RouteVersionSuffixMapping[routeName];
return mapping.ContainsKey(versionControllerName)
? versionControllerName
: controllerName;
}
}
修改WebApiConfig.Register方法
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
...... //odata路由
config.MapODataServiceRoute(
routeName: "V1OdataRouteVersioning",
routePrefix: "Odata/V1",
model: GetEdmModel());
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
config.AddODataQueryFilter(); config.Services.Replace(typeof(IHttpControllerSelector), new ODataVersionControllerSelector (config));
var controllerSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as ODataVersionControllerSelector ;
controllerSelector.RouteVersionSuffixMapping.Add("V1OdataRouteVersioning", "V1"); ......
}
} private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
#region Publication
var publicationsSet = builder.EntitySet<Publication>("Publications").EntityType.Collection;
var getPublicationsFunction = publicationsSet.Function("GetPublications").Returns<PublicationDTO>();
getPublicationsFunction.Parameter<int>("userId"); publicationsSet.Action("AddPublication").Returns<int>().Parameter<PublicationAddBindingModel>("publicationAddBM");
publicationsSet.Action("DeletePublication").Returns<IHttpActionResult>().Parameter<PublicationDelBindingModel>("publicationDelBM");
#endregion builder.Namespace = "Service";
return builder.GetEdmModel();
}
2 普通Api版本控制
扩展IHttpControllerSelector
public class NormalVersionControllerSelector : IHttpControllerSelector
{
private const string Version = "version";
private const string ControllerKey = "controller"; private readonly HttpConfiguration _configuration;
private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _controllers;
private readonly HashSet<string> _duplicates; public NormalVersionControllerSelector(HttpConfiguration config)
{
_configuration = config;
_duplicates = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
_controllers = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDictionary);
} private Dictionary<string, HttpControllerDescriptor> InitializeControllerDictionary()
{
var dictionary = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase); IAssembliesResolver assembliesResolver = _configuration.Services.GetAssembliesResolver();
IHttpControllerTypeResolver controllersResolver = _configuration.Services.GetHttpControllerTypeResolver(); ICollection<Type> controllerTypes = controllersResolver.GetControllerTypes(assembliesResolver); foreach (Type t in controllerTypes)
{
var segments = t.Namespace.Split(Type.Delimiter); //去掉HY_WebApi.V1.Controllers.KeyController中的HY_WebApi.
//去掉HY_WebApi.HYDB.V1.Controllers.HYSearchController中的HY_WebApi.HYDB.
//因此,保留V1.Controllers.KeyController这三部分
//键值格式如:V1.Controllers.KeyController
string[] items = t.FullName.Split(new char[]{'.'},StringSplitOptions.RemoveEmptyEntries);
int count = items.Count();
var key = string.Format("{0}.{1}.{2}", items[count - ], items[count - ], items[count - ]); // Check for duplicate keys.
if (dictionary.ContainsKey(key))
{
_duplicates.Add(key);
}
else
{
dictionary[key] = new HttpControllerDescriptor(_configuration, t.Name, t);
}
} return dictionary;
} // Get a value from the route data, if present.
private static T GetRouteVariable<T>(IHttpRouteData routeData, string name)
{
object result = null;
if (routeData.Values.TryGetValue(name, out result))
{
return (T)result;
}
return default(T);
} public HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
IHttpRouteData routeData = request.GetRouteData();
if (routeData == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
} // Get the namespace and controller variables from the route data.
string version = GetRouteVariable<string>(routeData, Version);
if (version == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
} string controllerName = GetRouteVariable<string>(routeData, ControllerKey);
if (controllerName == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
} // 匹配控制器
string key = String.Format("{0}.Controllers.{1}{2}Controller", version, controllerName,version); HttpControllerDescriptor controllerDescriptor;
if (_controllers.Value.TryGetValue(key, out controllerDescriptor))
{
return controllerDescriptor;
}
else if (_duplicates.Contains(key))
{
throw new HttpResponseException(
request.CreateErrorResponse(HttpStatusCode.InternalServerError,
"Multiple controllers were found that match this request."));
}
else
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
} public IDictionary<string, HttpControllerDescriptor> GetControllerMapping()
{
return _controllers.Value;
}
}
}
修改WebApiConfig.Register方法
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{ ...... // Web API 路由
config.Routes.MapHttpRoute(
name: "defaultRoute",
routeTemplate: "api/{version}/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Services.Replace(typeof(IHttpControllerSelector), new NormalVersionControllerSelector(config)); ...... }
}
3 同时支持Odata,与普通Web Api版本控制
扩展DefaultHttpControllerSelector
public class VersionControllerSelector : DefaultHttpControllerSelector
{
public Dictionary<string, string> RouteVersionSuffixMapping { get; set; }
private HttpConfiguration configuration;
public VersionControllerSelector(HttpConfiguration configuration)
: base(configuration)
{
this.configuration = configuration;
if (RouteVersionSuffixMapping == null)
{
RouteVersionSuffixMapping = new Dictionary<string, string>();
}
}
public override string GetControllerName(HttpRequestMessage request)
{
return SelectController(request).ControllerName;
} public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
var routeName = request.ODataProperties().RouteName; if (!string.IsNullOrWhiteSpace(routeName))
{//odata路由
var selector = new ODataVersionControllerSelector(configuration);
selector.RouteVersionSuffixMapping = RouteVersionSuffixMapping;
return selector.SelectController(request);
}
else
{//普通路由
var selector = new NormalVersionControllerSelector(configuration);
return selector.SelectController(request);
}
}
} 修改WebApiConfig.Register方法
public static class WebApiConfig public static void Register(HttpConfiguration config)
{
// Web API 路由
config.Routes.MapHttpRoute(
name: "defaultRoute",
routeTemplate: "api/{version}/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
); //odata路由
config.MapODataServiceRoute(
routeName: "V1OdataRouteVersioning",
routePrefix: "Odata/V1",
model: GetEdmModel());
config.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
config.AddODataQueryFilter(); config.Services.Replace(typeof(IHttpControllerSelector), new VersionControllerSelector(config));
var controllerSelector = config.Services.GetService(typeof(IHttpControllerSelector)) as VersionControllerSelector;
controllerSelector.RouteVersionSuffixMapping.Add("V1OdataRouteVersioning", "V1");
}
}
其中GetEdmModel()方法与前述方法相同。
ASP.NET Web API编程——版本控制的更多相关文章
- ASP.NET Web API编程——路由
路由过程大致分为三个阶段: 1)请求URI匹配已存在路由模板 2)选择控制器 3)选择操作 1匹配已存在的路由模板 路由模板 在WebApiConfig.Register方法中定义路由,例如模板默认生 ...
- ASP.NET Web API编程——序列化与内容协商
1 多媒体格式化器 多媒体类型又叫MIME类型,指示了数据的格式.在HTTP协议中多媒体类型描述了消息体的格式.一个多媒体类型包括两个字符串:类型和子类型. 例如: text/html.image/p ...
- ASP.NET Web API编程——构建api帮助文档
1 概要 创建ASP.NET Web Api 时模板自带Help Pages框架. 2 问题 1)使用VS创建Web Api项目时,模板将Help Pages框架自动集成到其中,使得Web Api项目 ...
- ASP.NET Web API编程——模型验证与绑定
1.模型验证 使用特性约束模型属性 可以使用System.ComponentModel.DataAnnotations提供的特性来限制模型. 例如,Required特性表示字段值不能为空,Range特 ...
- ASP.NET Web API编程——文件上传
首先分别介绍正确的做法和错误的做法,然后分析他们的不同和错误之处,以便读者在实现此功能时可避开误区 1正确的做法 public class AvaterController : BaseApiCont ...
- ASP.NET Web API编程——异常捕获
1 向客户端发送错误消息 使用throw new HttpResponseException()向客户端抛出错误信息. HttpResponseException包含两个重载的构造函数,其中一个是构造 ...
- ASP.NET Web API编程——文件下载
断点续传基本原理 HTTP协议中与断点续传相关的HTTP头为:Range和Content-Range标头,断点续传实现流程: 1)客户端请求下载一个文件,文件的总长度为n:已经下载了一部分文件,长度为 ...
- ASP.NET Web API编程——客户端调用
可以使用HttpClient这个调用Web API,下面是HttpClient的定义,列举了一些常用的方法,其中还有一些没有列举,包括重载的方法. public class HttpClient : ...
- ASP.NET Web API编程——使用Odata
路由配置 routePrefix路由前缀,必须含有Odata字符串,否则路由不到Odata控制器. V1表示版本,可以使用这种方式进行版本控制,也可以使用其他方式. config.Count().Fi ...
随机推荐
- Expression Blend实例中文教程(4) - 布局控件快速入门Canvas
上一篇,我介绍了Silverlight控件被分为三种类型, 第一类: Layout Controls(布局控件) 第二类: Item Controls (项目控件) 第三类: User Interac ...
- 最近使用日期控件时,用到了My97DatePicker控件,单日期控件,记录一下
以上是使用时的效果,可以自己设定日期有效区间,如下图: 对于起始日期和终止日期的控制如下: <td> <label >起始日期:</label> <input ...
- CSS属性: 阴影 轮廓 渐变
注: 本文摘自 宁静致远 - CSDN / 但愿人长久 千里共婵娟 - CSDN 阴影 使用box-shadow属性可以为元素添加阴影效果, 比如 box-shadow: h-shadow v-sha ...
- 配合sublime使用flexible.js实现微信开发页面自适应
什么是flexible.js 是一个终端设备适配的解决方案.也就是说它可以让你在不同的终端设备中实现页面适配. 是一个用来适配移动端的javascript框架.根据宽度的不同设置不同的字体大小,样式间 ...
- SSIS 和 SSRS自制Template
可以使用VS 制作一个SSIS 的Package. 路径:C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssembl ...
- CentOS 7运维管理笔记(4)----安装ftp服务器
在CentOS 7下安装ftp服务器,可以使局域网内的主机拥有共享文件的一个站点. 在Linux系统下,vsftp是一款应用比较广泛的FTP软件,其特点是小巧轻快,安全易用.目前在开源操作系统中常用的 ...
- RoadFlow工作流与JUI(DWZ)前端框架的集成
此文只说明RoadFlow前端与JUI的集成,关于程序和接口请参照WebForm或MVC文档. 修改JUI配置文件dwz.frag.xml,此文件一般位于JUI根目录下. 2.修改文件js/dwz.n ...
- Java——实现对密码进行MD5加密
package common; /** *@author作者 E-Mail: *@version 创建时间:2015-9-24+下午01:22:44 *类说明 **/ import java.secu ...
- IE的兼容性设置 X-UA-Compatible
< meta http-equiv = "X-UA-Compatible" content = "IE=edge,chrome=1" /> 是IE8 ...
- ESP32D0WDQ6 灯泡 黑客
这个黑客表现得如何聪明 灯泡 可能泄漏您的Wi-Fi密码O网页链接破解者博客详文 Pwn the LIFX Mini white O网页链接ESP32D0WDQ6, a SoC from ESPRES ...