128 lines
4.0 KiB
C#
128 lines
4.0 KiB
C#
// 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.AspNet.Mvc;
|
|
using Microsoft.AspNet.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 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;
|
|
}
|
|
}
|
|
} |