Moved some things around:

- Options are now given to strategies
- Options only contains properties relevant to the middleware itself. Strategies can have their own properties, e.g. AcceptLanguageHeaderRequestCultureStrategy limits the number of values in the header to try
- Strategies now derive from common base class and validate against the options, e.g. app specified supported cultures
- Renamed RequestLocalizationMiddlewareOptions to RequestLocalizationOptions
- Fixed missing doc comments
This commit is contained in:
damianedwards 2015-05-11 15:28:50 -07:00
parent 9834a27728
commit 306d71ef43
11 changed files with 118 additions and 46 deletions

View File

@ -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.Collections.Generic;
using System.Globalization;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
@ -20,10 +21,19 @@ namespace LocalizationSample
public void Configure(IApplicationBuilder app, IStringLocalizer<Startup> SR)
{
var options = new RequestLocalizationMiddlewareOptions
var options = new RequestLocalizationOptions
{
// Set options here to change middleware behavior
//SupportedCultures = new List<CultureInfo>
//{
// new CultureInfo("en-US"),
// new CultureInfo("en-AU")
//},
//SupportedUICultures = new List<CultureInfo>
//{
// new CultureInfo("en-US"),
// new CultureInfo("en-AU")
//}
};
app.UseRequestLocalization(options);

View File

@ -1,7 +1,6 @@
// 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.Globalization;
using System.Linq;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Localization.Internal;
@ -13,7 +12,7 @@ namespace Microsoft.AspNet.Localization
/// <summary>
/// Determines the culture information for a request via the value of the Accept-Language header.
/// </summary>
public class AcceptLanguageHeaderRequestCultureStrategy : IRequestCultureStrategy
public class AcceptLanguageHeaderRequestCultureStrategy : RequestCultureStrategy
{
/// <summary>
/// The maximum number of values in the Accept-Language header to attempt to create a <see cref="CultureInfo"/>
@ -23,7 +22,7 @@ namespace Microsoft.AspNet.Localization
public int MaximumAcceptLanguageHeaderValuesToTry { get; set; } = 3;
/// <inheritdoc />
public RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
public override RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
{
var acceptLanguageHeader = httpContext.Request.GetTypedHeaders().AcceptLanguage;
@ -53,7 +52,14 @@ namespace Microsoft.AspNet.Localization
var culture = CultureInfoCache.GetCultureInfo(language.Value);
if (culture != null)
{
return RequestCulture.GetRequestCulture(culture);
var requestCulture = RequestCulture.GetRequestCulture(culture);
requestCulture = ValidateRequestCulture(requestCulture);
if (requestCulture != null)
{
return requestCulture;
}
}
}
}

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNet.Localization
/// <summary>
/// Determines the culture information for a request via the value of a cookie.
/// </summary>
public class CookieRequestCultureStrategy : IRequestCultureStrategy
public class CookieRequestCultureStrategy : RequestCultureStrategy
{
private static readonly char[] _cookieSeparator = new[] { '|' };
private static readonly string _culturePrefix = "c=";
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Localization
public string CookieName { get; set; } = DefaultCookieName;
/// <inheritdoc />
public RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
public override RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
{
var cookie = httpContext.Request.Cookies[CookieName];
@ -33,7 +33,11 @@ namespace Microsoft.AspNet.Localization
return null;
}
return ParseCookieValue(cookie);
var requestCulture = ParseCookieValue(cookie);
requestCulture = ValidateRequestCulture(requestCulture);
return requestCulture;
}
/// <summary>

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Localization
/// <summary>
/// Determines the culture information for a request via the configured delegate.
/// </summary>
public class CustomRequestCultureStrategy : IRequestCultureStrategy
public class CustomRequestCultureStrategy : RequestCultureStrategy
{
private readonly Func<HttpContext, RequestCulture> _strategy;
@ -24,7 +24,7 @@ namespace Microsoft.AspNet.Localization
}
/// <inheritdoc />
public RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
public override RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
{
return _strategy(httpContext);
}

View File

@ -19,7 +19,7 @@ namespace Microsoft.AspNet.Builder
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
public static IApplicationBuilder UseRequestLocalization([NotNull] this IApplicationBuilder builder)
{
var options = new RequestLocalizationMiddlewareOptions();
var options = new RequestLocalizationOptions();
return UseRequestLocalization(builder, options);
}
@ -33,7 +33,7 @@ namespace Microsoft.AspNet.Builder
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
public static IApplicationBuilder UseRequestLocalization(
[NotNull] this IApplicationBuilder builder,
[NotNull] RequestLocalizationMiddlewareOptions options)
[NotNull] RequestLocalizationOptions options)
{
return builder.UseMiddleware<RequestLocalizationMiddleware>(options);
}

