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

Added support for get culture information from request's route data i… #288

Closed
wants to merge 3 commits into from

Conversation

kichalla
Copy link
Member

…nformation.

[Fixes #122] Get segment from mapped route for CustomRequestCultureProvider

@Eilon

…nformation.

[Fixes #122] Get segment from mapped route for CustomRequestCultureProvider
@hishamco
Copy link
Contributor

Great, looks I need to close my issue #282 because I was planning to make a PR for this, unfortunately no one respond to that issue 😞

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why you're creating a new project for Routing? It will be nice to follow the structure that's already used in the repo. I think adding RouteDataRequestCultureProvider.cs is appropriate choice

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to avoid dependency of Routing in core localization package as it does not depend on routing.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid point

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same thing here add we can adds the test to the Microsoft.AspNetCore.Localization.Tests project

@hishamco
Copy link
Contributor

Can we add this to the https://github.com/aspnet/Localization/tree/dev/test/LocalizationWebsite for functional test, because what you did in the unit tests that you wrote is to configure the localization options inside app.UseRouter, practically we need to configure it before app.UseMvc, and this will lead to the issue that described here aspnet/Mvc#4952 HttpContext.GetRouteData() always will return null because the routing is not injected yet

new CultureInfo("ar-YE")
}
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can replace it with

options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider()
                                {
                                    Options = options,
                                    RouteDataStringKey = "c",
                                    UIRouteDataStringKey = "uic"
                                });

new CultureInfo("ar-YE")
}
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Simplify this with

options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider()
                                {
                                    Options = options
                                });

{
DefaultRequestCulture = new RequestCulture("en-US")
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as my previous suggestion

@hishamco
Copy link
Contributor

It's also possible to register the newly RequestCultureProvider here https://github.com/aspnet/Localization/blob/dev/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs#L26 instead of adding it every time while we configure the options


if (!string.IsNullOrWhiteSpace(RouteDataStringKey))
{
culture = httpContext.GetRouteValue(RouteDataStringKey) as string;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use ToString() here?

Copy link
Contributor

@dougbu dougbu Sep 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hishamco good idea. @kichalla why didn't you make this change and do the same thing for uiCulture?

new CultureInfo("ar-YE")
}
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as previous suggestion


Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var data = await response.Content.ReadAsStringAsync();
Assert.Equal($"{expectedCulture},{expectedUICulture}", data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pleas add new line here

{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
return context.Response.WriteAsync(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here

new CultureInfo("ar-YE")
}
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here


Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var data = await response.Content.ReadAsStringAsync();
Assert.Equal("en-US,en-US", data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here

{
DefaultRequestCulture = new RequestCulture("en-US")
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here


Assert.Equal(HttpStatusCode.OK, response.StatusCode);
var data = await response.Content.ReadAsStringAsync();
Assert.Equal($"{expectedCulture},{expectedUICulture}", data);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here

{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
return context.Response.WriteAsync(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here

new CultureInfo("ar-YE")
}
};
options.RequestCultureProviders = new[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add new line here

using Microsoft.AspNetCore.TestHost;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
using System.Net;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sort the namesapces

if (culture == null && uiCulture == null)
{
// No values specified for either so no match
return Task.FromResult((ProviderCultureResult)null);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use Microsoft.Extensions.TaskCache.Sources to avoid creating this Task in every request.

/// <see cref="RouteDataStringKey"/> will be used.
/// Defaults to "ui-culture".
/// </summary>
public string UIRouteDataStringKey { get; set; } = "ui-culture";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use a new options class.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Experience here is in line with existing culture providers. So I do not want to do anything different with this new provider.

@kichalla
Copy link
Member Author

It's also possible to register the newly RequestCultureProvider here https://github.com/aspnet/Localization/blob/dev/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs#L26 instead of adding it every time while we configure the options

Adding the new provider in the linked location would cause that package to indirectly depend on Routing which we want to avoid.

@kichalla
Copy link
Member Author

Can we add this to the https://github.com/aspnet/Localization/tree/dev/test/LocalizationWebsite for functional test, because what you did in the unit tests that you wrote is to configure the localization options inside app.UseRouter, practically we need to configure it before app.UseMvc, and this will lead to the issue that described here aspnet/Mvc#4952 HttpContext.GetRouteData() always will return null because the routing is not injected yet

If you take a look at the website, it does not depend on MVC (this is on purpose as in our build process we do not want to create a circular dependency between repositories). For the scenario you mentioned, I am planning to update an existing test in MVC which tests the scenario you mentioned: https://github.com/aspnet/Mvc/blob/dev/test/WebSites/FiltersWebSite/LocalizationPipeline.cs#L27

@kichalla
Copy link
Member Author

🆙 📅


if (!string.IsNullOrWhiteSpace(RouteDataStringKey))
{
culture = httpContext.GetRouteValue(RouteDataStringKey) as string;
Copy link
Contributor

@dougbu dougbu Sep 26, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hishamco good idea. @kichalla why didn't you make this change and do the same thing for uiCulture?

"dependencies": {
"Microsoft.AspNetCore.Localization": "1.1.0-*",
"Microsoft.AspNetCore.Routing": "1.1.0-*",
"Microsoft.Extensions.TaskCache.Sources": "1.1.0-*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This must be a "type": "build" dependency.

@@ -23,7 +23,8 @@
"Microsoft.AspNetCore.Http.Extensions": "1.1.0-*",
"Microsoft.Extensions.Globalization.CultureInfoCache": "1.1.0-*",
"Microsoft.Extensions.Localization.Abstractions": "1.1.0-*",
"Microsoft.Extensions.Options": "1.1.0-*"
"Microsoft.Extensions.Options": "1.1.0-*",
"Microsoft.Extensions.TaskCache.Sources": "1.1.0-*"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"type": "build"

string culture = null;
string uiCulture = null;

if (!string.IsNullOrWhiteSpace(RouteDataStringKey))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't check white space.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No description provided.

@kichalla
Copy link
Member Author

🆙 📅

@@ -33,7 +34,7 @@ public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpC

if (acceptLanguageHeader == null || acceptLanguageHeader.Count == 0)
{
return Task.FromResult((ProviderCultureResult)null);
return TaskCache<ProviderCultureResult>.DefaultCompletedTask;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this change applicable in this PR, or may we need another PR, while this one specially for adding RouteDataCulureRequestProvider

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hishamco this is fine. Good in fact. We were cleaning up cacheable Tasks and @kichalla got ahead of the curve.

{
app.UseRouter(routes =>
{
routes.MapRoute(routeTemplate, (IApplicationBuilder fork) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fork ??

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can subApp instead

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do call this a forked pipeline. But subApp is also commonly used.

var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
return context.Response.WriteAsync(
$"{requestCulture.Culture.Name},{requestCulture.UICulture.Name}");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: lessen the indenting

{
app.UseRouter(routes =>
{
routes.MapRoute(routeTemplate, (IApplicationBuilder fork) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fork ??


namespace Microsoft.AspNetCore.Localization.Routing
{
public class RouteDataRequestCultureProviderTest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 3 tests in this class seem to share a lot of boilerplate. Can any of that be moved into helper methods to reduce the repetition and make the differences between the setups more obvious?

@kichalla
Copy link
Member Author

861ae52

@kichalla kichalla closed this Sep 30, 2016
@kichalla kichalla deleted the kichalla/routedata-cultureprovider branch January 30, 2017 19:57
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants