Issue #1736 - Razor view searches in case-sensitive filesystems.
This commit is contained in:
parent
823e9f1516
commit
54c1fed254
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor
|
||||
|
|
@ -49,7 +49,9 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
{
|
||||
var keyBuilder = new StringBuilder();
|
||||
var routeValues = context.ActionContext.RouteData.Values;
|
||||
var controller = routeValues.GetValueOrDefault<string>(RazorViewEngine.ControllerKey);
|
||||
var controller = RazorViewEngine.GetNormalizedRouteValue(
|
||||
context.ActionContext,
|
||||
RazorViewEngine.ControllerKey);
|
||||
|
||||
// format is "{viewName}:{isPartial}:{controllerName}:{areaName}:"
|
||||
keyBuilder.Append(context.ViewName)
|
||||
|
|
@ -58,7 +60,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
.Append(CacheKeySeparator)
|
||||
.Append(controller);
|
||||
|
||||
var area = routeValues.GetValueOrDefault<string>(RazorViewEngine.AreaKey);
|
||||
var area = RazorViewEngine.GetNormalizedRouteValue(context.ActionContext, RazorViewEngine.AreaKey);
|
||||
if (!string.IsNullOrEmpty(area))
|
||||
{
|
||||
keyBuilder.Append(CacheKeySeparator)
|
||||
|
|
|
|||
|
|
@ -1,26 +0,0 @@
|
|||
// 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 Microsoft.Framework.Internal;
|
||||
|
||||
namespace System.Collections.Generic
|
||||
{
|
||||
internal static class DictionaryExtensions
|
||||
{
|
||||
public static T GetValueOrDefault<T>([NotNull] this IDictionary<string, object> dictionary,
|
||||
[NotNull] string key)
|
||||
{
|
||||
object valueAsObject;
|
||||
if (dictionary.TryGetValue(key, out valueAsObject))
|
||||
{
|
||||
if (valueAsObject is T)
|
||||
{
|
||||
return (T)valueAsObject;
|
||||
}
|
||||
}
|
||||
|
||||
return default(T);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,8 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNet.Mvc.Razor.Internal;
|
||||
using Microsoft.AspNet.Mvc.Razor.OptionDescriptors;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using Microsoft.Framework.Internal;
|
||||
|
|
@ -133,6 +135,62 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
return GetRazorPageResult(context, pageName, isPartial: true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the case-normalized route value for the specified route <paramref name="key"/>.
|
||||
/// </summary>
|
||||
/// <param name="context">The <see cref="ActionContext"/>.</param>
|
||||
/// <param name="key">The route key to lookup.</param>
|
||||
/// <returns>The value corresponding to the key.</returns>
|
||||
/// <remarks>
|
||||
/// The casing of a route value in <see cref="ActionContext.RouteData"/> is determined by the client.
|
||||
/// This making constructing paths for view locations in a case sensitive file system unreliable. Using the
|
||||
/// <see cref="ActionDescriptor.RouteValueDefaults"/> for attribute routes and
|
||||
/// <see cref="ActionDescriptor.RouteConstraints"/> for traditional routes to get route values produces
|
||||
/// consistently cased results.
|
||||
/// </remarks>
|
||||
internal static string GetNormalizedRouteValue(ActionContext context, string key)
|
||||
{
|
||||
object routeValue;
|
||||
if (!context.RouteData.Values.TryGetValue(key, out routeValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var actionDescriptor = context.ActionDescriptor;
|
||||
string normalizedValue = null;
|
||||
if (actionDescriptor.AttributeRouteInfo != null)
|
||||
{
|
||||
object match;
|
||||
if (actionDescriptor.RouteValueDefaults.TryGetValue(key, out match))
|
||||
{
|
||||
normalizedValue = match?.ToString();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// For traditional routes, lookup the key in RouteConstraints if the key is RequireKey.
|
||||
var match = actionDescriptor.RouteConstraints.FirstOrDefault(
|
||||
constraint => string.Equals(constraint.RouteKey, key, StringComparison.OrdinalIgnoreCase));
|
||||
if (match != null && match.KeyHandling != RouteKeyHandling.CatchAll)
|
||||
{
|
||||
if (match.KeyHandling == RouteKeyHandling.DenyKey)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
normalizedValue = match.RouteValue;
|
||||
}
|
||||
}
|
||||
|
||||
var stringRouteValue = routeValue?.ToString();
|
||||
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return normalizedValue;
|
||||
}
|
||||
|
||||
return stringRouteValue;
|
||||
}
|
||||
|
||||
private RazorPageResult GetRazorPageResult(ActionContext context,
|
||||
string pageName,
|
||||
bool isPartial)
|
||||
|
|
@ -164,8 +222,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
bool isPartial)
|
||||
{
|
||||
// Initialize the dictionary for the typical case of having controller and action tokens.
|
||||
var routeValues = context.RouteData.Values;
|
||||
var areaName = routeValues.GetValueOrDefault<string>(AreaKey);
|
||||
var areaName = GetNormalizedRouteValue(context, AreaKey);
|
||||
|
||||
// Only use the area view location formats if we have an area token.
|
||||
var viewLocations = !string.IsNullOrEmpty(areaName) ? AreaViewLocationFormats :
|
||||
|
|
@ -204,7 +261,7 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
}
|
||||
|
||||
// 3. Use the expanded locations to look up a page.
|
||||
var controllerName = routeValues.GetValueOrDefault<string>(ControllerKey);
|
||||
var controllerName = GetNormalizedRouteValue(context, ControllerKey);
|
||||
var searchedLocations = new List<string>();
|
||||
foreach (var path in viewLocations)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
// 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.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using RazorEmbeddedViewsWebSite;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
// The EmbeddedFileSystem used by RazorEmbeddedViewsWebSite performs case sensitive lookups for files.
|
||||
// These tests verify that we correctly normalize route values when constructing view lookup paths.
|
||||
public class RazorFileSystemCaseSensitivityTest
|
||||
{
|
||||
private const string SiteName = nameof(RazorEmbeddedViewsWebSite);
|
||||
private readonly Action<IApplicationBuilder> _app = new Startup().Configure;
|
||||
private readonly Action<IServiceCollection> _configureServices = new Startup().ConfigureServices;
|
||||
|
||||
[Fact]
|
||||
public async Task RazorViewEngine_NormalizesActionName_WhenLookingUpViewPaths()
|
||||
{
|
||||
// Arrange
|
||||
var expectedMessage = "Hello test-user, this is /RazorEmbeddedViews_Home";
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetStringAsync("http://localhost/RazorEmbeddedViews_Home/index?User=test-user");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RazorViewEngine_NormalizesControllerRouteValue_WhenLookingUpViewPaths()
|
||||
{
|
||||
// Arrange
|
||||
var expectedMessage = "Hello test-user, this is /razorembeddedviews_home";
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetStringAsync("http://localhost/razorembeddedviews_home?User=test-user");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, response);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task RazorViewEngine_NormalizesAreaRouteValue_WhenLookupViewPaths()
|
||||
{
|
||||
// Arrange
|
||||
var expectedMessage = "Hello admin-user, this is /restricted/razorembeddedviews_admin/login";
|
||||
var server = TestHelper.CreateServer(_app, SiteName, _configureServices);
|
||||
var client = server.CreateClient();
|
||||
var target = "http://localhost/restricted/razorembeddedviews_admin/login?AdminUser=admin-user";
|
||||
|
||||
// Act
|
||||
var response = await client.GetStringAsync(target);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expectedMessage, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -126,6 +126,59 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
expanderContext,
|
||||
"test3:1:controller3:area3:culture:fr:theme:sleek"
|
||||
};
|
||||
|
||||
yield return new object[]
|
||||
{
|
||||
new ViewLocationExpanderContext(
|
||||
GetActionContextWithActionDescriptor(
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
{"controller", "MyController" },
|
||||
},
|
||||
new Dictionary<string, string>()
|
||||
{
|
||||
{"controller", "mycontroller" },
|
||||
},
|
||||
isAttributeRouted: true),
|
||||
"test",
|
||||
isPartial: false),
|
||||
"test:0:mycontroller"
|
||||
};
|
||||
|
||||
yield return new object[]
|
||||
{
|
||||
new ViewLocationExpanderContext(
|
||||
GetActionContextWithActionDescriptor(
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
{"controller", "MyController" },
|
||||
},
|
||||
new Dictionary<string, string>()
|
||||
{
|
||||
{"controller", "mycontroller" },
|
||||
},
|
||||
isAttributeRouted: true),
|
||||
"test",
|
||||
isPartial: false),
|
||||
"test:0:mycontroller"
|
||||
};
|
||||
|
||||
yield return new object[]
|
||||
{
|
||||
new ViewLocationExpanderContext(
|
||||
GetActionContextWithActionDescriptor(
|
||||
new Dictionary<string, object>()
|
||||
{
|
||||
{"controller", "mycontroller" },
|
||||
},
|
||||
new Dictionary<string, string>()
|
||||
{
|
||||
},
|
||||
isAttributeRouted: true),
|
||||
"test",
|
||||
isPartial: false),
|
||||
"test:0:mycontroller"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -150,7 +203,42 @@ namespace Microsoft.AspNet.Mvc.Razor
|
|||
routeData.Values["area"] = area;
|
||||
}
|
||||
|
||||
return new ActionContext(new DefaultHttpContext(), routeData, new ActionDescriptor());
|
||||
var actionDesciptor = new ActionDescriptor();
|
||||
actionDesciptor.RouteConstraints = new List<RouteDataActionConstraint>();
|
||||
return new ActionContext(new DefaultHttpContext(), routeData, actionDesciptor);
|
||||
}
|
||||
|
||||
private static ActionContext GetActionContextWithActionDescriptor(
|
||||
IDictionary<string, object> routeValues,
|
||||
IDictionary<string, string> routesInActionDescriptor,
|
||||
bool isAttributeRouted)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var routeData = new RouteData();
|
||||
foreach (var kvp in routeValues)
|
||||
{
|
||||
routeData.Values.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
var actionDescriptor = new ActionDescriptor();
|
||||
if (isAttributeRouted)
|
||||
{
|
||||
actionDescriptor.AttributeRouteInfo = new Routing.AttributeRouteInfo();
|
||||
foreach (var kvp in routesInActionDescriptor)
|
||||
{
|
||||
actionDescriptor.RouteValueDefaults.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actionDescriptor.RouteConstraints = new List<RouteDataActionConstraint>();
|
||||
foreach (var kvp in routesInActionDescriptor)
|
||||
{
|
||||
actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(kvp.Key, kvp.Value));
|
||||
}
|
||||
}
|
||||
|
||||
return new ActionContext(httpContext, routeData, actionDescriptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@ using Microsoft.AspNet.Routing;
|
|||
using Microsoft.AspNet.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
using Microsoft.AspNet.Mvc.Routing;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.Razor.Test
|
||||
{
|
||||
|
|
@ -594,7 +595,151 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
Assert.Equal(expected, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[Theory]
|
||||
// Looks in RouteValueDefaults
|
||||
[InlineData(true)]
|
||||
// Looks in RouteConstraints
|
||||
[InlineData(false)]
|
||||
public void FindPage_SelectsActionCaseInsensitively(bool isAttributeRouted)
|
||||
{
|
||||
// The ActionDescriptor contains "Foo" and the RouteData contains "foo"
|
||||
// which matches the case of the constructor thus searching in the appropriate location.
|
||||
// Arrange
|
||||
var routeValues = new Dictionary<string, object>
|
||||
{
|
||||
{ "controller", "foo" }
|
||||
};
|
||||
|
||||
var page = new Mock<IRazorPage>(MockBehavior.Strict).Object;
|
||||
var pageFactory = new Mock<IRazorPageFactory>();
|
||||
pageFactory.Setup(p => p.CreateInstance("/Views/Foo/details.cshtml"))
|
||||
.Returns(page)
|
||||
.Verifiable();
|
||||
|
||||
var viewEngine = CreateViewEngine(pageFactory.Object);
|
||||
var routesInActionDescriptor = new Dictionary<string, string>()
|
||||
{
|
||||
{ "controller", "Foo" }
|
||||
};
|
||||
|
||||
var context = GetActionContextWithActionDescriptor(routeValues, routesInActionDescriptor, isAttributeRouted);
|
||||
|
||||
// Act
|
||||
var result = viewEngine.FindPage(context, "details");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("details", result.Name);
|
||||
Assert.Same(page, result.Page);
|
||||
Assert.Null(result.SearchedLocations);
|
||||
pageFactory.Verify();
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Looks in RouteValueDefaults
|
||||
[InlineData(true)]
|
||||
// Looks in RouteConstraints
|
||||
[InlineData(false)]
|
||||
public void FindPage_LooksForPages_UsingActionDescriptor_Controller(bool isAttributeRouted)
|
||||
{
|
||||
// Arrange
|
||||
var expected = new[]
|
||||
{
|
||||
"/Views/bar/foo.cshtml",
|
||||
"/Views/Shared/foo.cshtml",
|
||||
};
|
||||
|
||||
var routeValues = new Dictionary<string, object>
|
||||
{
|
||||
{ "controller", "Bar" }
|
||||
};
|
||||
var routesInActionDescriptor = new Dictionary<string, string>()
|
||||
{
|
||||
{ "controller", "bar" }
|
||||
};
|
||||
var page = Mock.Of<IRazorPage>();
|
||||
|
||||
var viewEngine = CreateViewEngine();
|
||||
var context = GetActionContextWithActionDescriptor(routeValues, routesInActionDescriptor, isAttributeRouted);
|
||||
|
||||
// Act
|
||||
var result = viewEngine.FindPage(context, "foo");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", result.Name);
|
||||
Assert.Null(result.Page);
|
||||
Assert.Equal(expected, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
// Looks in RouteValueDefaults
|
||||
[InlineData(true)]
|
||||
// Looks in RouteConstraints
|
||||
[InlineData(false)]
|
||||
public void FindPage_LooksForPages_UsingActionDescriptor_Areas(bool isAttributeRouted)
|
||||
{
|
||||
// Arrange
|
||||
var expected = new[]
|
||||
{
|
||||
"/Areas/world/Views/bar/foo.cshtml",
|
||||
"/Areas/world/Views/Shared/foo.cshtml",
|
||||
"/Views/Shared/foo.cshtml"
|
||||
};
|
||||
|
||||
var routeValues = new Dictionary<string, object>
|
||||
{
|
||||
{ "controller", "Bar" },
|
||||
{ "area", "World" }
|
||||
};
|
||||
var routesInActionDescriptor = new Dictionary<string, string>()
|
||||
{
|
||||
{ "controller", "bar" },
|
||||
{ "area", "world" }
|
||||
};
|
||||
var page = Mock.Of<IRazorPage>();
|
||||
|
||||
var viewEngine = CreateViewEngine();
|
||||
var context = GetActionContextWithActionDescriptor(routeValues, routesInActionDescriptor, isAttributeRouted);
|
||||
|
||||
// Act
|
||||
var result = viewEngine.FindPage(context, "foo");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("foo", result.Name);
|
||||
Assert.Null(result.Page);
|
||||
Assert.Equal(expected, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void FindPage_LooksForPages_UsesRouteValuesAsFallback(bool isAttributeRouted)
|
||||
{
|
||||
// Arrange
|
||||
var expected = new[]
|
||||
{
|
||||
"/Views/foo/bar.cshtml",
|
||||
"/Views/Shared/bar.cshtml",
|
||||
};
|
||||
|
||||
var routeValues = new Dictionary<string, object>()
|
||||
{
|
||||
{ "controller", "foo" }
|
||||
};
|
||||
var page = Mock.Of<IRazorPage>();
|
||||
|
||||
var viewEngine = CreateViewEngine();
|
||||
var context = GetActionContextWithActionDescriptor(routeValues, new Dictionary<string, string>(), isAttributeRouted);
|
||||
|
||||
// Act
|
||||
var result = viewEngine.FindPage(context, "bar");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("bar", result.Name);
|
||||
Assert.Null(result.Page);
|
||||
Assert.Equal(expected, result.SearchedLocations);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AreaViewLocationFormats_ContainsExpectedLocations()
|
||||
{
|
||||
// Arrange
|
||||
|
|
@ -626,6 +771,252 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
Assert.Equal(viewLocations, viewEngine.ViewLocationFormats);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ReturnsValueFromRouteConstraints_IfKeyHandlingIsRequired()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
RouteConstraints = new[]
|
||||
{
|
||||
new RouteDataActionConstraint(key, "Route-Value")
|
||||
}
|
||||
};
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Route-Value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ReturnsRouteValue_IfValueDoesNotMatchRouteConstraint()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
RouteConstraints = new[]
|
||||
{
|
||||
new RouteDataActionConstraint(key, "different-value")
|
||||
}
|
||||
};
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("route-value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ReturnsNull_IfRouteConstraintKeyHandlingIsDeny()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
RouteConstraints = new[]
|
||||
{
|
||||
new RouteDataActionConstraint(key, routeValue: string.Empty)
|
||||
}
|
||||
};
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Null(result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ReturnsRouteDataValue_IfRouteConstraintKeyHandlingIsCatchAll()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
RouteConstraints = new[]
|
||||
{
|
||||
RouteDataActionConstraint.CreateCatchAll(key)
|
||||
}
|
||||
};
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("route-value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_UsesRouteValueDefaults_IfAttributeRouted()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
AttributeRouteInfo = new AttributeRouteInfo(),
|
||||
};
|
||||
actionDescriptor.RouteValueDefaults[key] = "Route-Value";
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("Route-Value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_UsesRouteValue_IfRouteValueDefaultsDoesNotMatchRouteValue()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
AttributeRouteInfo = new AttributeRouteInfo(),
|
||||
};
|
||||
actionDescriptor.RouteValueDefaults[key] = "different-value";
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("route-value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ConvertsRouteDefaultToStringValue_IfAttributeRouted()
|
||||
{
|
||||
using (new CultureReplacer())
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
AttributeRouteInfo = new AttributeRouteInfo(),
|
||||
};
|
||||
actionDescriptor.RouteValueDefaults[key] = 32;
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = 32;
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("32", result);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_UsesRouteDataValue_IfKeyDoesNotExistInRouteDefaultValues()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
AttributeRouteInfo = new AttributeRouteInfo(),
|
||||
};
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = "route-value";
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("route-value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ConvertsRouteValueToString()
|
||||
{
|
||||
using (new CultureReplacer())
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor
|
||||
{
|
||||
AttributeRouteInfo = new AttributeRouteInfo(),
|
||||
};
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = 43;
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("43", result);
|
||||
}
|
||||
}
|
||||
|
||||
private RazorViewEngine CreateViewEngine(IRazorPageFactory pageFactory = null,
|
||||
IRazorViewFactory viewFactory = null,
|
||||
IEnumerable<IViewLocationExpander> expanders = null,
|
||||
|
|
@ -673,7 +1064,42 @@ namespace Microsoft.AspNet.Mvc.Razor.Test
|
|||
routeData.Values.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
return new ActionContext(httpContext, routeData, new ActionDescriptor());
|
||||
var actionDesciptor = new ActionDescriptor();
|
||||
actionDesciptor.RouteConstraints = new List<RouteDataActionConstraint>();
|
||||
return new ActionContext(httpContext, routeData, actionDesciptor);
|
||||
}
|
||||
|
||||
private static ActionContext GetActionContextWithActionDescriptor(
|
||||
IDictionary<string, object> routeValues,
|
||||
IDictionary<string, string> routesInActionDescriptor,
|
||||
bool isAttributeRouted)
|
||||
{
|
||||
var httpContext = new DefaultHttpContext();
|
||||
var routeData = new RouteData();
|
||||
foreach (var kvp in routeValues)
|
||||
{
|
||||
routeData.Values.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
var actionDescriptor = new ActionDescriptor();
|
||||
if (isAttributeRouted)
|
||||
{
|
||||
actionDescriptor.AttributeRouteInfo = new AttributeRouteInfo();
|
||||
foreach (var kvp in routesInActionDescriptor)
|
||||
{
|
||||
actionDescriptor.RouteValueDefaults.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actionDescriptor.RouteConstraints = new List<RouteDataActionConstraint>();
|
||||
foreach (var kvp in routesInActionDescriptor)
|
||||
{
|
||||
actionDescriptor.RouteConstraints.Add(new RouteDataActionConstraint(kvp.Key, kvp.Value));
|
||||
}
|
||||
}
|
||||
|
||||
return new ActionContext(httpContext, routeData, actionDescriptor);
|
||||
}
|
||||
|
||||
private class OverloadedLocationViewEngine : RazorViewEngine
|
||||
|
|
|
|||
Loading…
Reference in New Issue