Convert `RouteValueDictionary` values to `string` using `CultureInfo.InvariantCulture` (#8674)
* Convert `RouteValueDictionary` values to `string` using `CultureInfo.InvariantCulture` - #8578 - user may override this choice in one case: - register a custom `IValueProviderFactory` to pass another `CultureInfo` into the `RouteValueProvider` - values are used as programmatic tokens outside `RouteValueProvider` nits: - take VS suggestions in changed classes - take VS suggestions in files I had open :)
This commit is contained in:
parent
734b919b02
commit
c74a945dda
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using BenchmarkDotNet.Attributes;
|
||||
|
|
@ -123,8 +124,8 @@ namespace Microsoft.AspNetCore.Mvc.Performance
|
|||
var isMatch = true;
|
||||
foreach (var kvp in action.RouteValues)
|
||||
{
|
||||
var routeValue = Convert.ToString(routeValues[kvp.Key]) ?? string.Empty;
|
||||
|
||||
var routeValue = Convert.ToString(routeValues[kvp.Key], CultureInfo.InvariantCulture) ??
|
||||
string.Empty;
|
||||
if (string.IsNullOrEmpty(kvp.Value) && string.IsNullOrEmpty(routeValue))
|
||||
{
|
||||
// Match
|
||||
|
|
@ -156,7 +157,7 @@ namespace Microsoft.AspNetCore.Mvc.Performance
|
|||
var routeValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var kvp in new RouteValueDictionary(obj))
|
||||
{
|
||||
routeValues.Add(kvp.Key, Convert.ToString(kvp.Value) ?? string.Empty);
|
||||
routeValues.Add(kvp.Key, Convert.ToString(kvp.Value, CultureInfo.InvariantCulture) ?? string.Empty);
|
||||
}
|
||||
|
||||
return new ActionDescriptor()
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
|
@ -59,7 +60,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
if (context.RouteData.Values.TryGetValue("format", out var obj))
|
||||
{
|
||||
// null and string.Empty are equivalent for route values.
|
||||
var routeValue = obj?.ToString();
|
||||
var routeValue = Convert.ToString(obj, CultureInfo.InvariantCulture);
|
||||
return string.IsNullOrEmpty(routeValue) ? null : routeValue;
|
||||
}
|
||||
|
||||
|
|
@ -166,8 +167,7 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
return;
|
||||
}
|
||||
|
||||
var objectResult = context.Result as ObjectResult;
|
||||
if (objectResult == null)
|
||||
if (!(context.Result is ObjectResult objectResult))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
|
|
@ -81,11 +82,10 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
var values = new string[keys.Length];
|
||||
for (var i = 0; i < keys.Length; i++)
|
||||
{
|
||||
context.RouteData.Values.TryGetValue(keys[i], out object value);
|
||||
|
||||
context.RouteData.Values.TryGetValue(keys[i], out var value);
|
||||
if (value != null)
|
||||
{
|
||||
values[i] = value as string ?? Convert.ToString(value);
|
||||
values[i] = value as string ?? Convert.ToString(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -220,9 +220,11 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
var actionsWithConstraint = new List<ActionSelectorCandidate>();
|
||||
var actionsWithoutConstraint = new List<ActionSelectorCandidate>();
|
||||
|
||||
var constraintContext = new ActionConstraintContext();
|
||||
constraintContext.Candidates = candidates;
|
||||
constraintContext.RouteContext = context;
|
||||
var constraintContext = new ActionConstraintContext
|
||||
{
|
||||
Candidates = candidates,
|
||||
RouteContext = context
|
||||
};
|
||||
|
||||
// Perf: Avoid allocations
|
||||
for (var i = 0; i < candidates.Count; i++)
|
||||
|
|
@ -294,7 +296,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
// canonical entries. When you don't hit a case-sensitive match it will try the case-insensitive dictionary
|
||||
// so you still get correct behaviors.
|
||||
//
|
||||
// The difference here is because while MVC is case-insensitive, doing a case-sensitive comparison is much
|
||||
// The difference here is because while MVC is case-insensitive, doing a case-sensitive comparison is much
|
||||
// faster. We also expect that most of the URLs we process are canonically-cased because they were generated
|
||||
// by Url.Action or another routing api.
|
||||
//
|
||||
|
|
@ -316,7 +318,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
OrdinalEntries = new Dictionary<string[], List<ActionDescriptor>>(StringArrayComparer.Ordinal);
|
||||
OrdinalIgnoreCaseEntries = new Dictionary<string[], List<ActionDescriptor>>(StringArrayComparer.OrdinalIgnoreCase);
|
||||
|
||||
// We need to first identify of the keys that action selection will look at (in route data).
|
||||
// We need to first identify of the keys that action selection will look at (in route data).
|
||||
// We want to only consider conventionally routed actions here.
|
||||
var routeKeys = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
for (var i = 0; i < actions.Items.Count; i++)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.Internal
|
||||
{
|
||||
|
|
@ -45,7 +46,7 @@ namespace Microsoft.AspNetCore.Mvc.Internal
|
|||
normalizedValue = value;
|
||||
}
|
||||
|
||||
var stringRouteValue = routeValue?.ToString();
|
||||
var stringRouteValue = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
|
||||
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return normalizedValue;
|
||||
|
|
|
|||
|
|
@ -88,10 +88,9 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
throw new ArgumentNullException(nameof(key));
|
||||
}
|
||||
|
||||
object value;
|
||||
if (_values.TryGetValue(key, out value))
|
||||
if (_values.TryGetValue(key, out var value))
|
||||
{
|
||||
var stringValue = value as string ?? value?.ToString() ?? string.Empty;
|
||||
var stringValue = value as string ?? Convert.ToString(value, Culture) ?? string.Empty;
|
||||
return new ValueProviderResult(stringValue, Culture);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
|
|
@ -51,10 +52,9 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
throw new ArgumentNullException(nameof(values));
|
||||
}
|
||||
|
||||
object obj;
|
||||
if (values.TryGetValue(routeKey, out obj))
|
||||
if (values.TryGetValue(routeKey, out var obj))
|
||||
{
|
||||
var value = obj as string;
|
||||
var value = Convert.ToString(obj, CultureInfo.InvariantCulture);
|
||||
if (value != null)
|
||||
{
|
||||
var actionDescriptors = GetAndValidateActionDescriptors(httpContext);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// 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 Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using System;
|
||||
|
||||
namespace Microsoft.AspNetCore.Routing
|
||||
{
|
||||
|
|
@ -104,7 +104,7 @@ namespace Microsoft.AspNetCore.Routing
|
|||
}
|
||||
|
||||
var address = CreateAddress(httpContext: null, page, handler, values);
|
||||
return generator.GetPathByAddress<RouteValuesAddress>(address, address.ExplicitValues, pathBase, fragment, options);
|
||||
return generator.GetPathByAddress(address, address.ExplicitValues, pathBase, fragment, options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -230,4 +230,4 @@ namespace Microsoft.AspNetCore.Routing
|
|||
return httpContext?.Features.Get<IRouteValuesFeature>()?.RouteValues;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Core;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
|
@ -163,8 +163,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
// Perf: In most of the common cases, GenerateUrl is called with a null protocol, host and fragment.
|
||||
// In such cases, we might not need to build any URL as the url generated is mostly same as the virtual path available in pathData.
|
||||
// For such common cases, this FastGenerateUrl method saves a string allocation per GenerateUrl call.
|
||||
string url;
|
||||
if (TryFastGenerateUrl(protocol, host, virtualPath, fragment, out url))
|
||||
if (TryFastGenerateUrl(protocol, host, virtualPath, fragment, out var url))
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
|
@ -227,8 +226,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
// Perf: In most of the common cases, GenerateUrl is called with a null protocol, host and fragment.
|
||||
// In such cases, we might not need to build any URL as the url generated is mostly same as the virtual path available in pathData.
|
||||
// For such common cases, this FastGenerateUrl method saves a string allocation per GenerateUrl call.
|
||||
string url;
|
||||
if (TryFastGenerateUrl(protocol, host, path, fragment: null, out url))
|
||||
if (TryFastGenerateUrl(protocol, host, path, fragment: null, out var url))
|
||||
{
|
||||
return url;
|
||||
}
|
||||
|
|
@ -351,7 +349,7 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
}
|
||||
else if (ambientValues != null)
|
||||
{
|
||||
currentPagePath = ambientValues["page"]?.ToString();
|
||||
currentPagePath = Convert.ToString(ambientValues["page"], CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
||||
|
|
@ -96,7 +95,7 @@ namespace Microsoft.AspNetCore.Mvc.ApplicationModels
|
|||
public IList<SelectorModel> Selectors { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a collection of route values that must be present in the <see cref="RouteData.Values"/>
|
||||
/// Gets a collection of route values that must be present in the <see cref="RouteData.Values"/>
|
||||
/// for the corresponding page to be selected.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
||||
{
|
||||
|
|
@ -57,8 +57,10 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
|
||||
if (ambiguousMatches == null)
|
||||
{
|
||||
ambiguousMatches = new List<HandlerMethodDescriptor>();
|
||||
ambiguousMatches.Add(bestMatch);
|
||||
ambiguousMatches = new List<HandlerMethodDescriptor>
|
||||
{
|
||||
bestMatch
|
||||
};
|
||||
}
|
||||
|
||||
ambiguousMatches.Add(handler);
|
||||
|
|
@ -165,13 +167,13 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
|
||||
private static string GetHandlerName(PageContext context)
|
||||
{
|
||||
var handlerName = Convert.ToString(context.RouteData.Values[Handler]);
|
||||
var handlerName = Convert.ToString(context.RouteData.Values[Handler], CultureInfo.InvariantCulture);
|
||||
if (!string.IsNullOrEmpty(handlerName))
|
||||
{
|
||||
return handlerName;
|
||||
}
|
||||
|
||||
if (context.HttpContext.Request.Query.TryGetValue(Handler, out StringValues queryValues))
|
||||
if (context.HttpContext.Request.Query.TryGetValue(Handler, out var queryValues))
|
||||
{
|
||||
return queryValues[0];
|
||||
}
|
||||
|
|
@ -192,4 +194,4 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure
|
|||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
if (!AttributeRouteModel.IsOverridePattern(routeTemplate) &&
|
||||
string.Equals(IndexFileName, fileName, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// For pages without an override route, and ending in /Index.cshtml, we want to allow
|
||||
// For pages without an override route, and ending in /Index.cshtml, we want to allow
|
||||
// incoming routing, but force outgoing routes to match to the path sans /Index.
|
||||
selectorModel.AttributeRouteModel.SuppressLinkGeneration = true;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using System.Globalization;
|
|||
using System.Text;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.Razor.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.TagHelpers.Internal;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Extensions.Internal;
|
||||
|
|
@ -25,7 +24,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
|
|||
private static readonly Func<IRequestCookieCollection, string, string> CookieAccessor = (c, key) => c[key];
|
||||
private static readonly Func<IHeaderDictionary, string, string> HeaderAccessor = (c, key) => c[key];
|
||||
private static readonly Func<IQueryCollection, string, string> QueryAccessor = (c, key) => c[key];
|
||||
private static readonly Func<RouteValueDictionary, string, string> RouteValueAccessor = (c, key) => c[key]?.ToString();
|
||||
private static readonly Func<RouteValueDictionary, string, string> RouteValueAccessor = (c, key) =>
|
||||
Convert.ToString(c[key], CultureInfo.InvariantCulture);
|
||||
|
||||
private const string CacheKeyTokenSeparator = "||";
|
||||
private const string VaryByName = "VaryBy";
|
||||
|
|
@ -91,7 +91,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers.Cache
|
|||
_cookies = ExtractCollection(tagHelper.VaryByCookie, request.Cookies, CookieAccessor);
|
||||
_headers = ExtractCollection(tagHelper.VaryByHeader, request.Headers, HeaderAccessor);
|
||||
_queries = ExtractCollection(tagHelper.VaryByQuery, request.Query, QueryAccessor);
|
||||
_routeValues = ExtractCollection(tagHelper.VaryByRoute, tagHelper.ViewContext.RouteData.Values, RouteValueAccessor);
|
||||
_routeValues = ExtractCollection(
|
||||
tagHelper.VaryByRoute,
|
||||
tagHelper.ViewContext.RouteData.Values,
|
||||
RouteValueAccessor);
|
||||
_varyByUser = tagHelper.VaryByUser;
|
||||
_varyByCulture = tagHelper.VaryByCulture;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.Encodings.Web;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
|
@ -441,7 +442,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
else if (stringValue == null)
|
||||
{
|
||||
stringValue = attributeValue.ToString();
|
||||
stringValue = Convert.ToString(attributeValue, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
var hasRelStylesheet = string.Equals("stylesheet", stringValue, StringComparison.Ordinal);
|
||||
|
|
@ -570,4 +571,4 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
Fallback = 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
|
|
@ -199,22 +200,20 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
throw new ArgumentNullException(nameof(context));
|
||||
}
|
||||
|
||||
object routeValue;
|
||||
if (!context.RouteData.Values.TryGetValue(ActionNameKey, out routeValue))
|
||||
if (!context.RouteData.Values.TryGetValue(ActionNameKey, out var routeValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var actionDescriptor = context.ActionDescriptor;
|
||||
string normalizedValue = null;
|
||||
string value;
|
||||
if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out value) &&
|
||||
if (actionDescriptor.RouteValues.TryGetValue(ActionNameKey, out var value) &&
|
||||
!string.IsNullOrEmpty(value))
|
||||
{
|
||||
normalizedValue = value;
|
||||
}
|
||||
|
||||
var stringRouteValue = routeValue?.ToString();
|
||||
var stringRouteValue = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
|
||||
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return normalizedValue;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
|
|
@ -115,10 +116,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
"Microsoft.AspNetCore.Mvc.ViewFound",
|
||||
new
|
||||
{
|
||||
actionContext = actionContext,
|
||||
actionContext,
|
||||
isMainPage = true,
|
||||
result = viewResult,
|
||||
viewName = viewName,
|
||||
viewName,
|
||||
view = result.View,
|
||||
});
|
||||
}
|
||||
|
|
@ -133,10 +134,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
"Microsoft.AspNetCore.Mvc.ViewNotFound",
|
||||
new
|
||||
{
|
||||
actionContext = actionContext,
|
||||
actionContext,
|
||||
isMainPage = true,
|
||||
result = viewResult,
|
||||
viewName = viewName,
|
||||
viewName,
|
||||
searchedLocations = result.SearchedLocations
|
||||
});
|
||||
}
|
||||
|
|
@ -199,7 +200,7 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
normalizedValue = value;
|
||||
}
|
||||
|
||||
var stringRouteValue = routeValue?.ToString();
|
||||
var stringRouteValue = Convert.ToString(routeValue, CultureInfo.InvariantCulture);
|
||||
if (string.Equals(normalizedValue, stringRouteValue, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return normalizedValue;
|
||||
|
|
|
|||
|
|
@ -97,8 +97,7 @@ namespace Microsoft.AspNetCore.Mvc.WebApiCompatShim
|
|||
}
|
||||
|
||||
var parameters = new List<OverloadedParameter>();
|
||||
object optionalParametersObject;
|
||||
candidate.Action.Properties.TryGetValue("OptionalParameters", out optionalParametersObject);
|
||||
candidate.Action.Properties.TryGetValue("OptionalParameters", out var optionalParametersObject);
|
||||
var optionalParameters = (HashSet<string>)optionalParametersObject;
|
||||
foreach (var parameter in candidate.Action.Parameters)
|
||||
{
|
||||
|
|
@ -191,4 +190,4 @@ namespace Microsoft.AspNetCore.Mvc.WebApiCompatShim
|
|||
public string Prefix { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
|
@ -8,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.Abstractions;
|
|||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
|
@ -28,13 +30,10 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("json", FormatSource.RouteData, "application/json")]
|
||||
[InlineData("json", FormatSource.QueryData, "application/json")]
|
||||
[InlineData("json", FormatSource.RouteAndQueryData, "application/json")]
|
||||
public void FormatFilter_ContextContainsFormat_DefaultFormat(
|
||||
string format,
|
||||
FormatSource place,
|
||||
string contentType)
|
||||
[InlineData("json", FormatSource.RouteData)]
|
||||
[InlineData("json", FormatSource.QueryData)]
|
||||
[InlineData("json", FormatSource.RouteAndQueryData)]
|
||||
public void FormatFilter_ContextContainsFormat_DefaultFormat(string format, FormatSource place)
|
||||
{
|
||||
// Arrange
|
||||
var mediaType = new StringSegment("application/json");
|
||||
|
|
@ -305,6 +304,25 @@ namespace Microsoft.AspNetCore.Mvc.Formatters
|
|||
Assert.Equal(expected, filter.GetFormat(context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void FormatFilter_GetFormat_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var mockObjects = new MockObjects();
|
||||
var context = mockObjects.CreateResultExecutingContext();
|
||||
context.RouteData.Values["format"] = new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7));
|
||||
var expected = "10/31/2018 07:37:38 -07:00";
|
||||
var filterAttribute = new FormatFilterAttribute();
|
||||
var filter = new FormatFilter(mockObjects.OptionsManager, NullLoggerFactory.Instance);
|
||||
|
||||
// Act
|
||||
var format = filter.GetFormat(context);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, filter.GetFormat(context));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FormatFilter_ExplicitContentType_SetOnObjectResult_TakesPrecedence()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ using Microsoft.AspNetCore.Mvc.Internal;
|
|||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
|
|
@ -64,6 +65,49 @@ namespace Microsoft.AspNetCore.Mvc.Infrastructure
|
|||
Assert.Collection(candidates, (a) => Assert.Same(actions[0], a));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void SelectCandidates_SingleMatch_UsesInvariantCulture()
|
||||
{
|
||||
var actions = new ActionDescriptor[]
|
||||
{
|
||||
new ActionDescriptor()
|
||||
{
|
||||
DisplayName = "A1",
|
||||
RouteValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "controller", "Home" },
|
||||
{ "action", "Index" },
|
||||
{ "date", "10/31/2018 07:37:38 -07:00" },
|
||||
},
|
||||
},
|
||||
new ActionDescriptor()
|
||||
{
|
||||
DisplayName = "A2",
|
||||
RouteValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ "controller", "Home" },
|
||||
{ "action", "About" }
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
var selector = CreateSelector(actions);
|
||||
|
||||
var routeContext = CreateRouteContext("GET");
|
||||
routeContext.RouteData.Values.Add("controller", "Home");
|
||||
routeContext.RouteData.Values.Add("action", "Index");
|
||||
routeContext.RouteData.Values.Add(
|
||||
"date",
|
||||
new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7)));
|
||||
|
||||
// Act
|
||||
var candidates = selector.SelectCandidates(routeContext);
|
||||
|
||||
// Assert
|
||||
Assert.Collection(candidates, (a) => Assert.Same(actions[0], a));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SelectCandidates_MultipleMatches()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -829,7 +829,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
private class TestableXmlSerializerInputFormatter : XmlSerializerInputFormatter
|
||||
{
|
||||
private bool _throwNonInputFormatterException;
|
||||
private readonly bool _throwNonInputFormatterException;
|
||||
|
||||
public TestableXmlSerializerInputFormatter(bool throwNonInputFormatterException)
|
||||
: base(new MvcOptions())
|
||||
|
|
@ -851,7 +851,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
private class TestableXmlDataContractSerializerInputFormatter : XmlDataContractSerializerInputFormatter
|
||||
{
|
||||
private bool _throwNonInputFormatterException;
|
||||
private readonly bool _throwNonInputFormatterException;
|
||||
|
||||
public TestableXmlDataContractSerializerInputFormatter(bool throwNonInputFormatterException)
|
||||
: base(new MvcOptions())
|
||||
|
|
@ -899,7 +899,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
private class DerivedXmlSerializerInputFormatter : XmlSerializerInputFormatter
|
||||
{
|
||||
private bool _throwNonInputFormatterException;
|
||||
private readonly bool _throwNonInputFormatterException;
|
||||
|
||||
public DerivedXmlSerializerInputFormatter(bool throwNonInputFormatterException)
|
||||
: base(new MvcOptions())
|
||||
|
|
@ -921,7 +921,7 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
|
||||
private class DerivedXmlDataContractSerializerInputFormatter : XmlDataContractSerializerInputFormatter
|
||||
{
|
||||
private bool _throwNonInputFormatterException;
|
||||
private readonly bool _throwNonInputFormatterException;
|
||||
|
||||
public DerivedXmlDataContractSerializerInputFormatter(bool throwNonInputFormatterException)
|
||||
: base(new MvcOptions())
|
||||
|
|
@ -952,4 +952,4 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding.Binders
|
|||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
||||
|
|
@ -45,6 +46,44 @@ namespace Microsoft.AspNetCore.Mvc.ModelBinding
|
|||
Assert.Equal("test-value", (string)result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void GetValueProvider_ReturnsValue_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var values = new RouteValueDictionary(new Dictionary<string, object>
|
||||
{
|
||||
{ "test-key", new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7)) },
|
||||
});
|
||||
var provider = new RouteValueProvider(BindingSource.Query, values);
|
||||
|
||||
// Act
|
||||
var result = provider.GetValue("test-key");
|
||||
|
||||
// Assert
|
||||
Assert.Equal("10/31/2018 07:37:38 -07:00", (string)result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetValueProvider_ReturnsValue_UsesSpecifiedCulture()
|
||||
{
|
||||
// Arrange
|
||||
var values = new RouteValueDictionary(new Dictionary<string, object>
|
||||
{
|
||||
{ "test-key", new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7)) },
|
||||
});
|
||||
var provider = new RouteValueProvider(BindingSource.Query, values, new CultureInfo("de-CH"));
|
||||
|
||||
// de-CH culture is slightly different on Windows versus other platforms.
|
||||
var expected = TestPlatformHelper.IsWindows ? "31.10.2018 07:37:38 -07:00" : "31.10.18 07:37:38 -07:00";
|
||||
|
||||
// Act
|
||||
var result = provider.GetValue("test-key");
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, (string)result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ContainsPrefix_ReturnsNullValue_IfKeyIsPresent()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
|||
using Microsoft.AspNetCore.Mvc.Infrastructure;
|
||||
using Microsoft.AspNetCore.Mvc.Internal;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
|
@ -233,6 +234,35 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
|||
Assert.True(match);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(RouteDirection.IncomingRequest)]
|
||||
[InlineData(RouteDirection.UrlGeneration)]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void ServiceInjected_RouteKey_Exists_UsesInvariantCulture(RouteDirection direction)
|
||||
{
|
||||
// Arrange
|
||||
var actionDescriptor = CreateActionDescriptor("testArea", "testController", "testAction");
|
||||
actionDescriptor.RouteValues.Add("randomKey", "10/31/2018 07:37:38 -07:00");
|
||||
|
||||
var provider = CreateActionDescriptorCollectionProvider(actionDescriptor);
|
||||
|
||||
var constraint = new KnownRouteValueConstraint(provider);
|
||||
|
||||
var values = new RouteValueDictionary()
|
||||
{
|
||||
{ "area", "testArea" },
|
||||
{ "controller", "testController" },
|
||||
{ "action", "testAction" },
|
||||
{ "randomKey", new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7)) },
|
||||
};
|
||||
|
||||
// Act
|
||||
var match = constraint.Match(httpContext: null, route: null, "randomKey", values, direction);
|
||||
|
||||
// Assert
|
||||
Assert.True(match);
|
||||
}
|
||||
|
||||
private static HttpContext GetHttpContext(ActionDescriptor actionDescriptor, bool setupRequestServices = true)
|
||||
{
|
||||
var descriptorCollectionProvider = CreateActionDescriptorCollectionProvider(actionDescriptor);
|
||||
|
|
|
|||
|
|
@ -219,4 +219,4 @@ namespace Microsoft.AspNetCore.Routing
|
|||
return httpContext;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ using System.Linq;
|
|||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||
using Microsoft.AspNetCore.Mvc.Routing;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Moq;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -248,6 +249,55 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test.Routing
|
|||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void Page_UsesAmbientRouteValueAndInvariantCulture_WhenPageIsNotNull()
|
||||
{
|
||||
// Arrange
|
||||
UrlRouteContext actual = null;
|
||||
var routeData = new RouteData
|
||||
{
|
||||
Values =
|
||||
{
|
||||
{ "page", new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7)) },
|
||||
}
|
||||
};
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = new ActionDescriptor
|
||||
{
|
||||
RouteValues = new Dictionary<string, string>
|
||||
{
|
||||
{ "page", "10/31/2018 07:37:38 -07:00" },
|
||||
},
|
||||
},
|
||||
RouteData = routeData,
|
||||
};
|
||||
|
||||
var urlHelper = CreateMockUrlHelper(actionContext);
|
||||
urlHelper.Setup(h => h.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||
.Callback((UrlRouteContext context) => actual = context);
|
||||
|
||||
// Act
|
||||
urlHelper.Object.Page("New Page", new { id = 13 });
|
||||
|
||||
// Assert
|
||||
urlHelper.Verify();
|
||||
Assert.NotNull(actual);
|
||||
Assert.Null(actual.RouteName);
|
||||
Assert.Collection(Assert.IsType<RouteValueDictionary>(actual.Values),
|
||||
value =>
|
||||
{
|
||||
Assert.Equal("id", value.Key);
|
||||
Assert.Equal(13, value.Value);
|
||||
},
|
||||
value =>
|
||||
{
|
||||
Assert.Equal("page", value.Key);
|
||||
Assert.Equal("10/31/New Page", value.Value);
|
||||
});
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Page_SetsHandlerToNull_IfValueIsNotSpecifiedInRouteValues()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1614,6 +1614,30 @@ namespace Microsoft.AspNetCore.Mvc.Razor
|
|||
Assert.Equal("Route-Value", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void GetNormalizedRouteValue_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var key = "some-key";
|
||||
var actionDescriptor = new ActionDescriptor();
|
||||
actionDescriptor.RouteValues.Add(key, "Route-Value");
|
||||
|
||||
var actionContext = new ActionContext
|
||||
{
|
||||
ActionDescriptor = actionDescriptor,
|
||||
RouteData = new RouteData()
|
||||
};
|
||||
|
||||
actionContext.RouteData.Values[key] = new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7));
|
||||
|
||||
// Act
|
||||
var result = RazorViewEngine.GetNormalizedRouteValue(actionContext, key);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("10/31/2018 07:37:38 -07:00", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetNormalizedRouteValue_ReturnsRouteValue_IfValueDoesNotMatch()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Xunit;
|
||||
|
||||
|
|
@ -419,6 +420,57 @@ namespace Microsoft.AspNetCore.Mvc.RazorPages.Internal
|
|||
Assert.Same(descriptor1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void Select_ReturnsHandlerThatMatchesHandler_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var descriptor1 = new HandlerMethodDescriptor
|
||||
{
|
||||
HttpMethod = "POST",
|
||||
Name = "10/31/2018 07:37:38 -07:00",
|
||||
};
|
||||
|
||||
var descriptor2 = new HandlerMethodDescriptor
|
||||
{
|
||||
HttpMethod = "POST",
|
||||
Name = "Delete",
|
||||
};
|
||||
|
||||
var pageContext = new PageContext
|
||||
{
|
||||
ActionDescriptor = new CompiledPageActionDescriptor
|
||||
{
|
||||
HandlerMethods = new List<HandlerMethodDescriptor>()
|
||||
{
|
||||
descriptor1,
|
||||
descriptor2,
|
||||
},
|
||||
},
|
||||
RouteData = new RouteData
|
||||
{
|
||||
Values =
|
||||
{
|
||||
{ "handler", new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7)) },
|
||||
}
|
||||
},
|
||||
HttpContext = new DefaultHttpContext
|
||||
{
|
||||
Request =
|
||||
{
|
||||
Method = "Post"
|
||||
},
|
||||
},
|
||||
};
|
||||
var selector = CreateSelector();
|
||||
|
||||
// Act
|
||||
var actual = selector.Select(pageContext);
|
||||
|
||||
// Assert
|
||||
Assert.Same(descriptor1, actual);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Select_HandlerFromQueryString()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -304,6 +304,31 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
Assert.Equal(expected, key);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void GenerateKey_UsesVaryByRoute_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var tagHelperContext = GetTagHelperContext();
|
||||
var cacheTagHelper = new CacheTagHelper(
|
||||
new CacheTagHelperMemoryCacheFactory(Mock.Of<IMemoryCache>()), new HtmlTestEncoder())
|
||||
{
|
||||
ViewContext = GetViewContext(),
|
||||
VaryByRoute = "Category",
|
||||
};
|
||||
cacheTagHelper.ViewContext.RouteData.Values["id"] = 4;
|
||||
cacheTagHelper.ViewContext.RouteData.Values["category"] =
|
||||
new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7));
|
||||
var expected = "CacheTagHelper||testid||VaryByRoute(Category||10/31/2018 07:37:38 -07:00)";
|
||||
|
||||
// Act
|
||||
var cacheTagKey = new CacheTagKey(cacheTagHelper, tagHelperContext);
|
||||
var key = cacheTagKey.GenerateKey();
|
||||
|
||||
// Assert
|
||||
Assert.Equal(expected, key);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GenerateKey_UsesVaryByUser_WhenUserIsNotAuthenticated()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
|
@ -20,6 +21,7 @@ using Microsoft.AspNetCore.Mvc.ViewEngines;
|
|||
using Microsoft.AspNetCore.Mvc.ViewFeatures;
|
||||
using Microsoft.AspNetCore.Razor.TagHelpers;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Caching.Memory;
|
||||
using Microsoft.Extensions.FileProviders;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
|
@ -161,8 +163,10 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
helper.FallbackTestValue = "hidden";
|
||||
helper.Href = "test.css";
|
||||
|
||||
var expectedAttributes = new TagHelperAttributeList(output.Attributes);
|
||||
expectedAttributes.Add(new TagHelperAttribute("href", "test.css"));
|
||||
var expectedAttributes = new TagHelperAttributeList(output.Attributes)
|
||||
{
|
||||
new TagHelperAttribute("href", "test.css")
|
||||
};
|
||||
|
||||
// Act
|
||||
helper.Process(context, output);
|
||||
|
|
@ -605,6 +609,47 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
Assert.Equal(expectedContent, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void RendersLinkTagsForGlobbedHrefResults_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var expectedContent = "<link rel=\"stylesheet\" href=\"HtmlEncode[[/css/site.css]]\" />" +
|
||||
"<link rel=\"stylesheet\" href=\"HtmlEncode[[/base.css]]\" />";
|
||||
var context = MakeTagHelperContext(
|
||||
attributes: new TagHelperAttributeList
|
||||
{
|
||||
{ "rel", new ConvertToStyleSheet() },
|
||||
{ "href", "/css/site.css" },
|
||||
{ "asp-href-include", "**/*.css" },
|
||||
});
|
||||
var output = MakeTagHelperOutput("link", attributes: new TagHelperAttributeList
|
||||
{
|
||||
{ "rel", new HtmlString("stylesheet") },
|
||||
});
|
||||
var globbingUrlBuilder = new Mock<GlobbingUrlBuilder>(
|
||||
new TestFileProvider(),
|
||||
Mock.Of<IMemoryCache>(),
|
||||
PathString.Empty);
|
||||
globbingUrlBuilder.Setup(g => g.BuildUrlList(null, "**/*.css", null))
|
||||
.Returns(new[] { "/base.css" });
|
||||
|
||||
var helper = GetHelper();
|
||||
|
||||
helper.GlobbingUrlBuilder = globbingUrlBuilder.Object;
|
||||
helper.Href = "/css/site.css";
|
||||
helper.HrefInclude = "**/*.css";
|
||||
|
||||
// Act
|
||||
helper.Process(context, output);
|
||||
|
||||
// Assert
|
||||
Assert.Equal("link", output.TagName);
|
||||
Assert.Equal("/css/site.css", output.Attributes["href"].Value);
|
||||
var content = HtmlContentUtilities.HtmlContentToString(output, new HtmlTestEncoder());
|
||||
Assert.Equal(expectedContent, content);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void RendersLinkTagsForGlobbedHrefResults_EncodesAsExpected()
|
||||
{
|
||||
|
|
@ -991,5 +1036,99 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
return urlHelperFactory.Object;
|
||||
}
|
||||
|
||||
private class ConvertToStyleSheet : IConvertible
|
||||
{
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool ToBoolean(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public byte ToByte(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public char ToChar(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public DateTime ToDateTime(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public decimal ToDecimal(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public double ToDouble(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public short ToInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public int ToInt32(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public long ToInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public sbyte ToSByte(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public float ToSingle(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
Assert.Equal(CultureInfo.InvariantCulture, provider);
|
||||
return "stylesheet";
|
||||
}
|
||||
|
||||
public object ToType(Type conversionType, IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ushort ToUInt16(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public uint ToUInt32(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ulong ToUInt64(IFormatProvider provider)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "something else";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -10,6 +11,7 @@ using Microsoft.AspNetCore.Mvc.Formatters;
|
|||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
|
@ -75,6 +77,30 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
Assert.Equal(viewName, viewEngineResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void FindView_UsesActionDescriptorName_IfViewNameIsNull_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var viewName = "10/31/2018 07:37:38 -07:00";
|
||||
var context = GetActionContext(viewName);
|
||||
context.RouteData.Values["action"] = new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7));
|
||||
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewResult = new PartialViewResult
|
||||
{
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var viewEngineResult = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(viewName, viewEngineResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithGetViewLocations()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
|
@ -9,6 +10,7 @@ using Microsoft.AspNetCore.Mvc.Controllers;
|
|||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||
using Microsoft.AspNetCore.Mvc.ViewEngines;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.AspNetCore.Testing;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
|
|
@ -74,6 +76,30 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
|||
Assert.Equal(viewName, viewEngineResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
[ReplaceCulture("de-CH", "de-CH")]
|
||||
public void FindView_UsesActionDescriptorName_IfViewNameIsNull_UsesInvariantCulture()
|
||||
{
|
||||
// Arrange
|
||||
var viewName = "10/31/2018 07:37:38 -07:00";
|
||||
var context = GetActionContext(viewName);
|
||||
context.RouteData.Values["action"] = new DateTimeOffset(2018, 10, 31, 7, 37, 38, TimeSpan.FromHours(-7));
|
||||
|
||||
var executor = GetViewExecutor();
|
||||
|
||||
var viewResult = new ViewResult
|
||||
{
|
||||
ViewData = new ViewDataDictionary(new EmptyModelMetadataProvider()),
|
||||
TempData = Mock.Of<ITempDataDictionary>(),
|
||||
};
|
||||
|
||||
// Act
|
||||
var viewEngineResult = executor.FindView(context, viewResult);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(viewName, viewEngineResult.ViewName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FindView_ReturnsExpectedNotFoundResult_WithGetViewLocations()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue