Skip to content
This repository was archived by the owner on Nov 29, 2018. It is now read-only.

Commit 359f187

Browse files
committed
Fix #111: Design changes to known/allowed culture list and cache
1 parent 90116dd commit 359f187

18 files changed

+249
-578
lines changed

Localization.sln

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
1919
global.json = global.json
2020
EndProjectSection
2121
EndProject
22-
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CultureInfoGenerator", "src\CultureInfoGenerator\CultureInfoGenerator.xproj", "{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}"
23-
EndProject
2422
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.Globalization.CultureInfoCache", "src\Microsoft.Extensions.Globalization.CultureInfoCache\Microsoft.Extensions.Globalization.CultureInfoCache.xproj", "{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}"
2523
EndProject
2624
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B723DB83-A670-4BCB-95FB-195361331AD2}"
@@ -55,10 +53,6 @@ Global
5553
{55D9501F-15B9-4339-A0AB-6082850E5FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
5654
{55D9501F-15B9-4339-A0AB-6082850E5FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
5755
{55D9501F-15B9-4339-A0AB-6082850E5FCE}.Release|Any CPU.Build.0 = Release|Any CPU
58-
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
59-
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
60-
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
61-
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Release|Any CPU.Build.0 = Release|Any CPU
6256
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
6357
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}.Debug|Any CPU.Build.0 = Debug|Any CPU
6458
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -88,7 +82,6 @@ Global
8882
{23E3BC23-3464-4D9B-BF78-02CB2182BEF0} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
8983
{A1FCF259-70F6-4605-AA2D-E4B356BE771A} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
9084
{55D9501F-15B9-4339-A0AB-6082850E5FCE} = {79878809-8D1C-4BD4-BA99-F1F13FF96FD8}
91-
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
9285
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
9386
{287AD58D-DF34-4F16-8616-FD78FA1CADF9} = {B723DB83-A670-4BCB-95FB-195361331AD2}
9487
{19A2A931-5C60-47A0-816A-0DC9C4CE5736} = {B723DB83-A670-4BCB-95FB-195361331AD2}

samples/LocalizationSample/Startup.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void Configure(IApplicationBuilder app, IStringLocalizer<Startup> SR)
4343

4444
//}));
4545

46-
app.UseRequestLocalization(options);
46+
app.UseRequestLocalization(options, new RequestCulture(new CultureInfo("en-US")));
4747

4848
app.Use(async (context, next) =>
4949
{

src/Microsoft.AspNet.Localization/AcceptLanguageHeaderRequestCultureProvider.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Globalization;
57
using System.Linq;
68
using System.Threading.Tasks;
79
using Microsoft.AspNet.Http;
@@ -55,17 +57,10 @@ public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpCon
5557
// the CultureInfo ctor
5658
if (language.Value != null)
5759
{
58-
var culture = CultureInfoCache.GetCultureInfo(language.Value);
60+
var culture = CultureInfoCache.GetCultureInfo(language.Value, Options.SupportedCultures);
5961
if (culture != null)
6062
{
61-
var requestCulture = new RequestCulture(culture);
62-
63-
requestCulture = ValidateRequestCulture(requestCulture);
64-
65-
if (requestCulture?.Culture == culture)
66-
{
67-
return Task.FromResult(requestCulture);
68-
}
63+
return Task.FromResult(new RequestCulture(culture));
6964
}
7065
}
7166
}

src/Microsoft.AspNet.Localization/ApplicationBuilderExtensions.cs

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Globalization;
56
using Microsoft.AspNet.Localization;
67

78
namespace Microsoft.AspNet.Builder
@@ -16,17 +17,26 @@ public static class ApplicationBuilderExtensions
1617
/// requests based on information provided by the client using the default options.
1718
/// </summary>
1819
/// <param name="builder">The <see cref="IApplicationBuilder"/>.</param>
20+
/// <param name="defaultRequestCulture">The default <see cref="RequestCulture"/> to use if none of the
21+
/// requested cultures match supported cultures.</param>
1922
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
20-
public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder builder)
23+
public static IApplicationBuilder UseRequestLocalization(
24+
this IApplicationBuilder builder,
25+
RequestCulture defaultRequestCulture)
2126
{
2227
if (builder == null)
2328
{
2429
throw new ArgumentNullException(nameof(builder));
2530
}
2631

32+
if (defaultRequestCulture == null)
33+
{
34+
throw new ArgumentNullException(nameof(defaultRequestCulture));
35+
}
36+
2737
var options = new RequestLocalizationOptions();
2838

29-
return UseRequestLocalization(builder, options);
39+
return UseRequestLocalization(builder, options, defaultRequestCulture);
3040
}
3141

3242
/// <summary>
@@ -35,10 +45,13 @@ public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilde
3545
/// </summary>
3646
/// <param name="builder">The <see cref="IApplicationBuilder"/>.</param>
3747
/// <param name="options">The options to configure the middleware with.</param>
48+
/// <param name="defaultRequestCulture">The default <see cref="RequestCulture"/> to use if none of the
49+
/// requested cultures match supported cultures.</param>
3850
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
3951
public static IApplicationBuilder UseRequestLocalization(
4052
this IApplicationBuilder builder,
41-
RequestLocalizationOptions options)
53+
RequestLocalizationOptions options,
54+
RequestCulture defaultRequestCulture)
4255
{
4356
if (builder == null)
4457
{
@@ -50,7 +63,12 @@ public static IApplicationBuilder UseRequestLocalization(
5063
throw new ArgumentNullException(nameof(options));
5164
}
5265

53-
return builder.UseMiddleware<RequestLocalizationMiddleware>(options);
66+
if (defaultRequestCulture == null)
67+
{
68+
throw new ArgumentNullException(nameof(defaultRequestCulture));
69+
}
70+
71+
return builder.UseMiddleware<RequestLocalizationMiddleware>(options, defaultRequestCulture);
5472
}
5573
}
5674
}

