版本控制

 

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

    版本控制   版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionController ...

  2. 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用

    由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...

  3. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【开篇】【持续更新中。。。】

    最近发现web api很火,园内也有各种大神已经在研究,本人在asp.net官网上看到一个系列教程,原文地址:http://bitoftech.net/2013/11/25/detailed-tuto ...

  4. 2.3属性在 ASP.NET Web API 2 路由

    路由是 Web API 如何匹配 URI 的行动.Web API 2 支持一种新型的路由,称为属性路由.顾名思义,属性路由使用属性来定义路由.属性路由给你更多的控制 Uri 在您的 web API.例 ...

  5. 使用ASP.NET Web Api构建基于REST风格的服务实战系列教程【九】——API变了,客户端怎么办?

    系列导航地址http://www.cnblogs.com/fzrain/p/3490137.html 前言 一旦我们将API发布之后,消费者就会开始使用并和其他的一些数据混在一起.然而,当新的需求出现 ...

  6. ASP.NET Web Api 服务器端变了,客户端该如何修改请求(转载)

    转载地址:http://www.cnblogs.com/fzrain/p/3558765.html 前言 一旦我们将API发布之后,消费者就会开始使用并和其他的一些数据混在一起.然而,当新的需求出现时 ...

  7. Asp.Net Web API 2第八课——Web API 2中的属性路由

    前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 路由就是Web API如何 ...

  8. Asp.Net Web API 2第五课——Web API路由

    Asp.Net Web API 导航   Asp.Net Web API第一课——入门 http://www.cnblogs.com/aehyok/p/3432158.html Asp.Net Web ...

  9. 【ASP.NET Web API教程】4.1 ASP.NET Web API中的路由

    原文:[ASP.NET Web API教程]4.1 ASP.NET Web API中的路由 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本博客文章,请先看前面的内容. ...

随机推荐

  1. java 虚拟机与并发处理几个问题简要(一)

    一.   处理任务时,应该将代码分成不同的部分,每一部分由一个线程进行,但是会因为任务负载不平衡导致有闲有忙.最好是应分成不同的部分,分配不同的线程,尽量让处理器不停的处理,不要闲下来.如何分配线程数 ...

  2. ZOJ 1489 HDU1395 2^x mod n = 1 数学

    2^x mod n = 1 Time Limit: 2 Seconds      Memory Limit:65536 KB Give a number n, find the minimum x t ...

  3. Two-phase clustering process for outliers detection 文章翻译

    基于二阶段聚集模式的异常探测 M.F .Jiang, S.S. Tseng *, C.M. Su 国立交通大学计算机与信息科学系,中国台北市新竹路100150号 1999年11月17日; 2000年4 ...

  4. JAVA提高五:注解Annotation

    今天我们学习JDK5.0中一个非常重要的特性,叫做注解.是现在非常流行的一种方式,可以说因为配置XML 比较麻烦或者比容易查找出错误,现在越来越多的框架开始支持注解方式,比如注明的Spring 框架, ...

  5. Linux计划任务-at命令

    第一部分:at命令   1. at命令:在一个指定的时间执行一个指定任务,只能执行一次,且需要开启atd进程(ps -ef | grep atd查看, 开启用/etc/init.d/atd start ...

  6. mysql 中翻页

    万变不离其中 select * from tableName where 条件 limit 当前页码*页面容量-1 , 页面容量

  7. PHP中的封装和继承

    1. 封装 1.1什么是封装? 通过访问修饰符,将类中的属性和方法进行私有化处理,并提供唯一的设置和读取的 set/get方法,以实现访问控制.这个过程称为封装. 注意:是实现访问控制,而不是拒绝访问 ...

  8. 用source语句引用mysql文件的细节注意

    今天在使用 mysql数据库的时候,创建 数据表的时候出现了很多的小问题,今天一天花费了大量的时间去解决这些问题.首先就是一些小的细节,在文本编辑器上编辑好了SQL语句,然后转移到mysql的命令行中 ...

  9. 07-从零玩转JavaWeb-对象内存分析

    上篇看了关于数组的内存分析,接下来看一下对象的内存分析 假定有如下类:  第一步会把Person的字节码放到方法区   执行main方法,把main方法的栈帧放到栈当中   Person zly = ...

  10. Linux 源码编译Python 3.6

    Linux 源码编译Python 3.6 1.操作系统以及版本显示 # uname -sr Linux 3.10.0-514.el7.x86_64 # uname -sr Linux 3.10.0-5 ...