View File

@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Localization
/// <summary>
/// The <see cref="IRequestCultureStrategy"/> that determined the request's culture information.
/// If the value is <c>null</c> then no strategy was used and the request's culture was set to the value of
/// <see cref="RequestLocalizationMiddlewareOptions.DefaultRequestCulture"/>.
/// <see cref="RequestLocalizationOptions.DefaultRequestCulture"/>.
/// </summary>
IRequestCultureStrategy Strategy { get; }
}

View File

@ -10,6 +10,14 @@ namespace Microsoft.AspNet.Localization
/// </summary>
public interface IRequestCultureStrategy
{
/// <summary>
/// Implements the strategy to determine the culture of the given request.
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> for the request.</param>
/// <returns>
/// The determined <see cref="RequestCulture"/>.
/// Returns <c>null</c> if the strategy couldn't determine a <see cref="RequestCulture"/>.
/// </returns>
RequestCulture DetermineRequestCulture(HttpContext httpContext);
}
}

View File

@ -10,7 +10,7 @@ namespace Microsoft.AspNet.Localization
/// <summary>
/// Determines the culture information for a request via values in the query string.
/// </summary>
public class QueryStringRequestCultureStrategy : IRequestCultureStrategy
public class QueryStringRequestCultureStrategy : RequestCultureStrategy
{
/// <summary>
/// The key that contains the culture name.
@ -26,7 +26,7 @@ namespace Microsoft.AspNet.Localization
public string UIQueryStringKey { get; set; } = "ui-culture";
/// <inheritdoc />
public RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
public override RequestCulture DetermineRequestCulture([NotNull] HttpContext httpContext)
{
var request = httpContext.Request;
if (!request.QueryString.HasValue)
@ -67,7 +67,11 @@ namespace Microsoft.AspNet.Localization
return null;
}
return RequestCulture.GetRequestCulture(culture, uiCulture);
var requestCulture = RequestCulture.GetRequestCulture(culture, uiCulture);
requestCulture = ValidateRequestCulture(requestCulture);
return requestCulture;
}
}
}

View File

@ -0,0 +1,61 @@
// 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 Microsoft.AspNet.Http;
using Microsoft.Framework.Internal;
namespace Microsoft.AspNet.Localization
{
/// <summary>
/// An abstract base class strategy for determining the culture information of an <see cref="HttpRequest"/>.
/// </summary>
public abstract class RequestCultureStrategy : IRequestCultureStrategy
{
/// <summary>
/// The current options for the <see cref="RequestLocalizationMiddleware"/>.
/// </summary>
public RequestLocalizationOptions Options { get; set; }
/// <inheritdoc />
public abstract RequestCulture DetermineRequestCulture(HttpContext httpContext);
/// <summary>
/// Determines if the given <see cref="RequestCulture"/> is valid according to the currently configured.
/// <see cref="RequestLocalizationOptions"/>.
/// </summary>
/// <param name="requestCulture">The <see cref="RequestCulture"/> to validate.</param>
/// <returns>
/// The original <see cref="RequestCulture"/> if it was valid, otherwise a new <see cref="RequestCulture"/>
/// with values for <see cref="RequestCulture.Culture"/> and <see cref="RequestCulture.UICulture"/> that are
/// valid for the current configuration, or <c>null</c> if neither <see cref="RequestCulture.Culture"/> or
/// <see cref="RequestCulture.UICulture"/> were valid.
/// </returns>
protected RequestCulture ValidateRequestCulture(RequestCulture requestCulture)
{
if (requestCulture == null || Options == null)
{
return requestCulture;
}
var result = requestCulture;
if (Options.SupportedCultures != null && !Options.SupportedCultures.Contains(result.Culture))
{
result = RequestCulture.GetRequestCulture(Options.DefaultRequestCulture.Culture, result.UICulture);
}
if (Options.SupportedUICultures != null && !Options.SupportedUICultures.Contains(result.UICulture))
{
result = RequestCulture.GetRequestCulture(result.Culture, Options.DefaultRequestCulture.UICulture);
}
if (requestCulture.Culture != result.Culture && requestCulture.UICulture != result.UICulture)
{
// Both cultures were invalid, just return null
return null;
}
return result;
}
}
}

