This repository has been archived by the owner on Dec 14, 2018. It is now read-only.
/
VersionRoute.cs
130 lines (110 loc) · 4.09 KB
/
VersionRoute.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ActionConstraints;
namespace VersioningWebSite
{
public class VersionRoute : RouteAttribute, IActionConstraintFactory
{
private readonly IActionConstraint _constraint;
// 5
// [5]
// (5)
// (5]
// [5)
// (3-5)
// (3-5]
// [3-5)
// [3-5]
// [35-56]
// Parses the above version formats and captures lb (lower bound), range, and hb (higher bound)
// We filter out (5), (5], [5) manually after we do the parsing.
private static readonly Regex _versionParser = new Regex(@"^(?<lb>[\(\[])?(?<range>\d+(-\d+)?)(?<hb>[\)\]])?$");
public bool IsReusable => true;
public VersionRoute(string template)
: base(template)
{
}
public VersionRoute(string template, string versionRange)
: base(template)
{
var constraint = CreateVersionConstraint(versionRange);
if (constraint == null)
{
var message = string.Format("Invalid version format: {0}", versionRange);
throw new ArgumentException(message, "versionRange");
}
_constraint = constraint;
}
private static IActionConstraint CreateVersionConstraint(string versionRange)
{
var match = _versionParser.Match(versionRange);
if (!match.Success)
{
return null;
}
var lowerBound = match.Groups["lb"].Value;
var higherBound = match.Groups["hb"].Value;
var range = match.Groups["range"].Value;
var rangeValues = range.Split('-');
if (rangeValues.Length == 1)
{
return GetSingleVersionOrUnboundedHigherVersionConstraint(lowerBound, higherBound, rangeValues);
}
else
{
return GetBoundedRangeVersionConstraint(lowerBound, higherBound, rangeValues);
}
}
private static IActionConstraint GetBoundedRangeVersionConstraint(
string lowerBound,
string higherBound,
string[] rangeValues)
{
// [3-5, (3-5, 3-5], 3-5), 3-5 are not valid
if (string.IsNullOrEmpty(lowerBound) || string.IsNullOrEmpty(higherBound))
{
return null;
}
var minVersion = int.Parse(rangeValues[0]);
var maxVersion = int.Parse(rangeValues[1]);
// Adjust min version and max version if the limit is exclusive.
minVersion = lowerBound == "(" ? minVersion + 1 : minVersion;
maxVersion = higherBound == ")" ? maxVersion - 1 : maxVersion;
if (minVersion > maxVersion)
{
return null;
}
return new VersionRangeValidator(minVersion, maxVersion);
}
private static IActionConstraint GetSingleVersionOrUnboundedHigherVersionConstraint(
string lowerBound,
string higherBound,
string[] rangeValues)
{
// (5], [5), (5), [5, (5, 5], 5) are not valid
if (lowerBound == "(" || higherBound == ")" ||
(string.IsNullOrEmpty(lowerBound) ^ string.IsNullOrEmpty(higherBound)))
{
return null;
}
var version = int.Parse(rangeValues[0]);
if (!string.IsNullOrEmpty(lowerBound))
{
// [5]
return new VersionRangeValidator(version, version);
}
else
{
// 5
return new VersionRangeValidator(version, maxVersion: null);
}
}
public IActionConstraint CreateInstance(IServiceProvider services)
{
return _constraint;
}
}
}