Get segment from mapped route for CustomRequestCultureProvider #122

Closed
Codenator81 opened this Issue Oct 20, 2015 · 29 comments

Comments

Projects
None yet
7 participants
@Codenator81

I tested after

app.UseMvc(routes =>

in startup class app.UseRequestLocalization not work.
For example user want culture segment been in:

routes.MapRoute(
                    name: "transRoute",
                    template: "{controller=Home}/{culture=en-US}/{action=Index}/{id?}");

So how I can get {culture} segment to find route match?

This is all way not processed:

options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
            {
                var routeContext = new RouteContext(context); // IsHandled all ways false

Thanks Alex

@BenjiZombie

This comment has been minimized.

Show comment
Hide comment
@BenjiZombie

BenjiZombie Oct 20, 2015

What I did was create a RouteRequestCultureProvider instead.

namespace Microsoft.AspNet.Localization
{
    /// <summary>
    /// Determines the culture information for a request via values in the route.
    /// </summary>
    public class RouteRequestCultureProvider : RequestCultureProvider
    {
        #region Overrides of RequestCultureProvider

        public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            var request = httpContext.Request;
            if (!request.Path.HasValue)
            {
                return Task.FromResult((RequestCulture) null);
            }

            var cultureValue = Regex.Match(
                request.Path.Value,
                @"^/([a-z]{2})",
                RegexOptions.IgnoreCase);

            if (cultureValue.Success)
            {
                var culture = CultureInfoCache.GetCultureInfo(cultureValue.Groups[1].Value);
                var uiCulture = CultureInfoCache.GetCultureInfo(cultureValue.Groups[1].Value);

                if (culture == null || uiCulture == null)
                {
                    return Task.FromResult((RequestCulture) null);
                }

                var requestCulture = new RequestCulture(culture, uiCulture);
                requestCulture = ValidateRequestCulture(requestCulture);

                return Task.FromResult(requestCulture);
            }

            return Task.FromResult((RequestCulture) null);
        }

        #endregion
    }
}

Then simply register it in the Configure method:

// Add localization to the request pipeline.
var requestLocalizationOptions = new RequestLocalizationOptions
{
    SupportedCultures = new List<CultureInfo>
    {
        new CultureInfo("en"),
        new CultureInfo("fr"),
        new CultureInfo("es")
    },
    SupportedUICultures = new List<CultureInfo>
    {
        new CultureInfo("en"),
        new CultureInfo("fr"),
        new CultureInfo("es")
    }
};
requestLocalizationOptions.RequestCultureProviders.Insert(2, new RouteRequestCultureProvider
{
    Options = requestLocalizationOptions
});
app.UseRequestLocalization(requestLocalizationOptions);

My route mapping is different from yours, but you can easily modify the code to fit your needs

// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{culture?}/{controller}/{action}/{id?}",
        defaults: new { culture = "en", controller = "Home", action = "Index" });
});

What I did was create a RouteRequestCultureProvider instead.

namespace Microsoft.AspNet.Localization
{
    /// <summary>
    /// Determines the culture information for a request via values in the route.
    /// </summary>
    public class RouteRequestCultureProvider : RequestCultureProvider
    {
        #region Overrides of RequestCultureProvider

        public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext)
        {
            if (httpContext == null)
            {
                throw new ArgumentNullException(nameof(httpContext));
            }

            var request = httpContext.Request;
            if (!request.Path.HasValue)
            {
                return Task.FromResult((RequestCulture) null);
            }

            var cultureValue = Regex.Match(
                request.Path.Value,
                @"^/([a-z]{2})",
                RegexOptions.IgnoreCase);

            if (cultureValue.Success)
            {
                var culture = CultureInfoCache.GetCultureInfo(cultureValue.Groups[1].Value);
                var uiCulture = CultureInfoCache.GetCultureInfo(cultureValue.Groups[1].Value);

                if (culture == null || uiCulture == null)
                {
                    return Task.FromResult((RequestCulture) null);
                }

                var requestCulture = new RequestCulture(culture, uiCulture);
                requestCulture = ValidateRequestCulture(requestCulture);

                return Task.FromResult(requestCulture);
            }

            return Task.FromResult((RequestCulture) null);
        }

