任何人都知道一个很好的解决方案来本地化ASP.NET MVC中的路由?我想要实现的是这两个网址指向相同的行动/资源:
此外,应该有可能根据当前文化生成路线(如果没有可用的翻译,则默认生成路线)。或者,如果我能够只指定一种文化,以便上面两个链接中只有一个能够起作用,那么这也是可行的。
我尝试了very nice approach by Maarten Balliauw,但遗憾的是,他的解决方案不适用于Html.RenderAction(...)
。
当然,我可以为所有翻译添加路线,例如
routes.MapRoute(
"Products_Categories",
"Produkte/Kategorien",
new { controller = "Products", action = "Categories" }
);
但这将最终导致大量路线,而且非常不灵活。任何更好的解决方案将不胜感激:-)越灵活越好。
答案 0 :(得分:2)
这可能是一种管理所有路由的可行方法 - 或者它的一些变体,例如在XML文件中定义路由
http://www.iansuttle.com/blog/post/ASPNET-MVC-Store-Routes-in-the-Database.aspx
你仍然会有大量的路线,但管理它们会更容易了
答案 1 :(得分:2)
您可以尝试我刚刚找到的令人敬畏的AttributeRouting项目!你可以通过NuGet获得它。
答案 2 :(得分:1)
可以在https://github.com/boudinov/mvc-5-routing-localization
上找到属性路由和基于常规路由的简单解决方案您可以使用/ de前缀来使用它们,因为它是首选方案。您需要在资源文件中将“产品”和“类别”翻译成德语:
http://example.org/de/Produkte/Kategorien
[LocalizedRoute("~/Products/Categories", translateUrl: true]
ActionResult Index(...)
或者是原始问题的有效答案,没有语言前缀,您可以像这样:
http://example.org/Produkte/Kategorien
[LocalizedRoute("~/Products/Categories", translateUrl: false, explicitCulture: "en")]
[LocalizedRoute("~/Produkte/Kategorien", translateUrl: false, explicitCulture: "de")]
ActionResult Index(...)
答案 3 :(得分:0)
我不确定这是否是正确的方法,至少不是你发布的方式。 网址中应该有一些定义文化的内容,例如:
否则,您最终可能会得到两种或多种语言/文化之间不明确的网址。
答案 4 :(得分:0)
MvcCodeRouting可以选择格式化或翻译路线,请参阅this page。
答案 5 :(得分:0)
尝试使用自定义路线。这比这里介绍的替代方案更灵活。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Routing;
using System.Web;
using System.Web.Mvc;
public class ProductRoute : RouteBase
{
public override RouteData GetRouteData(HttpContextBase httpContext)
{
RouteData result = null;
string virutalPath = httpContext.Request.Url.AbsolutePath.Substring(1).ToLowerInvariant();
// Call the database here to retrieve the productId based off of the virtualPath
var productId = Product.GetProductIdFromVirtualPath(virutalPath);
if (productId != Guid.Empty)
{
result = new RouteData(this, new MvcRouteHandler());
result.Values["controller"] = "Product";
result.Values["action"] = "Details";
result.Values["id"] = productId;
}
return result;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData result = null;
string controller = Convert.ToString(values["controller"]);
string action = Convert.ToString(values["action"]);
if (controller == "Product")
{
string path = string.Empty;
if (action == "Details")
{
Guid productId = (Guid)values["id"];
// Call the database here to get the Virtual Path
var virtualPath = Product.GetVirtualPathFromProductId(productId);
}
if (!String.IsNullOrEmpty(virtualPath))
{
result = new VirtualPathData(this, virtualPath);
}
}
return result;
}
}
您可以通过将路径直接添加到Global.asax中的路由表来使用该路由,如下所示:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"home", // Route name
"", // URL with parameters
new { controller = "Home", action = "Index" } // Parameter defaults
);
// Add your custom route like so
routes.Add(new ProductRoute());
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
}
然后在您的本地化产品表上,只需要一个包含查找路径的字段(不带前导斜杠)。当然,您没有提到如何存储数据,所以您必须自己提出。
此外,您需要通过将其解析出virtualPath来处理本地化。根据谷歌的说法,它应该在那里。您应该根据传递的标题处理初始文化,并将其重定向(302)到所选文化的URL。然后用户应该能够切换语言,在这种情况下,您可以将其放入cookie中,以便记住他们的偏好。但是,搜索引擎应该能够通过URL告知文化而不传递任何标题。
这将通过GetVirtualPath()方法处理@ Html.RenderAction()的情况,如果需要,您可以更改逻辑。我建议你添加缓存,因为这会使每个请求按原样命中数据库。路径表在应用启动时填充,但每个路由都在每个请求上执行。
还有一件事 - 要处理“路由不匹配”的情况,只需返回null,路由器将继续前进到下一个配置的路由。这允许您根据需要配置任意数量的自定义路由,而无需混合逻辑。