src/Microsoft.AspNet.Localization/CookieRequestCultureProvider.cs

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
6+
using System.Globalization;
57
using System.Threading.Tasks;
68
using Microsoft.AspNet.Http;
79
using Microsoft.Extensions.Globalization;
@@ -43,9 +45,7 @@ public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpCon
4345
return Task.FromResult((RequestCulture)null);
4446
}
4547

46-
var requestCulture = ParseCookieValue(cookie);
47-
48-
requestCulture = ValidateRequestCulture(requestCulture);
48+
var requestCulture = ParseCookieValue(cookie, Options.SupportedCultures, Options.SupportedUICultures);
4949

5050
return Task.FromResult(requestCulture);
5151
}
@@ -75,7 +75,10 @@ public static string MakeCookieValue(RequestCulture requestCulture)
7575
/// </summary>
7676
/// <param name="value">The cookie value to parse.</param>
7777
/// <returns>The <see cref="RequestCulture"/> or <c>null</c> if parsing fails.</returns>
78-
public static RequestCulture ParseCookieValue(string value)
78+
public static RequestCulture ParseCookieValue(
79+
string value,
80+
IList<CultureInfo> supportedCultures,
81+
IList<CultureInfo> supportedUICultures)
7982
{
8083
if (string.IsNullOrWhiteSpace(value))
8184
{
@@ -100,8 +103,8 @@ public static RequestCulture ParseCookieValue(string value)
100103
var cultureName = potentialCultureName.Substring(_culturePrefix.Length);
101104
var uiCultureName = potentialUICultureName.Substring(_uiCulturePrefix.Length);
102105

103-
var culture = CultureInfoCache.GetCultureInfo(cultureName);
104-
var uiCulture = CultureInfoCache.GetCultureInfo(uiCultureName);
106+
var culture = CultureInfoCache.GetCultureInfo(cultureName, supportedCultures);
107+
var uiCulture = CultureInfoCache.GetCultureInfo(uiCultureName, supportedUICultures);
105108

106109
if (culture == null || uiCulture == null)
107110
{

src/Microsoft.AspNet.Localization/IRequestCultureProvider.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

4+
using System.Collections.Generic;
5+
using System.Globalization;
46
using System.Threading.Tasks;
57
using Microsoft.AspNet.Http;
68

src/Microsoft.AspNet.Localization/QueryStringRequestCultureProvider.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpCon
7171
queryCulture = queryUICulture;
7272
}
7373

74-
var culture = CultureInfoCache.GetCultureInfo(queryCulture);
75-
var uiCulture = CultureInfoCache.GetCultureInfo(queryUICulture);
74+
var culture = CultureInfoCache.GetCultureInfo(queryCulture, Options.SupportedCultures);
75+
var uiCulture = CultureInfoCache.GetCultureInfo(queryUICulture, Options.SupportedUICultures);
7676

7777
if (culture == null || uiCulture == null)
7878
{
@@ -81,8 +81,6 @@ public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpCon
8181

8282
var requestCulture = new RequestCulture(culture, uiCulture);
8383

84-
requestCulture = ValidateRequestCulture(requestCulture);
85-
8684
return Task.FromResult(requestCulture);
8785
}
8886
}

src/Microsoft.AspNet.Localization/RequestCultureProvider.cs

Lines changed: 0 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -19,43 +19,5 @@ public abstract class RequestCultureProvider : IRequestCultureProvider
1919
/// <inheritdoc />
2020
public abstract Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext);
2121

