使用 MVC 的属性路由和 RouteLocalization.mvc 的特定语言默认值 URL

Language-specific Default URL using MVC's Attribute Routing and RouteLocalization.mvc

我希望能够为我的网站创建一个简洁的特定于语言的默认值 URL,以便当有人浏览时:

somesite.com

他们被重定向到语言文化页面,例如:

具体来说,我想要/Home/Index附加到URLs:

我承诺使用 RouteLocalization.mvc

制作此网站

我想在可行的范围内使用 MVC 属性路由

我无法弄清楚如何在不添加 "index".

之类的情况下使 Start() 方法重定向到特定于语言文化的 URL

我尝试过的示例如下:

using RouteLocalization.Mvc;
using RouteLocalization.Mvc.Extensions;
using RouteLocalization.Mvc.Setup;

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.Clear();

        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapMvcAttributeRoutes(Localization.LocalizationDirectRouteProvider);

        const string en = "en-us";
        ISet<string> acceptedCultures = new HashSet<string>() { en, "de", "fr", "es", "it" };

        routes.Localization(configuration =>
        {
            configuration.DefaultCulture = en;
            configuration.AcceptedCultures = acceptedCultures;
            configuration.AttributeRouteProcessing = AttributeRouteProcessing.AddAsNeutralAndDefaultCultureRoute;
            configuration.AddCultureAsRoutePrefix = true;
            configuration.AddTranslationToSimiliarUrls = true;
        }).TranslateInitialAttributeRoutes().Translate(localization =>
        {
            localization.AddRoutesTranslation();
        });

        CultureSensitiveHttpModule.GetCultureFromHttpContextDelegate = Localization.DetectCultureFromBrowserUserLanguages(acceptedCultures, en);

        var defaultCulture = System.Threading.Thread.CurrentThread.CurrentUICulture.Name;

        routes.MapRoute(
            name: "DefaultLocalized",
            url: "{culture}/{controller}/{action}/{id}",
            constraints: new { culture = @"(\w{2})|(\w{2}-\w{2})" }, 
            defaults: new { culture = defaultCulture, controller = "Home", action = "Index", id = UrlParameter.Optional }
        );

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

还有我的家庭控制器:

public class HomeController : Controller
{
    [HttpGet]
    [Route]
    public RedirectToRouteResult Start()
    {
        return RedirectToAction("Home", new { culture = Thread.CurrentThread.CurrentCulture.Name });
    }

    [Route("Index", Name = "Home.Index")]
    public ActionResult Index()
    {
        return View();
    }

    public ActionResult Contact()
    {
        return View();
    }

    public ActionResult About()
    {
        return View();
    }
}

我的 Global.asax 文件:

public class MvcApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {            
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        AreaRegistration.RegisterAllAreas();
    }
}

重定向与路由相比是一个单独的问题。由于您将 any URL 重定向到其本地化对象的目标是一个横切关注点,因此您最好的选择是制作一个全局过滤器。

public class RedirectToUserLanguageFilter : IActionFilter
{
    private readonly string defaultCulture;
    private readonly IEnumerable<string> supportedCultures;

    public RedirectToUserLanguageFilter(string defaultCulture, IEnumerable<string> supportedCultures)
    {
        if (string.IsNullOrEmpty(defaultCulture))
            throw new ArgumentNullException("defaultCulture");
        if (supportedCultures == null || !supportedCultures.Any())
            throw new ArgumentNullException("supportedCultures");

        this.defaultCulture = defaultCulture;
        this.supportedCultures = supportedCultures;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var routeValues = filterContext.RequestContext.RouteData.Values;

        // If there is no value for culture, redirect
        if (routeValues != null && !routeValues.ContainsKey("culture"))
        {
            string culture = this.defaultCulture;
            var userLanguages = filterContext.HttpContext.Request.UserLanguages;
            if (userLanguages.Length > 0)
            {
                foreach (string language in userLanguages.SelectMany(x => x.Split(';')))
                {
                    // Check whether language is supported before setting it.
                    if (supportedCultures.Contains(language))
                    {
                        culture = language;
                        break;
                    }
                }
            }

            // Add the culture to the route values
            routeValues.Add("culture", culture);

            filterContext.Result = new RedirectToRouteResult(routeValues);
        }
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // Do nothing
    }
}

用法

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new RedirectToUserLanguageFilter("en", new string[] { "en", "de", "fr", "es", "it" }));
        filters.Add(new HandleErrorAttribute());
    }
}

另请注意,您的路由配置有误。路由设置是 运行 每个应用程序启动一次,因此将默认文化设置为当前线程的文化是没有意义的。事实上,你根本不应该为你的文化路线设置默认文化,因为你希望它错过所以你的 Default 路线将在没有文化设置的情况下执行。

routes.MapRoute(
    name: "DefaultLocalized",
    url: "{culture}/{controller}/{action}/{id}",
    constraints: new { culture = @"(\w{2})|(\w{2}-\w{2})" },
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);