        #endregion
    }
}

Then simply register it in the Configure method:

// Add localization to the request pipeline.
var requestLocalizationOptions = new RequestLocalizationOptions
{
    SupportedCultures = new List<CultureInfo>
    {
        new CultureInfo("en"),
        new CultureInfo("fr"),
        new CultureInfo("es")
    },
    SupportedUICultures = new List<CultureInfo>
    {
        new CultureInfo("en"),
        new CultureInfo("fr"),
        new CultureInfo("es")
    }
};
requestLocalizationOptions.RequestCultureProviders.Insert(2, new RouteRequestCultureProvider
{
    Options = requestLocalizationOptions
});
app.UseRequestLocalization(requestLocalizationOptions);

My route mapping is different from yours, but you can easily modify the code to fit your needs

// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{culture?}/{controller}/{action}/{id?}",
        defaults: new { culture = "en", controller = "Home", action = "Index" });
});
@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 20, 2015

@BenjiZombie thanks for good example.
I do similar in my code https://github.com/WeebDo/WeebDo.CMF/blob/master/src/WeebDoCMF/Startup.cs#L190
I think there no way to get segment {culture} from route for now before

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{culture?}/{controller}/{action}/{id?}",
        defaults: new { culture = "en", controller = "Home", action = "Index" });
});

@BenjiZombie thanks for good example.
I do similar in my code https://github.com/WeebDo/WeebDo.CMF/blob/master/src/WeebDoCMF/Startup.cs#L190
I think there no way to get segment {culture} from route for now before

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{culture?}/{controller}/{action}/{id?}",
        defaults: new { culture = "en", controller = "Home", action = "Index" });
});
@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 20, 2015

@hishamco Thanks I implement my code based on your links 👍
Here question more about how get culture as I do in MVC 5 from Controller

RouteData.Values["culture"] as string;

@hishamco Thanks I implement my code based on your links 👍
Here question more about how get culture as I do in MVC 5 from Controller

RouteData.Values["culture"] as string;
@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

What is the value of ViewBag.Trans when you print it out, because I don't know what is the issue in your sample

Contributor

hishamco commented Oct 20, 2015

What is the value of ViewBag.Trans when you print it out, because I don't know what is the issue in your sample

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 20, 2015

@hishamco There everything work great. My issue is how get route segment from route template before UseMVC middleware. But I think it is not possible. I will try different approach.

@hishamco There everything work great. My issue is how get route segment from route template before UseMVC middleware. But I think it is not possible. I will try different approach.

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

Why you need it before MVC middleware?!! if that's the case i will try to look in your sample

Contributor

hishamco commented Oct 20, 2015

Why you need it before MVC middleware?!! if that's the case i will try to look in your sample

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 20, 2015

@hishamco You are right 👍
I will write own middleware which going to work after UseMVC and set needed culture thread

@hishamco You are right 👍
I will write own middleware which going to work after UseMVC and set needed culture thread

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

All the best @Codenator81 , be free to ask if you have an issue again

Contributor

hishamco commented Oct 20, 2015

All the best @Codenator81 , be free to ask if you have an issue again

@danroth27

This comment has been minimized.

Show comment
Hide comment
@danroth27

danroth27 Oct 20, 2015

Member

@kirthik @DamianEdwards We should look at what our guidance is for using path segments for determining the culture and maybe provide a sample on how to do it.

Member

danroth27 commented Oct 20, 2015

@kirthik @DamianEdwards We should look at what our guidance is for using path segments for determining the culture and maybe provide a sample on how to do it.

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

