Dresel / RouteLocalization

RouteLocalization is an MVC and Web API package that allows localization of your attribute routes.
MIT License
67 stars 13 forks source link

Disable Route translation in API not working #47

Closed mdmoura closed 9 years ago

mdmoura commented 9 years ago

Hello,

I am working on a project to which I will add route localization in the future. I decided to add RouteLocalization to API routes now but in a way that wouldn't do anything:

  GlobalConfiguration.Configure(y => y.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider));

  GlobalConfiguration.Configuration.ContinueAfterPreviousInitialization(x => {
    x.Routes.Localization(y => {
      y.AcceptedCultures = new HashSet<String>(new String[] { "en" });
      y.DefaultCulture = "en";
      y.AttributeRouteProcessing = RouteLocalization.Http.Setup.AttributeRouteProcessing.None;
      y.AddCultureAsRoutePrefix = false;
      y.AddTranslationToSimiliarUrls = false;
    }).TranslateInitialAttributeRoutes().Translate(y => {  });
  });

  GlobalConfiguration.Configuration.MessageHandlers.Add(new CultureSensitiveMessageHandler() {
    GetCultureFromHttpRequestMessageDelegate = x => new CultureInfo("en")
  });

  GlobalConfiguration.Configuration.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

When I called the Api routes I got 404 errors. I switched to API setup:

  GlobalConfiguration.Configure(x => x.MapHttpAttributeRoutes());

In this case everything works fine ... Any idea what might be wrong?

Thank You, Miguel

Dresel commented 9 years ago

You are not adding any routes. Use a different AttributeRouteProcessing setting (if you don't want localizations yet, use AddAsNeutralRoute), or add some translations manually.

mdmoura commented 9 years ago

Yes, I tried that ... Let me show what I have for MVC and which is working fine:

RouteTable.Routes.MapMvcAttributeRoutes(Localization.LocalizationDirectRouteProvider);

RouteTable.Routes.Localization(x => {
    x.AcceptedCultures = new HashSet<String>(new String[] { "en" });
    x.DefaultCulture = "en";
    x.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
    x.AddCultureAsRoutePrefix = false;
    x.AddTranslationToSimiliarUrls = false;
  }).TranslateInitialAttributeRoutes().Translate(z => z.Process());

  CultureSensitiveHttpModule.GetCultureFromHttpContextDelegate = ctx => new CultureInfo("en") 

  GlobalFilters.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

So in this case the routes I defined in attributes are being used.

Now I used something similar to Web API but I always get 404 errors:

  GlobalConfiguration.Configure(y => y.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider));

  GlobalConfiguration.Configuration.ContinueAfterPreviousInitialization(x => {
    x.Routes.Localization(y => {
      x.AcceptedCultures = new HashSet<String>(new String[] { "en" });
      x.DefaultCulture = "en";
      y.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
      y.AddCultureAsRoutePrefix = false;
      y.AddTranslationToSimiliarUrls = false;
    }).TranslateInitialAttributeRoutes().Translate(y => y.Process());
  });

  GlobalConfiguration.Configuration.MessageHandlers.Add(new CultureSensitiveMessageHandler() {
    GetCultureFromHttpRequestMessageDelegate = message => new CultureInfo("en")
  });

  GlobalConfiguration.Configuration.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

NOTE

In both cases process is just an extension that, at the moment, does nothing:

public static void Process(this Localization localization) { }

Any idea why this is working fine for MVC and not for Web API?

If I replace Route Localization configuration for Web Api by:

GlobalConfiguration.Configure(x => x.MapHttpAttributeRoutes());

Then everything works fine ...

Thank You, Miguel

Dresel commented 9 years ago

Which WebAPI version are you using? Is it a WebAPI only project or are you mixing MVC + WebApi?

Can you verify that configuration.LocalizationCollectionRoutes (within the x.Routes.Localization callback) contains your WebAPI routes?

You may want to post your complete RouteConfig.cs.

mdmoura commented 9 years ago

I have been trying to solve this but no luck ...

This is a MVC 5.2.3 + Web API 5.2.3 project.

I checked and the API routes are being added ... But I always get a 404 error when using Route Localization.

I have the following route configuration:

MVC

  RouteTable.Routes.MapMvcAttributeRoutes(Localization.LocalizationDirectRouteProvider);

  RouteTable.Routes.Localization(x => {
      x.AcceptedCultures = new HashSet<String>(new String[] { "en", "pt" });
      x.DefaultCulture = "en";
      x.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
      x.AddCultureAsRoutePrefix = false;
      x.AddTranslationToSimiliarUrls = false;
    }).TranslateInitialAttributeRoutes().Translate(z => z.Process());

  CultureSensitiveHttpModule.GetCultureFromHttpContextDelegate = ctx => new CultureInfo("en");

  GlobalFilters.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

  RouteTable.Routes.MapRoute("Start", String.Empty, new { controller = "Home", action = "Start" }, new[] { MVCSite.Controllers" });

  RouteTable.Routes.MapRoute("404", "{*url}", new { controller = "Error", action = "NotFound_" });

  AreaRegistration.RegisterAllAreas();

WEB API

  GlobalConfiguration.Configure(y => y.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider));

  GlobalConfiguration.Configuration.ContinueAfterPreviousInitialization(x => {
    x.Routes.Localization(y => {
      y.AcceptedCultures = new HashSet<String>(new String[] { "en", "pt" });
      y.DefaultCulture = "en";
      y.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
      y.AddCultureAsRoutePrefix = false;
      y.AddTranslationToSimiliarUrls = false;
    }).TranslateInitialAttributeRoutes().Translate(y => y.Process());
  });

  GlobalConfiguration.Configuration.MessageHandlers.Add(new CultureSensitiveMessageHandler() {
    GetCultureFromHttpRequestMessageDelegate = message => new CultureInfo("en")
  });

  GlobalConfiguration.Configuration.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

Does this help?

Dresel commented 9 years ago

Is this setup within one file (MVC + WebAPI)? Maybe its a namespace issue. If so, please post the complete content of your RouteConfig.cs (or whatever it is called)...

mdmoura commented 9 years ago

To avoid namespace problems I have the two setups in different files.

Web API

using RouteLocalization.Http;
using RouteLocalization.Http.Extensions;
using RouteLocalization.Http.Setup;
using SusanaValdez.Base;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.Http;

public static class ApiRoute {

  public static void Setup() {

      GlobalConfiguration.Configure(y => y.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider));

      GlobalConfiguration.Configuration.ContinueAfterPreviousInitialization(x => {
        x.Routes.Localization(y => {
          y.AcceptedCultures = new HashSet<String>(new String[] { "en", "pt" });
          y.DefaultCulture = "en";
          y.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
          y.AddCultureAsRoutePrefix = true;
          y.AddTranslationToSimiliarUrls = true;
        }).TranslateInitialAttributeRoutes().Translate(y => y.Process());
    });

        GlobalConfiguration.Configuration.MessageHandlers.Add(new CultureSensitiveMessageHandler() {
        GetCultureFromHttpRequestMessageDelegate = message => new CultureInfo("en")
   });

     GlobalConfiguration.Configuration.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));
  }
}

MVC

using RouteLocalization.Mvc;
using RouteLocalization.Mvc.Extensions;
using RouteLocalization.Mvc.Setup;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Web.Mvc;
using System.Web.Routing;

public static class MvcRoute {

  public static void Setup() {

    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("{*favicon}", new { favicon = @"(.*/)?favicon.([iI][cC][oO]|[gG][iI][fF])(/.*)?" });

    RouteTable.Routes.MapMvcAttributeRoutes(Localization.LocalizationDirectRouteProvider);

    RouteTable.Routes.Localization(x => {
        x.AcceptedCultures = new HashSet<String>(new String[] { "en", "pt" });
        x.DefaultCulture = "en";
        x.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
        x.AddCultureAsRoutePrefix = true;
        x.AddTranslationToSimiliarUrls = true;
      }).TranslateInitialAttributeRoutes().Translate(z => z.Process());

      CultureSensitiveHttpModule.GetCultureFromHttpContextDelegate = ctx => new CultureInfo("en");

     GlobalFilters.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

     RouteTable.Routes.MapRoute("Start", String.Empty, new { controller = "Home", action = "Start" }, new[] { "MVCSite.Controllers"" });

  }
}

And I call both methods from application start.

Dresel commented 9 years ago

And how does your WebAPI Controller look like?

You are using RouteAttributes and not the default API route?

config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

Maybe you can upload a sample repository, that will be easier than remote guessing :)

Dresel commented 9 years ago

When you use your setup like this, does the ContinueAfterPreviousInitialization callback ever gets executed? I tried to use your code and it doesn't...

I would suggest using the configuration instance like in the web api project template or the RouteLocalization sample project:

// Global.asax.cs
GlobalConfiguration.Configure(WebApiConfig.Register);

// WebApiConfig.cs
public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Only work with config object instance

If you still want to stick with your static code, try to use

GlobalConfiguration.Configuration.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider);

GlobalConfiguration.Configuration.ContinueAfterPreviousInitialization(localization => {

or

GlobalConfiguration.Configure(y =>
{
    y.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider);

    y.ContinueAfterPreviousInitialization(x => {
mdmoura commented 9 years ago

Finally, now it works following your suggestion:

    GlobalConfiguration.Configure(x => {

      x.MapHttpAttributeRoutes(Localization.LocalizationDirectRouteProvider);

      x.ContinueAfterPreviousInitialization(y => {
        y.Routes.Localization(z => {
          z.AcceptedCultures = new HashSet<String>(new String[] { "en", "pt" });
          z.DefaultCulture = "en";
          z.AttributeRouteProcessing = AttributeRouteProcessing.AddAsDefaultCultureRoute;
          z.AddCultureAsRoutePrefix = true;
          z.AddTranslationToSimiliarUrls = true;
        }).TranslateInitialAttributeRoutes().Translate(w => w.Process());
      });

      x.MessageHandlers.Add(new CultureSensitiveMessageHandler() {
        GetCultureFromHttpRequestMessageDelegate = message => new CultureInfo("en")
      });

      x.Filters.Add(new CultureSensitiveActionFilterAttribute(true, true));

    });

Thanks!