View File

@ -17,14 +17,14 @@ namespace Microsoft.AspNet.Localization
public class RequestLocalizationMiddleware
{
private readonly RequestDelegate _next;
private readonly RequestLocalizationMiddlewareOptions _options;
private readonly RequestLocalizationOptions _options;
/// <summary>
/// Creates a new <see cref="RequestLocalizationMiddleware"/>.
/// </summary>
/// <param name="next">The <see cref="RequestDelegate"/> representing the next middleware in the pipeline.</param>
/// <param name="options"></param>
public RequestLocalizationMiddleware([NotNull] RequestDelegate next, [NotNull] RequestLocalizationMiddlewareOptions options)
public RequestLocalizationMiddleware([NotNull] RequestDelegate next, [NotNull] RequestLocalizationOptions options)
{
_next = next;
_options = options;
@ -56,20 +56,6 @@ namespace Microsoft.AspNet.Localization
}
}
if (_options.SupportedCultures != null)
{
// Ensure that selected cultures are in the supported list and if not, set them to the default
if (!_options.SupportedCultures.Contains(requestCulture.Culture))
{
requestCulture = RequestCulture.GetRequestCulture(_options.DefaultRequestCulture.Culture, requestCulture.UICulture);
}
if (!_options.SupportedUICultures.Contains(requestCulture.UICulture))
{
requestCulture = RequestCulture.GetRequestCulture(requestCulture.Culture, _options.DefaultRequestCulture.UICulture);
}
}
context.SetFeature<IRequestCultureFeature>(new RequestCultureFeature(requestCulture, winningStrategy));
SetCurrentThreadCulture(requestCulture);

View File

@ -10,30 +10,23 @@ namespace Microsoft.AspNet.Localization
/// <summary>
/// Specifies options for the <see cref="RequestLocalizationMiddleware"/>.
/// </summary>
public class RequestLocalizationMiddlewareOptions
public class RequestLocalizationOptions
{
/// <summary>
/// Creates a new <see cref="RequestLocalizationMiddlewareOptions"/> with default values.
/// Creates a new <see cref="RequestLocalizationOptions"/> with default values.
/// </summary>
public RequestLocalizationMiddlewareOptions()
public RequestLocalizationOptions()
{
DefaultRequestCulture = RequestCulture.GetRequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
RequestCultureStrategies = new List<IRequestCultureStrategy>
{
new QueryStringRequestCultureStrategy(),
new CookieRequestCultureStrategy(),
new AcceptLanguageHeaderRequestCultureStrategy { MaximumAcceptLanguageHeaderValuesToTry = MaximumAcceptLanguageHeaderValuesToTry }
new QueryStringRequestCultureStrategy { Options = this },
new CookieRequestCultureStrategy { Options = this },
new AcceptLanguageHeaderRequestCultureStrategy { Options = this }
};
}
/// <summary>
/// The maximum number of values in the Accept-Language header to attempt to create a <see cref="CultureInfo"/>
/// from for the current request.
/// Defaults to <c>3</c>.
/// </summary>
public int MaximumAcceptLanguageHeaderValuesToTry { get; set; } = 3;
/// <summary>
/// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured
/// <see cref="IRequestCultureStrategy"/> options result in a non-<c>null</c> result.