C# ASP.NET MVC 5中的本地化路由无意中重定向到主页
我正在为一个已经在ASP.NET MVC 5中发布的网站配置本地化 我遵循的将本地化集成到我的站点的指南来自codeproject,我发现它非常好: 现在,为了解释这个问题,每当我加载主页索引C# ASP.NET MVC 5中的本地化路由无意中重定向到主页,c#,asp.net,asp.net-mvc,C#,Asp.net,Asp.net Mvc,我正在为一个已经在ASP.NET MVC 5中发布的网站配置本地化 我遵循的将本地化集成到我的站点的指南来自codeproject,我发现它非常好: 现在,为了解释这个问题,每当我加载主页索引http://www.example.com/如果没有路由路径,它将重定向到正确的语言http://www.example.com/en这是所需的结果 我的网站URL的格式为http://www.example.com/controller/action。每当我访问http://www.example.co
http://www.example.com/
如果没有路由路径,它将重定向到正确的语言http://www.example.com/en
这是所需的结果
我的网站URL的格式为http://www.example.com/controller/action
。每当我访问http://www.example.com/controller/
它现在会将我重定向回http://www.example.com/en
而不是http://www.example.com/en/controller/index
。当我试着输入http://www.example.com/controller/action
它抛出404错误,而不是http://www.example.com/en/controller/action
我认为问题出在LocalizationHelper.cs
文件中的GetLocalistedUrl
函数中
public static string GetLocalisedUrl(Uri initialUri, IList<string> controllersNames, IList<string> userLangs)
{
var res = string.Empty;
var supportedLocales = GetSupportedLocales();
var origUrl = initialUri;
// Dicide requested url to parts
var cleanedSegments = origUrl.Segments.Select(X => X.Replace("/", "")).ToList();
// Check is already supported locale defined in route
// cleanedSegments[0] is empty string, so lang parameter will be in [1] url segment
var isLocaleDefined = cleanedSegments.Count > 1 && supportedLocales.Contains(cleanedSegments[1]);
// does request need to be changed
var isRequestPathToHandle =
// Url has controller's name part
(cleanedSegments.Count > 1 && cleanedSegments.Intersect(controllersNames).Count() > 0) ||
// This condition is for default (initial) route
(cleanedSegments.Count == 1) ||
// initial route with lang parameter that is not supported -> need to change it
(cleanedSegments.Count == 2 && !supportedLocales.Contains(cleanedSegments[1]));
if (!isLocaleDefined && isRequestPathToHandle)
{
var langVal = "";
// Get user preffered language from Accept-Language header
if (userLangs != null && userLangs.Count > 0)
{
// For our locale name approach we'll take only first part of lang-locale definition
var splitted = userLangs[0].Split(new char[] { '-' });
langVal = splitted[0];
}
// If we don't support requested language - then redirect to requested page with default language
if (!supportedLocales.Contains(langVal))
langVal = supportedLocales[0];
var normalisedPathAndQuery = origUrl.PathAndQuery;
if ((cleanedSegments.Count > 2 &&
!controllersNames.Contains(cleanedSegments[1]) &&
controllersNames.Contains(cleanedSegments[2])) ||
(cleanedSegments.Count == 2) && (!controllersNames.Contains(cleanedSegments[1])))
{
// Second segment contains lang parameter, third segment contains controller name
cleanedSegments.RemoveAt(1);
// Remove wrong locale name from initial Uri
normalisedPathAndQuery = string.Join("/", cleanedSegments) + origUrl.Query;
}
// Finally, create new uri with language loocale
res = string.Format("{0}://{1}:{2}/{3}{4}", origUrl.Scheme, origUrl.Host, origUrl.Port, langVal.ToLower(), normalisedPathAndQuery);
}
return res;
}
公共静态字符串GetLocalisedUrl(Uri初始Uri、IList控制器名称、IList用户语言)
{
var res=string.Empty;
var supportedLocales=GetSupportedLocales();
var origUrl=initialUri;
//Dicide请求的零件url
var cleanedSegments=origUrl.Segments.Select(X=>X.Replace(“/”,“”)).ToList();
//路由中已定义了支持的区域设置
//cleanedSegments[0]是空字符串,因此lang参数将位于[1]url段中
var isLocaleDefined=cleanedSegments.Count>1&&supportedLocales.Contains(cleanedSegments[1]);
//请求是否需要更改
var isRequestPathToHandle=
//Url包含控制器的名称部分
(cleanedSegments.Count>1&&cleanedSegments.Intersect(controllersNames.Count()>0)||
//此条件适用于默认(初始)路线
(cleanedSegments.Count==1)||
//不支持lang参数的初始路由->需要更改它
(cleanedSegments.Count==2&&!supportedLocales.Contains(cleanedSegments[1]);
如果(!isLocaleDefined&&isRequestPathToHandle)
{
var langVal=“”;
//从Accept language标头获取用户首选的语言
if(userLangs!=null&&userLangs.Count>0)
{
//对于我们的语言环境名称方法,我们只使用语言环境定义的第一部分
var splitted=userLangs[0]。拆分(新字符[]{'-});
langVal=splitted[0];
}
//如果我们不支持请求的语言,则使用默认语言重定向到请求的页面
如果(!supportedLocales.Contains(langVal))
langVal=supportedLocales[0];
var normalisedPathAndQuery=origUrl.PathAndQuery;
如果((cleanedSegments.Count>2&&
!controllersNames.Contains(已清除的段[1])&&
controllersNames.Contains(cleanedSegments[2]))||
(cleanedSegments.Count==2)和(!controllersNames.Contains(cleanedSegments[1]))
{
//第二段包含lang参数,第三段包含控制器名称
清除段。移除(1);
//从初始Uri中删除错误的区域设置名称
normalisedPathAndQuery=string.Join(“/”,cleanedSegments)+origUrl.Query;
}
//最后,使用loocale语言创建新的uri
res=string.Format(“{0}://{1}:{2}/{3}{4}”,origUrl.Scheme,origUrl.Host,origUrl.Port,langVal.ToLower(),normalisedPathAndQuery);
}
返回res;
}
该函数在创建的IHttpModule扩展中调用
public class LangQueryAppenderModule : IHttpModule
{
/// <summary>
/// List of supported locales
/// </summary>
private readonly IList<string> _supportedLocales;
/// <summary>
/// We need to have controllers list to correctly handle situations
/// when target method name is missed
/// </summary>
private readonly IList<string> _controllersNamesList;
public LangQueryAppenderModule()
{
// Get list of supported locales
_supportedLocales = LocalizationHelper.GetSupportedLocales();
// Get controllers list of current project by reflection
var asmPath = HttpContext.Current.Server.MapPath("~/bin/Central.dll");
Assembly asm = Assembly.LoadFile(asmPath);
var controllerTypes = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type));
_controllersNamesList = new List<string>();
foreach (var controllerType in controllerTypes)
{
var fullName = controllerType.Name;
// We need only name part of Controller class that is used in route
_controllersNamesList.Add(fullName.Substring(0, fullName.Length - "Controller".Length));
}
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source, EventArgs e)
{
try
{
HttpApplication app = (HttpApplication)source;
HttpContext ctx = app.Context;
// We will redirect to url with defined locale only in case for HTTP GET verb
// cause we assume that all requests with other verbs will be called from site directly
// where all the urls created with URLHelper, so it complies with routing rules and will contain "lang" parameter
if (string.Equals(ctx.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
var localisedUri = LocalizationHelper.GetLocalisedUrl(ctx.Request.Url, _controllersNamesList, ctx.Request.UserLanguages);
if (!string.IsNullOrEmpty(localisedUri))
// Perform redirect action to changed url if it exists
ctx.Response.Redirect(localisedUri);
}
}
catch (Exception)
{
// Some logging logic could be here
}
}
public void Dispose() { }
}
公共类LangQueryAppenderModule:IHttpModule
{
///
///支持的区域设置列表
///
私有只读IList_支持的Locales;
///
///我们需要有控制器列表来正确处理情况
///缺少目标方法名称时
///
私有只读IList_控制器名称列表;
公共LangQueryAppenderModule()
{
//获取支持的区域设置列表
_supportedLocales=LocalizationHelper.GetSupportedLocales();
//通过反射获取当前项目的控制器列表
var asmPath=HttpContext.Current.Server.MapPath(“~/bin/Central.dll”);
Assembly asm=Assembly.LoadFile(asmPath);
var controllerTypes=asm.GetTypes()
其中(type=>typeof(Controller).IsAssignableFrom(type));
_controllersNamesList=新列表();
foreach(controllerTypes中的var controllerType)
{
var fullName=controllerType.Name;
//我们只需要命名路由中使用的控制器类的一部分
_添加(fullName.Substring(0,fullName.Length—“Controller.Length”);
}
}
//在Init函数中,注册HttpApplication
//事件,通过添加处理程序。
public void Init(HttpApplication应用程序)
{
application.BeginRequest+=(新的EventHandler(this.application_BeginRequest));
}
私有void应用程序_BeginRequest(对象源,事件参数e)
{
尝试
{
HttpApplication应用程序=(HttpApplication)源;
HttpContext ctx=app.Context;
//仅在HTTP GET动词的情况下,我们将重定向到具有已定义语言环境的url
//因为我们假设所有带有其他谓词的请求都将直接从站点调用
//其中所有URL都是使用URLHelper创建的,因此它符合路由规则并将包含“lang”参数
if(string.Equals(ctx.Request.HttpMethod,“GET”,StringComparison.OrdinalIgnoreCase))
{
var localisedUri=Loc
public static string GetLocalisedUrl(Uri initialUri, IList<string> controllersNames, IList<string> userLangs)
{
var res = string.Empty;
var supportedLocales = GetSupportedLocales();
var origUrl = initialUri;
// Dicide requested url to parts
var cleanedSegments = origUrl.Segments.Select(X => X.Replace("/", "")).ToList();
// Check is already supported locale defined in route
// cleanedSegments[0] is empty string, so lang parameter will be in [1] url segment
var isLocaleDefined = cleanedSegments.Count > 1 && supportedLocales.Contains(cleanedSegments[1]);
cleanedSegments = cleanedSegments.ConvertAll(d => d.ToLower());
// does request need to be changed
var isRequestPathToHandle =
// Url has controller's name part
(cleanedSegments.Count > 1 && cleanedSegments.Intersect(controllersNames).Count() > 0) ||
// This condition is for default (initial) route
(cleanedSegments.Count == 1) ||
// initial route with lang parameter that is not supported -> need to change it
(cleanedSegments.Count == 2 && !supportedLocales.Contains(cleanedSegments[1]));
if (!isLocaleDefined && isRequestPathToHandle)
{
var langVal = "";
// Get user preffered language from Accept-Language header
if (userLangs != null && userLangs.Count > 0)
{
// For our locale name approach we'll take only first part of lang-locale definition
var splitted = userLangs[0].Split(new char[] { '-' });
langVal = splitted[0];
}
// If we don't support requested language - then redirect to requested page with default language
if (!supportedLocales.Contains(langVal))
langVal = supportedLocales[0];
var normalisedPathAndQuery = origUrl.PathAndQuery;
if ((cleanedSegments.Count > 2 &&
!controllersNames.Contains(cleanedSegments[1].ToLower()) &&
controllersNames.Contains(cleanedSegments[2].ToLower())) ||
(cleanedSegments.Count == 2) && (!controllersNames.Contains(cleanedSegments[1])))
{
// Second segment contains lang parameter, third segment contains controller name
cleanedSegments.RemoveAt(1);
// Remove wrong locale name from initial Uri
normalisedPathAndQuery = string.Join("/", cleanedSegments) + origUrl.Query;
}
// Finally, create new uri with language loocale
res = string.Format("{0}://{1}:{2}/{3}{4}", origUrl.Scheme, origUrl.Host, origUrl.Port, langVal.ToLower(), normalisedPathAndQuery.ToLower());
}
return res;
}