@danroth27 i provide a simple unit test in https://github.com/aspnet/Localization/blob/dev/test/Microsoft.AspNet.Localization.Tests/CustomRequestCultureProviderTest.cs#L46, also I already suggest #43, if this will help i will make a PR for that

Contributor

hishamco commented Oct 20, 2015

@danroth27 i provide a simple unit test in https://github.com/aspnet/Localization/blob/dev/test/Microsoft.AspNet.Localization.Tests/CustomRequestCultureProviderTest.cs#L46, also I already suggest #43, if this will help i will make a PR for that

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 20, 2015

Middlewares don`t work after UseMVC middleware

Middlewares don`t work after UseMVC middleware

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

@Codenator81 if what you are looking for is in culture segment in "{controller=Home}/{culture=en-US}/{action=Index}/{id?}", I will try to look to into your sample or i will write a code snippet to display the culture segment

Contributor

hishamco commented Oct 20, 2015

@Codenator81 if what you are looking for is in culture segment in "{controller=Home}/{culture=en-US}/{action=Index}/{id?}", I will try to look to into your sample or i will write a code snippet to display the culture segment

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 20, 2015

@hishamco Yes I looking for that.

@hishamco Yes I looking for that.

@damienbod

This comment has been minimized.

Show comment
Hide comment
@damienbod

damienbod Oct 20, 2015

I think this should be an extra default Provider like the others as this is a common use case. What do you think?

Greetings Damien

I think this should be an extra default Provider like the others as this is a common use case. What do you think?

Greetings Damien

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

Ok @Codenator81 I will dig into that
@damienbod as I said before, I already suggest that in #43

Contributor

hishamco commented Oct 20, 2015

Ok @Codenator81 I will dig into that
@damienbod as I said before, I already suggest that in #43

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

@Codenator81 for saving time do you have a repo with the latest changes that you did?

Contributor

hishamco commented Oct 20, 2015

@Codenator81 for saving time do you have a repo with the latest changes that you did?

@damienbod

This comment has been minimized.

Show comment
Hide comment
@damienbod

damienbod Oct 20, 2015

@hishamco

Thanks for your answer, your PR sounds great, I was thinking more of a MVC 6 extension which would allow me to define my culture in the MVC attribute routing.

Greetings Damien

@hishamco

Thanks for your answer, your PR sounds great, I was thinking more of a MVC 6 extension which would allow me to define my culture in the MVC attribute routing.

Greetings Damien

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 20, 2015

Contributor

@damienbod IMHO while there's RequestCultureProvider is out-of-the-box it will be nice to be provider than extension

Contributor

hishamco commented Oct 20, 2015

@damienbod IMHO while there's RequestCultureProvider is out-of-the-box it will be nice to be provider than extension

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 28, 2015

Contributor

@Codenator81 have you look to this sample https://github.com/aspnet/Mvc/tree/9342cb0ab78add8c527edcbc4c0988edc96f01e3/test/WebSites/LocalizationWebSite if you didn't get your answer, I will add a sample demo for that

Contributor

hishamco commented Oct 28, 2015

@Codenator81 have you look to this sample https://github.com/aspnet/Mvc/tree/9342cb0ab78add8c527edcbc4c0988edc96f01e3/test/WebSites/LocalizationWebSite if you didn't get your answer, I will add a sample demo for that

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 28, 2015

@hishamco I see that example long time ago. For now it is outdated? For example app.UseCultureReplacer(); I don`t find (may be removed from code)?
I think there is good example for starters or people who moving from < MVC5.

As I wrote one comment before I looking for segment in Controller. Same people do simelar approach in filter. But for now it is not possible get segment from middleware. I think it is routing feature or issue.
Not Localization.

@hishamco I see that example long time ago. For now it is outdated? For example app.UseCultureReplacer(); I don`t find (may be removed from code)?
I think there is good example for starters or people who moving from < MVC5.

