title: Optionally override request culture via url/route in an ASP.NET Core 1.0 Application
body: <p>I am trying to override the culture of the current request. I got it working partly using a custom <code>ActionFilterAttribute</code>.</p>
  
  
  
  <pre class="lang-cs prettyprint-override"><code>public sealed class LanguageActionFilter : ActionFilterAttribute
  {
      private readonly ILogger logger;
      private readonly IOptions&lt;RequestLocalizationOptions&gt; localizationOptions;
  
      public LanguageActionFilter(ILoggerFactory loggerFactory, IOptions&lt;RequestLocalizationOptions&gt; options)
      {
          if (loggerFactory == null)
              throw new ArgumentNullException(nameof(loggerFactory));
  
          if (options == null)
              throw new ArgumentNullException(nameof(options));
  
          logger = loggerFactory.CreateLogger(nameof(LanguageActionFilter));
          localizationOptions = options;
      }
  
      public override void OnActionExecuting(ActionExecutingContext context)
      {
          string culture = context.RouteData.Values["culture"]?.ToString();
  
          if (!string.IsNullOrWhiteSpace(culture))
          {
              logger.LogInformation($"Setting the culture from the URL: {culture}");
  
  #if DNX46
              System.Threading.Thread.CurrentThread.CurrentCulture = new CultureInfo(culture);
              System.Threading.Thread.CurrentThread.CurrentUICulture = new CultureInfo(culture);
  #else
              CultureInfo.CurrentCulture = new CultureInfo(culture);
              CultureInfo.CurrentUICulture = new CultureInfo(culture);
  #endif
          }
  
          base.OnActionExecuting(context);
      }
  }
  </code></pre>
  
  <p>On the controller I use the <code>LanguageActionFilter</code>.</p>
  
  <pre class="lang-cs prettyprint-override"><code>[ServiceFilter(typeof(LanguageActionFilter))]
  [Route("api/{culture}/[controller]")]
  public class ProductsController : Controller
  {
      ...
  }
  </code></pre>
  
  <p>This works so far, but I have two issues with it: </p>
  
  <ol>
  <li>I don't like having to declare <code>{culture}</code> on every controller, as I am going to need it on every route. </li>
  <li>I having a default culture doesn't work with this approach, even if I declare it as <code>[Route("api/{culture=en-US}/[controller]")]</code> for obvious reasons. </li>
  </ol>
  
  <p>Setting a default route results is not working neither. </p>
  
  <pre class="lang-cs prettyprint-override"><code>app.UseMvc( routes =&gt;
  {
      routes.MapRoute(
          name: "DefaultRoute",
          template: "api/{culture=en-US}/{controller}"
      );
  });
  </code></pre>
  
  <p>I also investigated in a custom <code>IRequestCultureProvider</code> implementation and add it to the <code>UseRequestLocalization</code> method like </p>
  
  <pre class="lang-cs prettyprint-override"><code>app.UseRequestLocalization(new RequestLocalizationOptions
  {
      RequestCultureProviders = new List&lt;IRequestCultureProvider&gt;
      {
          new UrlCultureProvider()
      },
      SupportedCultures = new List&lt;CultureInfo&gt;
      {
          new CultureInfo("de-de"),
          new CultureInfo("en-us"),
          new CultureInfo("en-gb")
      },
      SupportedUICultures = new List&lt;CultureInfo&gt;
      {
          new CultureInfo("de-de"),
          new CultureInfo("en-us"),
          new CultureInfo("en-gb")
      }
  }, new RequestCulture("en-US"));
  </code></pre>
  
  <p>but then I don't have access to the routes there (I assume cause the routes are done later in the pipeline). Of course I could also try to parse the requested url. And I don't even know if I could change the route at this place so it would match the above route with the culture in it. </p>
  
  <p>Passing the culture via query parameter or changing the order of the parameters inside the route is not an option. </p>
  
  <p>Both urls <code>api/en-us/products</code> as we as <code>api/products</code> should route to the same controller, where the former don't change the culture. </p>
  
  <p>The order in which the culture will be determined should be</p>
  
  <ol>
  <li>If defined in url, take it</li>
  <li>If not defined in url, check query string and use that</li>
  <li>If not defined in query, check cookies</li>
  <li>If not defined in cookie, use <code>Accept-Language</code> header. </li>
  </ol>
  
  <p>2-4 is done via <code>UseRequestLocalization</code> and that works. Also I don't like the current approach having to add two attributes to each controller (<code>{culture}</code> in route and the <code>[ServiceFilter(typeof(LanguageActionFilter))]</code>).</p>
  
  <p><strong>Edit:</strong>
  I also like to limit the number of valid locales to the one set in <code>SupportedCultures</code> property of the <code>RequestLocalizationOptions</code> passed to the <code>UseRequestLocalization</code>.</p>
  
  <p><code>IOptions&lt;RequestLocalizationOptions&gt; localizationOptions</code> in the <code>LanguageActionFilter</code> above doesn't work as it returns a new instance of <code>RequestLocalizationOptions</code> where <code>SupportedCultures</code> is always <code>null</code> and not the one passed to the.</p>
  
  <p>FWIW it's an RESTful WebApi project.</p>