版本控制

 

版本控制的方法有很多,这里提供一种将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编程——版本控制的更多相关文章

  1. ASP.NET Web API编程——路由

    路由过程大致分为三个阶段: 1)请求URI匹配已存在路由模板 2)选择控制器 3)选择操作 1匹配已存在的路由模板 路由模板 在WebApiConfig.Register方法中定义路由,例如模板默认生 ...

  2. ASP.NET Web API编程——序列化与内容协商

    1 多媒体格式化器 多媒体类型又叫MIME类型,指示了数据的格式.在HTTP协议中多媒体类型描述了消息体的格式.一个多媒体类型包括两个字符串:类型和子类型. 例如: text/html.image/p ...

  3. ASP.NET Web API编程——构建api帮助文档

    1 概要 创建ASP.NET Web Api 时模板自带Help Pages框架. 2 问题 1)使用VS创建Web Api项目时,模板将Help Pages框架自动集成到其中,使得Web Api项目 ...

  4. ASP.NET Web API编程——模型验证与绑定

    1.模型验证 使用特性约束模型属性 可以使用System.ComponentModel.DataAnnotations提供的特性来限制模型. 例如,Required特性表示字段值不能为空,Range特 ...

  5. ASP.NET Web API编程——文件上传

    首先分别介绍正确的做法和错误的做法,然后分析他们的不同和错误之处,以便读者在实现此功能时可避开误区 1正确的做法 public class AvaterController : BaseApiCont ...

  6. ASP.NET Web API编程——异常捕获

    1 向客户端发送错误消息 使用throw new HttpResponseException()向客户端抛出错误信息. HttpResponseException包含两个重载的构造函数,其中一个是构造 ...

  7. ASP.NET Web API编程——文件下载

    断点续传基本原理 HTTP协议中与断点续传相关的HTTP头为:Range和Content-Range标头,断点续传实现流程: 1)客户端请求下载一个文件,文件的总长度为n:已经下载了一部分文件,长度为 ...

  8. ASP.NET Web API编程——客户端调用

    可以使用HttpClient这个调用Web API,下面是HttpClient的定义,列举了一些常用的方法,其中还有一些没有列举,包括重载的方法. public class HttpClient : ...

  9. ASP.NET Web API编程——使用Odata

    路由配置 routePrefix路由前缀,必须含有Odata字符串,否则路由不到Odata控制器. V1表示版本,可以使用这种方式进行版本控制,也可以使用其他方式. config.Count().Fi ...

随机推荐

  1. Map.Entry遍历集合中的元素

    Entry是Map中的一个内部累,map.entrySet()可以得到key和value的视图给你一个比较简单的小事例public static void main(String[] args) { ...

  2. IDEA创建一个Spring MVC 框架Java Web项目,Gradle构建

    注:此篇有些细节没写出,此文主要写重要的环节和需要注意的地方,轻喷 新建项目 选择Gradle , 勾选java 和 web.之后就是设定项目路径和名称,这里就不啰嗦了. build.gradle文件 ...

  3. Java基础(十三)反射

    一.反射 1.反射概念 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的 ...

  4. 一、python简单爬取静态网页

    一.简单爬虫框架 简单爬虫框架由四个部分组成:URL管理器.网页下载器.网页解析器.调度器,还有应用这一部分,应用主要是NLP配合相关业务. 它的基本逻辑是这样的:给定一个要访问的URL,获取这个ht ...

  5. php foreach遍历

    foreach($facility_list['data'] as $facility){ //处理语句} 第一种格式遍历给定的 array_expression_r_r 数组.每次循环中,当前单元的 ...

  6. Postman安装及入门实践(以百度搜索为例)

    一.Postman安装 可以FQ的小伙伴可以直接去官网下载:https://www.getpostman.com 如果不能,可以用我的安装包,版本找最新的:链接:https://pan.baidu.c ...

  7. JavaScript练习笔记整理·1 - 6.23

    练习平台Codewars地址:https://www.codewars.com/ 欢迎和大家一起来讨论~╭( ・ㅂ・)و ̑̑   基础练习(1):   我的解答为: class SmallestIn ...

  8. 《一马当先 O2O创业真人秀》阿里云创客+项目提交报名中

    传统行业与互联网的相互融合,线上与线下的互通,正在掀起一股“互联网+”新风潮和创业热潮.支付宝钱包.快的打车.淘点点……这些耳熟能详的应用早已成为人们生活的一部分.而越来越多的“互联网+”创新项目,将 ...

  9. opencv 从摄像头中读取视频并保存(c++版)

    原文:http://blog.csdn.net/zhongshijunacm/article/details/68947890 OpenCV中的视频操作函数如下表所列: VideoCapture Vi ...

  10. 数据库聚焦与非聚焦索引 事务处理 redis innodb引擎(九)

    1 数据库事务处理 一个数据库事务通常包含对数据库进行读或写的一个操作序列 . 当一个事务被提交给了DBMS(数据库管理系统),则DBMS需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库 ...