22-
/// <summary>
23-
/// Determines if the given <see cref="RequestCulture"/> is valid according to the currently configured.
24-
/// <see cref="RequestLocalizationOptions"/>.
25-
/// </summary>
26-
/// <param name="requestCulture">The <see cref="RequestCulture"/> to validate.</param>
27-
/// <returns>
28-
/// The original <see cref="RequestCulture"/> if it was valid, otherwise a new <see cref="RequestCulture"/>
29-
/// with values for <see cref="RequestCulture.Culture"/> and <see cref="RequestCulture.UICulture"/> that are
30-
/// valid for the current configuration, or <c>null</c> if neither <see cref="RequestCulture.Culture"/> or
31-
/// <see cref="RequestCulture.UICulture"/> were valid.
32-
/// </returns>
33-
protected RequestCulture ValidateRequestCulture(RequestCulture requestCulture)
34-
{
35-
if (requestCulture == null || Options == null)
36-
{
37-
return requestCulture;
38-
}
39-
40-
var result = requestCulture;
41-
42-
if (Options.SupportedCultures != null && !Options.SupportedCultures.Contains(result.Culture))
43-
{
44-
result = new RequestCulture(Options.DefaultRequestCulture.Culture, result.UICulture);
45-
}
46-
47-
if (Options.SupportedUICultures != null && !Options.SupportedUICultures.Contains(result.UICulture))
48-
{
49-
result = new RequestCulture(result.Culture, Options.DefaultRequestCulture.UICulture);
50-
}
51-
52-
if (requestCulture.Culture != result.Culture && requestCulture.UICulture != result.UICulture)
53-
{
54-
// Both cultures were invalid, just return null
55-
return null;
56-
}
57-
58-
return result;
59-
}
6022
}
6123
}

