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:
parent
63dcdd6ca5
commit
27d6a735af
|
|
@ -20,6 +20,9 @@
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'">
|
||||||
<DevelopmentServerPort>28778</DevelopmentServerPort>
|
<DevelopmentServerPort>28778</DevelopmentServerPort>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||||
|
<DevelopmentServerPort>22209</DevelopmentServerPort>
|
||||||
|
</PropertyGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="project.json" />
|
<Content Include="project.json" />
|
||||||
<Content Include="web.config" />
|
<Content Include="web.config" />
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
<Compile Include="Constraints\BoolRouteConstraint.cs" />
|
<Compile Include="Constraints\BoolRouteConstraint.cs" />
|
||||||
<Compile Include="Constraints\IntRouteConstraint.cs" />
|
<Compile Include="Constraints\IntRouteConstraint.cs" />
|
||||||
<Compile Include="Constraints\RegexRouteConstraint.cs" />
|
<Compile Include="Constraints\RegexRouteConstraint.cs" />
|
||||||
|
<Compile Include="Constraints\RequiredRouteConstraint.cs" />
|
||||||
<Compile Include="DefaultInlineConstraintResolver.cs" />
|
<Compile Include="DefaultInlineConstraintResolver.cs" />
|
||||||
<Compile Include="IInlineConstraintResolver.cs" />
|
<Compile Include="IInlineConstraintResolver.cs" />
|
||||||
<Compile Include="INamedRouter.cs" />
|
<Compile Include="INamedRouter.cs" />
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -40,6 +40,7 @@
|
||||||
<Compile Include="Constraints\AlphaRouteConstraintTests.cs" />
|
<Compile Include="Constraints\AlphaRouteConstraintTests.cs" />
|
||||||
<Compile Include="Constraints\RegexConstraintTests.cs" />
|
<Compile Include="Constraints\RegexConstraintTests.cs" />
|
||||||
<Compile Include="Constraints\IntRouteConstraintsTests.cs" />
|
<Compile Include="Constraints\IntRouteConstraintsTests.cs" />
|
||||||
|
<Compile Include="Constraints\RequiredRouteConstraintTests.cs" />
|
||||||
<Compile Include="DefaultInlineConstraintResolverTest.cs" />
|
<Compile Include="DefaultInlineConstraintResolverTest.cs" />
|
||||||
<Compile Include="RouteCollectionTest.cs" />
|
<Compile Include="RouteCollectionTest.cs" />
|
||||||
<Compile Include="InlineRouteParameterParserTests.cs" />
|
<Compile Include="InlineRouteParameterParserTests.cs" />
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue