Changed to use OptionalRouteConstraint created by Routing to use for inline optional parameters in attribute routing. Also added tests for inline parameters.
This commit is contained in:
parent
00b61ec1e6
commit
ba8cf3ca46
|
|
@ -224,6 +224,11 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
{
|
||||
if (parameter.InlineConstraints != null)
|
||||
{
|
||||
if (parameter.IsOptional)
|
||||
{
|
||||
constraintBuilder.SetOptional(parameter.Name);
|
||||
}
|
||||
|
||||
foreach (var inlineConstraint in parameter.InlineConstraints)
|
||||
{
|
||||
constraintBuilder.AddResolvedConstraint(parameter.Name, inlineConstraint.Constraint);
|
||||
|
|
|
|||
|
|
@ -198,6 +198,53 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
Assert.Equal(expectedRouteGroup, context.RouteData.Values["test_route_group"]);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("template/{parameter:int}", "/template/5", true)]
|
||||
[InlineData("template/{parameter:int?}", "/template/5", true)]
|
||||
[InlineData("template/{parameter:int?}", "/template", true)]
|
||||
[InlineData("template/{parameter:int?}", "/template/qwer", false)]
|
||||
public async Task AttributeRoute_WithOptionalInlineConstraint(string template, string request, bool expectedResult)
|
||||
{
|
||||
// Arrange
|
||||
var expectedRouteGroup = string.Format("{0}&&{1}", 0, template);
|
||||
|
||||
// We need to force the creation of a closure in order to avoid an issue with Moq and Roslyn.
|
||||
var numberOfCalls = 0;
|
||||
Action<RouteContext> callBack = ctx => { ctx.IsHandled = true; numberOfCalls++; };
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(r => r.RouteAsync(It.IsAny<RouteContext>()))
|
||||
.Callback(callBack)
|
||||
.Returns(Task.FromResult(true))
|
||||
.Verifiable();
|
||||
|
||||
var firstRoute = CreateMatchingEntry(next.Object, template, order: 0);
|
||||
|
||||
// We setup the route entries in reverse order of precedence to ensure that when we
|
||||
// try to route the request, the route with a higher precedence gets tried first.
|
||||
var matchingRoutes = new[] { firstRoute };
|
||||
|
||||
var linkGenerationEntries = Enumerable.Empty<AttributeRouteLinkGenerationEntry>();
|
||||
|
||||
var route = new AttributeRoute(next.Object, matchingRoutes, linkGenerationEntries, NullLoggerFactory.Instance);
|
||||
|
||||
var context = CreateRouteContext(request);
|
||||
|
||||
// Act
|
||||
await route.RouteAsync(context);
|
||||
|
||||
// Assert
|
||||
if (expectedResult)
|
||||
{
|
||||
Assert.True(context.IsHandled);
|
||||
Assert.Equal(expectedRouteGroup, context.RouteData.Values["test_route_group"]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.False(context.IsHandled);
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("template/5", "template/{parameter:int}")]
|
||||
[InlineData("template/5", "template/{parameter}")]
|
||||
|
|
@ -246,6 +293,56 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
Assert.Equal(expectedGroup, selectedGroup);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("template/{parameter:int}", "template/5", 5)]
|
||||
[InlineData("template/{parameter:int?}", "template/5", 5)]
|
||||
[InlineData("template/{parameter:int?}", "template", null)]
|
||||
[InlineData("template/{parameter:int?}", null, "asdf")]
|
||||
[InlineData("template/{parameter:alpha?}", "template/asdf", "asdf")]
|
||||
[InlineData("template/{parameter:alpha?}", "template", null)]
|
||||
[InlineData("template/{parameter:int:range(1,20)?}", "template", null)]
|
||||
[InlineData("template/{parameter:int:range(1,20)?}", "template/5", 5)]
|
||||
[InlineData("template/{parameter:int:range(1,20)?}", null, 21)]
|
||||
public void AttributeRoute_GenerateLink_OptionalInlineParameter(string template, string expectedResult, object parameter)
|
||||
{
|
||||
// Arrange
|
||||
var expectedGroup = CreateRouteGroup(0, template);
|
||||
|
||||
string selectedGroup = null;
|
||||
|
||||
var next = new Mock<IRouter>();
|
||||
next.Setup(n => n.GetVirtualPath(It.IsAny<VirtualPathContext>())).Callback<VirtualPathContext>(ctx =>
|
||||
{
|
||||
selectedGroup = (string)ctx.ProvidedValues[AttributeRouting.RouteGroupKey];
|
||||
ctx.IsBound = true;
|
||||
})
|
||||
.Returns((string)null);
|
||||
|
||||
var matchingRoutes = Enumerable.Empty<AttributeRouteMatchingEntry>();
|
||||
|
||||
var entry = CreateGenerationEntry(template, requiredValues: null);
|
||||
|
||||
var linkGenerationEntries = new[] { entry };
|
||||
|
||||
var route = new AttributeRoute(next.Object, matchingRoutes, linkGenerationEntries, NullLoggerFactory.Instance);
|
||||
VirtualPathContext context;
|
||||
|
||||
if (parameter != null)
|
||||
{
|
||||
context = CreateVirtualPathContext(values: null, ambientValues: new { parameter = parameter });
|
||||
}
|
||||
else
|
||||
{
|
||||
context = CreateVirtualPathContext(values: null, ambientValues: null);
|
||||
}
|
||||
|
||||
// Act
|
||||
string result = route.GetVirtualPath(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedResult, result);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("template/5", "template/{parameter:int}")]
|
||||
[InlineData("template/5", "template/{parameter}")]
|
||||
|
|
@ -1295,6 +1392,11 @@ namespace Microsoft.AspNet.Mvc.Routing
|
|||
{
|
||||
if (parameter.InlineConstraints != null)
|
||||
{
|
||||
if (parameter.IsOptional)
|
||||
{
|
||||
constraintBuilder.SetOptional(parameter.Name);
|
||||
}
|
||||
|
||||
foreach (var constraint in parameter.InlineConstraints)
|
||||
{
|
||||
constraintBuilder.AddResolvedConstraint(parameter.Name, constraint.Constraint);
|
||||
|
|
|
|||
|
|
@ -2,11 +2,14 @@
|
|||
// 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.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using InlineConstraints;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Newtonsoft.Json;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
|
|
@ -40,12 +43,633 @@ namespace Microsoft.AspNet.Mvc.FunctionalTests
|
|||
var client = server.CreateClient();
|
||||
|
||||
// Act & Assert
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(() => client.GetAsync("http://localhost/area-withoutexists/Users"));
|
||||
var ex = await Assert.ThrowsAsync<InvalidOperationException>(
|
||||
() => client.GetAsync("http://localhost/area-withoutexists/Users")
|
||||
);
|
||||
|
||||
Assert.Equal("The view 'Index' was not found." +
|
||||
" The following locations were searched:\r\n/Areas/Users/Views/Home/Index.cshtml\r\n" +
|
||||
"/Areas/Users/Views/Shared/Index.cshtml\r\n/Views/Shared/Index.cshtml.",
|
||||
ex.Message);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductById_IntConstraintForOptionalId_IdPresent()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductById/5");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["id"], "5");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductById");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductById_IntConstraintForOptionalId_NoId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductById");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductById");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductById_IntConstraintForOptionalId_NotIntId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductById/asdf");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByName_AlphaContraintForMandatoryName_ValidName()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByName/asdf");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["name"], "asdf");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByName");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByName_AlphaContraintForMandatoryName_NonAlphaName()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByName/asd123");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByName_AlphaContraintForMandatoryName_NoName()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByName");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByManufacturingDate_DateTimeConstraintForMandatoryDateTime_ValidDateTime()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response =
|
||||
await client.GetAsync(@"http://localhost/products/GetProductByManufacturingDate/2014-10-11T13:45:30");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["dateTime"], new DateTime(2014, 10, 11, 13, 45, 30));
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByManufacturingDate");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByCategoryName_StringLengthConstraint_ForOptionalCategoryName_ValidCatName()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByCategoryName/Sports");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["name"], "Sports");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByCategoryName");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByCategoryName_StringLengthConstraint_ForOptionalCategoryName_InvalidCatName()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response =
|
||||
await client.GetAsync("http://localhost/products/GetProductByCategoryName/SportsSportsSportsSports");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByCategoryName_StringLength1To20Constraint_ForOptionalCategoryName_NoCatName()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByCategoryName");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByCategoryName");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByCategoryId_Int10To100Constraint_ForMandatoryCatId_ValidId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByCategoryId/40");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["catId"], "40");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByCategoryId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByCategoryId_Int10To100Constraint_ForMandatoryCatId_InvalidId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByCategoryId/5");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByCategoryId_Int10To100Constraint_ForMandatoryCatId_NotIntId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByCategoryId/asdf");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByPrice_FloatContraintForOptionalPrice_Valid()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByPrice/4023.23423");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["price"], "4023.23423");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByPrice");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByPrice_FloatContraintForOptionalPrice_NoPrice()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByPrice");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByPrice");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByManufacturerId_IntMin10Constraint_ForOptionalManufacturerId_Valid()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByManufacturerId/57");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["manId"], "57");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByManufacturerId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetProductByManufacturerId_IntMin10Cinstraint_ForOptionalManufacturerId_NoId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetProductByManufacturerId");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetProductByManufacturerId");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetUserByName_RegExConstraint_ForMandatoryName_Valid()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetUserByName/abc");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Products");
|
||||
Assert.Equal(result["action"], "GetUserByName");
|
||||
Assert.Equal(result["name"], "abc");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetUserByName_RegExConstraint_ForMandatoryName_InValid()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/products/GetUserByName/abcd");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreById_GuidConstraintForOptionalId_Valid()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response =
|
||||
await client.GetAsync("http://localhost/Store/GetStoreById/691cf17a-791b-4af8-99fd-e739e168170f");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["id"], "691cf17a-791b-4af8-99fd-e739e168170f");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Store");
|
||||
Assert.Equal(result["action"], "GetStoreById");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreById_GuidConstraintForOptionalId_NoId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Store/GetStoreById");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Store");
|
||||
Assert.Equal(result["action"], "GetStoreById");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreById_GuidConstraintForOptionalId_NotGuidId()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Store/GetStoreById/691cf17a-791b");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreByLocation_StringLengthConstraint_AlphaConstraint_ForMandatoryLocation_Valid()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Store/GetStoreByLocation/Bellevue");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
var result = await GetResponseValues(response);
|
||||
Assert.Equal(result["location"], "Bellevue");
|
||||
Assert.Equal(result["controller"], "InlineConstraints_Store");
|
||||
Assert.Equal(result["action"], "GetStoreByLocation");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreByLocation_StringLengthConstraint_AlphaConstraint_ForMandatoryLocation_MoreLength()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Store/GetStoreByLocation/BellevueRedmond");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreByLocation_StringLengthConstraint_AlphaConstraint_ForMandatoryLocation_LessLength()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Store/GetStoreByLocation/Be");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task GetStoreByLocation_StringLengthConstraint_AlphaConstraint_ForMandatoryLocation_NoAlpha()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Store/GetStoreByLocation/Bell124");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
|
||||
}
|
||||
|
||||
public static IEnumerable<object[]> QueryParameters
|
||||
{
|
||||
// The first four parameters are controller name, action name, parameters in the query and their values.
|
||||
// These are used to generate a link, the last parameter is expected generated link
|
||||
get
|
||||
{
|
||||
// Attribute Route, id:int? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductById",
|
||||
"id",
|
||||
"5",
|
||||
"/products/GetProductById/5"
|
||||
};
|
||||
|
||||
// Attribute Route, id:int? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductById",
|
||||
"id",
|
||||
"sdsd", ""
|
||||
};
|
||||
|
||||
// Attribute Route, name:alpha constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByName",
|
||||
"name",
|
||||
"zxcv",
|
||||
"/products/GetProductByName/zxcv"
|
||||
};
|
||||
|
||||
// Attribute Route, name:length(1,20)? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByCategoryName",
|
||||
"name",
|
||||
"sports",
|
||||
"/products/GetProductByCategoryName/sports"
|
||||
};
|
||||
|
||||
// Attribute Route, name:length(1,20)? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByCategoryName",
|
||||
null,
|
||||
null,
|
||||
"/products/GetProductByCategoryName"
|
||||
};
|
||||
|
||||
// Attribute Route, catId:int:range(10, 100) constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByCategoryId",
|
||||
"catId",
|
||||
"50",
|
||||
"/products/GetProductByCategoryId/50"
|
||||
};
|
||||
|
||||
// Attribute Route, catId:int:range(10, 100) constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByCategoryId",
|
||||
"catId",
|
||||
"500",
|
||||
""
|
||||
};
|
||||
|
||||
// Attribute Route, name:length(1,20)? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByPrice",
|
||||
"price",
|
||||
"123.45",
|
||||
"/products/GetProductByPrice/123.45"
|
||||
};
|
||||
|
||||
// Attribute Route, price:float? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByManufacturerId",
|
||||
"manId",
|
||||
"15",
|
||||
"/products/GetProductByManufacturerId/15"
|
||||
};
|
||||
|
||||
// Attribute Route, manId:int:min(10)? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByManufacturerId",
|
||||
"manId",
|
||||
"qwer",
|
||||
""
|
||||
};
|
||||
|
||||
// Attribute Route, manId:int:min(10)? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByManufacturerId",
|
||||
"manId",
|
||||
"1",
|
||||
""
|
||||
};
|
||||
|
||||
// Attribute Route, manId:int:min(10)? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByManufacturerId",
|
||||
"manId",
|
||||
"1",
|
||||
""
|
||||
};
|
||||
|
||||
// Attribute Route, dateTime:datetime constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Products",
|
||||
"GetProductByManufacturingDate",
|
||||
"dateTime",
|
||||
"2014-10-11T13:45:30",
|
||||
"/products/GetProductByManufacturingDate/2014-10-11T13%3a45%3a30"
|
||||
};
|
||||
|
||||
// Conventional Route, id:guid? constraint
|
||||
yield return new object[]
|
||||
{
|
||||
"InlineConstraints_Store",
|
||||
"GetStoreById",
|
||||
"id",
|
||||
"691cf17a-791b-4af8-99fd-e739e168170f",
|
||||
"/store/GetStoreById/691cf17a-791b-4af8-99fd-e739e168170f"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[MemberData(nameof(QueryParameters))]
|
||||
public async Task GetGeneratedLink(
|
||||
string controller,
|
||||
string action,
|
||||
string parameterName,
|
||||
string parameterValue,
|
||||
string expectedLink)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_provider, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
string url;
|
||||
|
||||
if (parameterName == null)
|
||||
{
|
||||
url = string.Format(
|
||||
"{0}newController={1}&newAction={2}",
|
||||
"http://localhost/products/GetGeneratedLink?",
|
||||
controller,
|
||||
action);
|
||||
}
|
||||
else
|
||||
{
|
||||
url = string.Format(
|
||||
"{0}newController={1}&newAction={2}&{3}={4}",
|
||||
"http://localhost/products/GetGeneratedLink?",
|
||||
controller,
|
||||
action,
|
||||
parameterName,
|
||||
parameterValue);
|
||||
}
|
||||
|
||||
var response = await client.GetAsync(url);
|
||||
|
||||
// Assert
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
Assert.Equal(expectedLink, body);
|
||||
}
|
||||
|
||||
private async Task<IDictionary<string, object>> GetResponseValues(HttpResponseMessage response)
|
||||
{
|
||||
var body = await response.Content.ReadAsStringAsync();
|
||||
return JsonConvert.DeserializeObject<IDictionary<string, object>>(body);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
// 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 Microsoft.AspNet.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace InlineConstraintsWebSite.Controllers
|
||||
{
|
||||
[Route("products/[action]")]
|
||||
public class InlineConstraints_ProductsController : Controller
|
||||
{
|
||||
public IDictionary<string, object> Index()
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{id:int?}")]
|
||||
public IDictionary<string, object> GetProductById(int id)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{name:alpha}")]
|
||||
public IDictionary<string, object> GetProductByName(string name)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{dateTime:datetime}")]
|
||||
public IDictionary<string, object> GetProductByManufacturingDate(DateTime dateTime)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{name:length(1,20)?}")]
|
||||
public IDictionary<string, object> GetProductByCategoryName(string name)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{catId:int:range(10, 100)}")]
|
||||
public IDictionary<string, object> GetProductByCategoryId(int catId)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{price:float?}")]
|
||||
public IDictionary<string, object> GetProductByPrice(float price)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet("{manId:int:min(10)?}")]
|
||||
public IDictionary<string, object> GetProductByManufacturerId(int manId)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
[HttpGet(@"{name:regex(^abc$)}")]
|
||||
public IDictionary<string, object> GetUserByName(string name)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
public string GetGeneratedLink()
|
||||
{
|
||||
var query = ActionContext.HttpContext.Request.Query;
|
||||
var values = query
|
||||
.Where(kvp => kvp.Key != "newAction" && kvp.Key != "newController")
|
||||
.ToDictionary(kvp => kvp.Key, kvp => (object)kvp.Value[0]);
|
||||
|
||||
return Url.Action(query["newAction"], query["newController"], values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
// 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 Microsoft.AspNet.Mvc;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace InlineConstraintsWebSite.Controllers
|
||||
{
|
||||
public class InlineConstraints_StoreController : Controller
|
||||
{
|
||||
public IDictionary<string, object> GetStoreById(Guid id)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
|
||||
public IDictionary<string, object> GetStoreByLocation(string location)
|
||||
{
|
||||
return ActionContext.RouteData.Values;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
<DevelopmentServerPort>45283</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.AspNet.Routing.Constraints;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace InlineConstraints
|
||||
|
|
@ -23,6 +24,15 @@ namespace InlineConstraints
|
|||
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("StoreId",
|
||||
"store/{action}/{id:guid?}",
|
||||
defaults: new { controller = "InlineConstraints_Store" });
|
||||
|
||||
routes.MapRoute("StoreLocation",
|
||||
"store/{action}/{location:minlength(3):maxlength(10)}",
|
||||
defaults: new { controller = "InlineConstraints_Store" },
|
||||
constraints: new { location = new AlphaRouteConstraint() });
|
||||
|
||||
// Used by tests for the 'exists' constraint.
|
||||
routes.MapRoute("areaExists-area", "area-exists/{area:exists}/{controller=Home}/{action=Index}");
|
||||
routes.MapRoute("areaExists", "area-exists/{controller=Home}/{action=Index}");
|
||||
|
|
|
|||
Loading…
Reference in New Issue