Implement a 'required' constraint

This is useful for a variety of interesting scenarios in link generation
where a default value doesn't appear in the route template as a parameter.

This can be used to implement the desired behavior for areas - where the
'area' key is sticky.
This commit is contained in:
Ryan Nowak 2014-07-02 16:38:30 -07:00
parent 63dcdd6ca5
commit 27d6a735af
5 changed files with 142 additions and 0 deletions

View File

@ -20,6 +20,9 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
<DevelopmentServerPort>28778</DevelopmentServerPort>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<DevelopmentServerPort>22209</DevelopmentServerPort>
</PropertyGroup>
<ItemGroup>
<Content Include="project.json" />
<Content Include="web.config" />

View File

@ -0,0 +1,39 @@
// Copyright (c) Microsoft Open Technologies, Inc. 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.Collections.Generic;
using System.Globalization;
using Microsoft.AspNet.Http;
namespace Microsoft.AspNet.Routing.Constraints
{
/// <summary>
/// Constraints a route parameter that must have a value.
/// </summary>
/// <remarks>
/// This constraint is primarily used to enforce that a non-parameter value is present during
/// URL generation.
/// </remarks>
public class RequiredRouteConstraint : IRouteConstraint
{
/// <inheritdoc />
public bool Match(
[NotNull]HttpContext httpContext,
[NotNull]IRouter route,
[NotNull]string routeKey,
[NotNull]IDictionary<string, object> values,
RouteDirection routeDirection)
{
object value;
if (values.TryGetValue(routeKey, out value) && value != null)
{
// In routing the empty string is equivalent to null, which is equivalent to an unset value.
var valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
return !string.IsNullOrEmpty(valueString);
}
return false;
}
}
}

View File

@ -41,6 +41,7 @@
<Compile Include="Constraints\BoolRouteConstraint.cs" />
<Compile Include="Constraints\IntRouteConstraint.cs" />
<Compile Include="Constraints\RegexRouteConstraint.cs" />
<Compile Include="Constraints\RequiredRouteConstraint.cs" />
<Compile Include="DefaultInlineConstraintResolver.cs" />
<Compile Include="IInlineConstraintResolver.cs" />
<Compile Include="INamedRouter.cs" />

View File

@ -0,0 +1,98 @@
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
#if NET45
using System;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Routing.Constraints;
using Moq;
using Xunit;
namespace Microsoft.AspNet.Routing.Tests
{
public class RequiredRouteConstraintTests
{
[Theory]
[InlineData(RouteDirection.IncomingRequest)]
[InlineData(RouteDirection.UrlGeneration)]
public void RequiredRouteConstraint_NoValue(RouteDirection direction)
{
// Arrange
var constraint = new RequiredRouteConstraint();
// Act
var result = constraint.Match(
Mock.Of<HttpContext>(),
Mock.Of<IRouter>(),
"area",
new RouteValueDictionary(new { controller = "Home", action = "Index" }),
direction);
// Assert
Assert.False(result);
}
[Theory]
[InlineData(RouteDirection.IncomingRequest)]
[InlineData(RouteDirection.UrlGeneration)]
public void RequiredRouteConstraint_Null(RouteDirection direction)
{
// Arrange
var constraint = new RequiredRouteConstraint();
// Act
var result = constraint.Match(
Mock.Of<HttpContext>(),
Mock.Of<IRouter>(),
"area",
new RouteValueDictionary(new { controller = "Home", action = "Index", area = (string)null }),
direction);
// Assert
Assert.False(result);
}
[Theory]
[InlineData(RouteDirection.IncomingRequest)]
[InlineData(RouteDirection.UrlGeneration)]
public void RequiredRouteConstraint_EmptyString(RouteDirection direction)
{
// Arrange
var constraint = new RequiredRouteConstraint();
// Act
var result = constraint.Match(
Mock.Of<HttpContext>(),
Mock.Of<IRouter>(),
"area",
new RouteValueDictionary(new { controller = "Home", action = "Index", area = string.Empty}),
direction);
// Assert
Assert.False(result);
}
[Theory]
[InlineData(RouteDirection.IncomingRequest)]
[InlineData(RouteDirection.UrlGeneration)]
public void RequiredRouteConstraint_WithValue(RouteDirection direction)
{
// Arrange
var constraint = new RequiredRouteConstraint();
// Act
var result = constraint.Match(
Mock.Of<HttpContext>(),
Mock.Of<IRouter>(),
"area",
new RouteValueDictionary(new { controller = "Home", action = "Index", area = "Store" }),
direction);
// Assert
Assert.True(result);
}
}
}
#endif

View File

@ -40,6 +40,7 @@
<Compile Include="Constraints\AlphaRouteConstraintTests.cs" />
<Compile Include="Constraints\RegexConstraintTests.cs" />
<Compile Include="Constraints\IntRouteConstraintsTests.cs" />
<Compile Include="Constraints\RequiredRouteConstraintTests.cs" />
<Compile Include="DefaultInlineConstraintResolverTest.cs" />
<Compile Include="RouteCollectionTest.cs" />
<Compile Include="InlineRouteParameterParserTests.cs" />