src/Microsoft.AspNet.Localization/RequestLocalizationMiddleware.cs

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,20 @@ public class RequestLocalizationMiddleware
1919
{
2020
private readonly RequestDelegate _next;
2121
private readonly RequestLocalizationOptions _options;
22+
private readonly RequestCulture _defaultRequestCulture;
2223

2324
/// <summary>
2425
/// Creates a new <see cref="RequestLocalizationMiddleware"/>.
2526
/// </summary>
2627
/// <param name="next">The <see cref="RequestDelegate"/> representing the next middleware in the pipeline.</param>
27-
/// <param name="options">The <see cref="RequestLocalizationOptions"/> representing the options for the <see cref="RequestLocalizationMiddleware"/>.</param>
28-
public RequestLocalizationMiddleware(RequestDelegate next, RequestLocalizationOptions options)
28+
/// <param name="options">The <see cref="RequestLocalizationOptions"/> representing the options for the
29+
/// <see cref="RequestLocalizationMiddleware"/>.</param>
30+
/// <param name="defaultRequestCulture">The default <see cref="RequestCulture"/> to use if none of the
31+
/// requested cultures match supported cultures.</param>
32+
public RequestLocalizationMiddleware(
33+
RequestDelegate next,
34+
RequestLocalizationOptions options,
35+
RequestCulture defaultRequestCulture)
2936
{
3037
if (next == null)
3138
{
@@ -37,8 +44,14 @@ public RequestLocalizationMiddleware(RequestDelegate next, RequestLocalizationOp
3744
throw new ArgumentNullException(nameof(options));
3845
}
3946

47+
if (defaultRequestCulture == null)
48+
{
49+
throw new ArgumentNullException(nameof(defaultRequestCulture));
50+
}
51+
4052
_next = next;
4153
_options = options;
54+
_defaultRequestCulture = defaultRequestCulture;
4255
}
4356

4457
/// <summary>
@@ -53,15 +66,18 @@ public async Task Invoke(HttpContext context)
5366
throw new ArgumentNullException(nameof(context));
5467
}
5568

56-
var requestCulture = _options.DefaultRequestCulture ??
57-
new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
69+
var requestCulture = _defaultRequestCulture;
5870

5971
IRequestCultureProvider winningProvider = null;
6072

6173
if (_options.RequestCultureProviders != null)
6274
{
6375
foreach (var provider in _options.RequestCultureProviders)
6476
{
77+
if (provider is RequestCultureProvider)
78+
{
79+
((RequestCultureProvider)provider).Options = _options;
80+
}
6581
var result = await provider.DetermineRequestCulture(context);
6682
if (result != null)
6783
{

src/Microsoft.AspNet.Localization/RequestLocalizationOptions.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ public class RequestLocalizationOptions
1717
/// </summary>
1818
public RequestLocalizationOptions()
1919
{
20-
DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
21-
2220
RequestCultureProviders = new List<IRequestCultureProvider>
2321
{
2422
new QueryStringRequestCultureProvider { Options = this },
@@ -27,14 +25,6 @@ public RequestLocalizationOptions()
2725
};
2826
}
2927

30-
/// <summary>
31-
/// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured
32-
/// <see cref="IRequestCultureProvider"/> options result in a non-<c>null</c> result.
33-
/// Defaults to <see cref="RequestCulture.Culture"/> set to <see cref="CultureInfo.DefaultThreadCurrentCulture"/>
34-
/// and <see cref="RequestCulture.UICulture"/> set to <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>.
35-
/// </summary>
36-
public RequestCulture DefaultRequestCulture { get; set; }
37-
3828
/// <summary>
3929
/// The cultures supported by the application. If this value is non-<c>null</c>, the
4030
/// <see cref="RequestLocalizationMiddleware"/> will only set the current request culture to an entry in this

src/Microsoft.Extensions.Globalization.CultureInfoCache/CultureInfoCache.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System.Collections.Concurrent;
5+
using System.Collections.Generic;
56
using System.Globalization;
7+
using System.Linq;
68

79
namespace Microsoft.Extensions.Globalization
810
{
911
/// <summary>
1012
/// Provides read-only cached instances of <see cref="CultureInfo"/>.
1113
/// </summary>
12-
public static partial class CultureInfoCache
14+
public static class CultureInfoCache
1315
{
1416
private static readonly ConcurrentDictionary<string, CacheEntry> _cache = new ConcurrentDictionary<string, CacheEntry>();
1517

@@ -22,11 +24,12 @@ public static partial class CultureInfoCache
2224
/// A read-only cached <see cref="CultureInfo"/> or <c>null</c> a match wasn't found in
2325
/// <see cref="KnownCultureNames"/>.
2426
/// </returns>
25-
public static CultureInfo GetCultureInfo(string name)
27+
public static CultureInfo GetCultureInfo(string name, IList<CultureInfo> SupportedCultures)
2628
{
2729
// Allow only known culture names as this API is called with input from users (HTTP requests) and
2830
// creating CultureInfo objects is expensive and we don't want it to throw either.
29-
if (name == null || !KnownCultureNames.Contains(name))
31+
if (name == null || SupportedCultures == null ||
32+
SupportedCultures.Where( s => s.Name.ToLowerInvariant() == name.ToLowerInvariant()).FirstOrDefault() == null)
3033
{
3134
return null;
3235
}

0 commit comments

Comments
 (0)