As I wrote one comment before I looking for segment in Controller. Same people do simelar approach in filter. But for now it is not possible get segment from middleware. I think it is routing feature or issue.
Not Localization.

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 28, 2015

Contributor

I see, but as I mentioned before issue #54 and https://github.com/aspnet/Localization/blob/dev/test/Microsoft.AspNet.Localization.Tests/CustomRequestCultureProviderTest.cs#L57 do such thing without using routes, I used segments instead, probably the idea is same. I'm not sure such sample should be in localization repo or mvc?!!
/cc @Eilon

Contributor

hishamco commented Oct 28, 2015

I see, but as I mentioned before issue #54 and https://github.com/aspnet/Localization/blob/dev/test/Microsoft.AspNet.Localization.Tests/CustomRequestCultureProviderTest.cs#L57 do such thing without using routes, I used segments instead, probably the idea is same. I'm not sure such sample should be in localization repo or mvc?!!
/cc @Eilon

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 28, 2015

@hishamco I see all that examples. All of them great 👍 My issue different.
I wrote before:

routes.MapRoute(
         name: "transRoute",
         template: "{controller=Home}/{culture=en-US}/{action=Index}/{id?}");

So I wont detect culture segment if it is at end route or at middle without rewrite code and just get that segment as I do in code there:

string cultureFromRoute = RouteData.Values["culture"] as string;

but segments can be detected only after routes initilized. So there no way get segment in middleware. Hope I explain my issue?

@hishamco I see all that examples. All of them great 👍 My issue different.
I wrote before:

routes.MapRoute(
         name: "transRoute",
         template: "{controller=Home}/{culture=en-US}/{action=Index}/{id?}");

So I wont detect culture segment if it is at end route or at middle without rewrite code and just get that segment as I do in code there:

string cultureFromRoute = RouteData.Values["culture"] as string;

but segments can be detected only after routes initilized. So there no way get segment in middleware. Hope I explain my issue?

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Oct 28, 2015

Contributor

Could you please add a repo summarize your scenario without any other stuff (MiniMVC), i already saw WeebDoCMF but I don't wanna miss on any other stuff 😄

Contributor

hishamco commented Oct 28, 2015

Could you please add a repo summarize your scenario without any other stuff (MiniMVC), i already saw WeebDoCMF but I don't wanna miss on any other stuff 😄

@Codenator81

This comment has been minimized.

Show comment
Hide comment
@Codenator81

Codenator81 Oct 28, 2015

Ok I will do it. May be today evening.

Ok I will do it. May be today evening.

@Eilon Eilon added this to the Backlog milestone Dec 2, 2015

@hishamco

This comment has been minimized.

Show comment
Hide comment
@hishamco

hishamco Aug 20, 2016

Contributor

It's in the way @Codenator81 😄
53a8fa6

Contributor

hishamco commented Aug 20, 2016

It's in the way @Codenator81 😄
53a8fa6

@Eilon Eilon added 1 - Ready and removed needs design labels Aug 20, 2016

@Eilon Eilon modified the milestones: 1.1.0, Backlog Aug 20, 2016

@kichalla kichalla added 2 - Working and removed 1 - Ready labels Aug 23, 2016

@kichalla kichalla added 1 - Ready and removed 2 - Working labels Sep 12, 2016

kichalla added a commit that referenced this issue Sep 24, 2016

Added support for get culture information from request's route data i…
…nformation.

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

kichalla added a commit that referenced this issue Sep 25, 2016

Added support for get culture information from request's route data i…
…nformation.

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

kichalla added a commit that referenced this issue Sep 25, 2016

Added support for get culture information from request's route data i…
…nformation.

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

@kichalla kichalla added 2 - Working and removed 1 - Ready labels Sep 25, 2016

@kichalla kichalla closed this in 861ae52 Sep 30, 2016

@kichalla kichalla added 3 - Done and removed 2 - Working labels Sep 30, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment