C# 为什么我会收到例外情况;在控制器“上未找到公共操作方法”;?
我使用下面的文章来支持多文化路线 如果您查看“注册路由”部分,您将看到当前路由(在“RegisterRoutes”方法中)用“{culture}”段更新 不同之处在于,我希望保留当前路由,并为每个路由添加一个重复的“{culture}”段,因此对于像“foo/bar”这样的路由,我将获得一个重复的“{culture}/foo/bar” 你可以看到,我也在确保新路线优先C# 为什么我会收到例外情况;在控制器“上未找到公共操作方法”;?,c#,asp.net-mvc,exception,routing,C#,Asp.net Mvc,Exception,Routing,我使用下面的文章来支持多文化路线 如果您查看“注册路由”部分,您将看到当前路由(在“RegisterRoutes”方法中)用“{culture}”段更新 不同之处在于,我希望保留当前路由,并为每个路由添加一个重复的“{culture}”段,因此对于像“foo/bar”这样的路由,我将获得一个重复的“{culture}/foo/bar” 你可以看到,我也在确保新路线优先 public static void MapMvcMultiCultureAttributes(this RouteCollec
public static void MapMvcMultiCultureAttributes(this RouteCollection routes, bool inheritedRoutes = true, string defaultCulture = "en-US", string cultureCookieName = "culture")
{
routes.MapMvcAttributeRoutes(inheritedRoutes ? new InheritedRoutesProvider() : null);
var multiCultureRouteHandler = new MultiCultureMvcRouteHandler(defaultCulture, cultureCookieName);
var initialList = routes.ToList();
routes.Clear();
foreach (var routeBase in initialList)
{
var route = routeBase as Route;
if (route != null)
{
if (route.Url.StartsWith("{culture}"))
{
continue;
}
var cultureUrl = "{culture}";
if (!String.IsNullOrWhiteSpace(route.Url))
{
cultureUrl += "/" + route.Url;
}
var cultureRoute = routes.MapRoute(null, cultureUrl, null, new
{
culture = "^\\D{2,3}(-\\D{2,3})?$"
});
cultureRoute.Defaults = route.Defaults;
cultureRoute.DataTokens = route.DataTokens;
foreach (var constraint in route.Constraints)
{
cultureRoute.Constraints.Add(constraint.Key, constraint.Value);
}
cultureRoute.RouteHandler = multiCultureRouteHandler;
route.RouteHandler = multiCultureRouteHandler;
}
routes.Add(routeBase);
}
}
“InheritedRoutesProvider”如下所示:
private class InheritedRoutesProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(ActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes(typeof(IDirectRouteFactory), true)
.Cast<IDirectRouteFactory>()
.ToArray();
}
}
public class MyBaseController: Controller
{
[HttpGet]
[Route("bar")]
public virtual ActionResult MyAction(){
{
return Content("Hello stranger!");
}
}
[RoutePrefix("foo")]
public class MyController: MyBaseController
{
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcMultiCultureAttributes();
routes.LowercaseUrls = true;
}
我的“RegisterRoutes”方法如下所示:
private class InheritedRoutesProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory> GetActionRouteFactories(ActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes(typeof(IDirectRouteFactory), true)
.Cast<IDirectRouteFactory>()
.ToArray();
}
}
public class MyBaseController: Controller
{
[HttpGet]
[Route("bar")]
public virtual ActionResult MyAction(){
{
return Content("Hello stranger!");
}
}
[RoutePrefix("foo")]
public class MyController: MyBaseController
{
}
public static void RegisterRoutes(RouteCollection routes)
{
routes.MapMvcMultiCultureAttributes();
routes.LowercaseUrls = true;
}
现在,如果我这样做:
- /foo/bar-工作李>
- /en US/foo/bar-HttpException在控制器“MyController”上未找到公共操作方法“MyAction”
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
string cultureName = RouteData.Values["culture"] as string;
if (cultureName == null)
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ?
Request.UserLanguages[0] : // obtain it from HTTP header AcceptLanguages
null;
// Validate culture name
cultureName = CultureHelper.GetImplementedCulture(cultureName); // This is safe
if (RouteData.Values["culture"] as string != cultureName)
{
// Force a valid culture in the URL
RouteData.Values["culture"] = cultureName.ToLower(); // lower case too
// Redirect user
Response.RedirectToRoute(RouteData.Values);
}
// Modify current thread's cultures
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback, state);
}
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Custom",
url: "{controller}/{action}/{culture}",
defaults: new { culture = CultureHelper.GetDefaultCulture(), controller = "Coordinate", action = "Index" }
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Custom",
url: "{controller}/{action}/{culture}",
defaults: new { culture = CultureHelper.GetDefaultCulture(), controller = "Coordinate", action = "Index" }
公共静态类CultureHelper
{
私有静态只读列表_cultures=新列表{
“目录”
})
公共静态bool IsRighToLeft()
{
返回System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.IsRightToLeft;
}
公共静态字符串GetImplementedCulture(字符串名称)
{
if(string.IsNullOrEmpty(name))
return GetDefaultCulture();//返回默认区域性
if(!CultureInfo.GetCultures(cultureType.SpecificCultures).Any(c=>c.Name.Equals(Name,StringComparison.InvariantCultureIgnoreCase)))
return GetDefaultCulture();//如果默认区域性无效,则返回默认区域性
if(_cultures.Any(c=>c.Equals(name,StringComparison.InvariantCultureIgnoreCase)))
返回name;//接受它
var n=GetNeutralCulture(名称);
foreach(文化中的变量c)
如果(c.StartsWith(n))
返回c;
return GetDefaultCulture();//返回默认区域性,因为找不到匹配项
}
公共静态字符串GetDefaultCulture()
{
返回“en GB”;//返回默认区域性,en GB
}
公共静态字符串GetCurrentCulture()
{
返回Thread.CurrentThread.CurrentCulture.Name;
}
公共静态字符串GetCurrentNeutralCulture()
{
返回GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name);
}
公共静态字符串GetNeutralCulture(字符串名称)
{
如果(!name.包含(“-”)返回名称;
返回名称。拆分('-')[0];//仅读取第一部分。例如“en”、“es”
}
公共静态列表GetImplementedLanguageNames()
{
List languageNames=新列表();
foreach(字符串区域性在_区域性中)
{
添加(新的键值对(culture,CultureInfo.GetCultureInfo(culture.EnglishName));
}
languageNames.Sort((第一对,下一对)=>
{
返回firstPair.Value.CompareTo(nextPair.Value);
});
字符串currCulture=GetCurrentCulture();
移除(新的键值对(currCulture,CultureInfo.GetCultureInfo(currCulture.EnglishName));
插入(0,新的键值对(currCulture,CultureInfo.GetCultureInfo(currCulture.EnglishName));
返回语言;
}
公共静态字符串GetDateTimeUsingCurrentCulture(DateTime dateToConvert)
{
CultureInfo ci=新的CultureInfo(GetCurrentCulture());
返回dateToConvert.ToString(ci.DateTimeFormat.ShortDatePattern+''+ci.DateTimeFormat.ShortTimePattern);
}
}
我认为使用属性路由无法实现这一点,因为传递给RegisterRoutes的RouteCollection及其后续RouteData非常不同,并且使用了无法访问的内部类
我已经确定RouteData需要一个名为“MS_DirectRouteMatches”的键,其值是RouteData的集合。如果您想进一步挖掘,请使用谷歌MS_DirectRouteMatches
最终,我假设这不是一个扩展点
如果你坚持传统的路线,你会获得更多的成功。我发现您的代码在这个场景中运行得非常好,但我希望您已经知道这一点。很抱歉,我无法为您提供更好的解决方案。据我所知,它没有使用父操作结果。我不知道为什么会这样。您可以在派生类中重写ActionResult,但对我来说,继承中似乎有问题。。你管理班级的方式有问题
public class MyBaseController: Controller
{
[HttpGet]
[Route("bar")]
public virtual ActionResult MyAction(){
{
return Content("Hello stranger!");
}
}
因此,假设这不起作用:
[RoutePrefix("foo")]
public class MyController: MyBaseController
{
[HttpGet]
[Route("foo")]
public override ActionResult MyAction(){
{
return Content("Hello stranger!");
}
}
我建议这样做:
[RoutePrefix("foo")]
public class MyController: MyBaseController
{
[HttpGet]
[Route("foo")]
public ActionResult MyAction(){
{
return Content("Hello stranger!");
}
}
这至少会告诉您继承是否有缺陷,您可以检查代码
另一种解决方法是使用一个控制器和两种不同格式的方法。您的
注册表项方法内容是什么。@RezaAghaei更新了。您在哪里声明了默认路由?没有默认路由,我完全依赖于属性(我不希望使用默认值的经典控制器/操作路由)。哦,没有看到该控制器。感谢您的示例,但我不希望在当前路由与指定路由不同(或为空)的情况下重定向,我还希望{culture}段成为第一段,并使用任何类型的路由(普通路由或路由属性)。因此用户将能够使用指定的或未指定的区域性访问我的路由(无重定向)。