擴展Webapi中的RouteConstraint中,讓DateTime類型,支持時間格式化(DateTimeFormat)
一、背景
大家在使用WebApi時,會用到DateTime爲參數,類似於這樣:
//url: xxx/2016-09-08
[HttpGet("{date:datetime}")]
public string Get(DateTime date)
{
return date.ToString("yyyyMMdd");
}
但是":datetime" 支持這樣的格式:
12/25/2009
11:45:00 PM
11:45:00
11:45
Apr 5 2009 11:45:00 PM
April 5 2009 11:45:00 PM
12/25/2009 11:45:00 PM
11:45:00 PM
2009-05-12T11:45:00Z
但我們有的時候想要的是類似這樣的格式:
20091225
091225
12252009
或是各種自定義的時間格式。
二、目的
用簡單的辦法來自定義這個時間格式。比如正則":regex"是支持參數的,我們讓默認的":datetime"來支持一個參數。 比如":datetime(yyyyMMdd)"
三、實現
要做一個自定義的 RouteConstraint ,我們要實現一個接口 IRouteConstraint 。
但我們可以偷個懶,我們找到DateTimeRouteConstraint的源碼,做一些修改。
Routing 源碼地址 :https://github.com/aspnet/Routing
找到 Routing/src/Microsoft.AspNetCore.Routing/Constraints/DateTimeRouteConstraint.cs
源碼:
public class DateTimeRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match(
HttpContext httpContext,
IRouter route,
string routeKey,
RouteValueDictionary values,
RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));
}
if (values == null)
{
throw new ArgumentNullException(nameof(values));
}
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is DateTime)
{
return true;
}
DateTime result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return DateTime.TryParse(valueString, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
}
return false;
}
}
我們來對這個做一點修改。給他增加兩個構造函數。
一個有一個string參數,用來接受DateTimeFormat。
一個無參數的,用來兼容默認無參的情況。
別的不多說了,直接上代碼。
public class DateTimeExRouteConstraint : IRouteConstraint
{
private readonly string _dateTimeformat;
public DateTimeExRouteConstraint(string p_dateTimeformat)
{
_dateTimeformat = p_dateTimeformat;
}
public DateTimeExRouteConstraint()
{
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
if (httpContext == null)
{
throw new ArgumentNullException(nameof(httpContext));
}
if (route == null)
{
throw new ArgumentNullException(nameof(route));
}
if (routeKey == null)
{
throw new ArgumentNullException(nameof(routeKey));
}
if (values == null)
{
throw new ArgumentNullException(nameof(values));
}
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
if (value is DateTime)
{
return true;
}
DateTime result;
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
if (!string.IsNullOrEmpty(_dateTimeformat))
{
var success = DateTime.TryParseExact(valueString, _dateTimeformat, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
if (success)
{
values[routeKey] = result;
}
return success;
}
return DateTime.TryParse(valueString, CultureInfo.InvariantCulture, DateTimeStyles.None, out result);
}
return false;
}
}
然後我們用這個新的 DateTimeExRouteConstraint 來替換默認的 RouteConstraint 。
找到 Startup.cs 的 ConfigureServices 方法,添加
services.Configure<RouteOptions>(options => options.ConstraintMap["datetime"] = typeof(DateTimeExRouteConstraint));
四、使用
實現以後,我們就可以愉快的使用的DateTimeFormat 的方式了。
比如這樣
//url: xxx/20160908
[HttpGet("{date:datetime(yyyyMMdd)}")]
public string Get(DateTime date)
{
return date.ToString();
}
或者這樣
//url: xxx/160908
[HttpGet("{date:datetime(yyMMdd)}")]
public string Get(DateTime date)
{
return date.ToString();
}
再或者這樣
//url: xxx/09082016
[HttpGet("{date:datetime(MMddyyyy)}")]
public string Get(DateTime date)
{
return date.ToString();
}
全看你喜歡了。