ASP.NET MVC:通过区域查找控制器

3

我的目标是通过控制器的名称和区域来查找控制器。如果我的当前httpContext与要查找的控制器处于相同的区域,则我已经成功完成了此操作。然而,我无法让我的ControllerFactory调用考虑到区域。以下是我的代码:

public static ControllerBase GetControllerByName(this HtmlHelper htmlHelper, string controllerName)
    {
      IControllerFactory factory = ControllerBuilder.Current.GetControllerFactory();
      IController controller = factory.CreateController(htmlHelper.ViewContext.RequestContext, controllerName);
      if (controller == null)
      {
        throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, "The IControllerFactory '{0}' did not return a controller for the name '{1}'.", factory.GetType(), controllerName));
      }
      return (ControllerBase)controller;
    }

由于它将RequestContext作为参数,因此我已添加了一个名为"area"的路由值,但没有任何变化。是否可以通过requestContext做些什么以考虑区域?我需要重写控制器工厂吗?如果需要,特别是哪个处理区域区分?

更新:

以下是我的AreaRegistration示例:

public class StoresAreaRegistration : AreaRegistration
  {
    public override string AreaName { get { return "Stores"; } }

    public override void RegisterArea(AreaRegistrationContext context)
    {
      context.MapRoute(
          AreaName,
          AreaName + "/{controller}/{action}/{id}",
          new { area = AreaName, controller = "Home", action = "Index", id = UrlParameter.Optional }
      );
    }
  }

你尝试过使用 RequestContext.RouteData 吗? - cheesemacfly
@cheesemacfly,是的 - htmlHelper.ViewContext.RequestContext.RouteData.DataTokens["area"] = areaNamehtmlHelper.ViewContext.RequestContext.RouteData.Values["area"] = areaName; 都尝试过了,但都没有成功。 - OnResolve
你的 GetControllerByName() 函数中没有访问 Request.RequestContext 对象的权限? - cheesemacfly
htmlHelper.ViewContext.RequestContext - OnResolve
你的函数 GetControllerByName() 内部无法访问 Request 对象? - cheesemacfly
显示剩余4条评论
1个回答

10
路由数据和命名空间用于定位控制器,它们存储在RequestContext中。如果需要更改它们,则必须在调用CreateController之前进行更改。如果找不到控制器,则可能会引发异常,因此您也需要考虑这一点。
更新:请注意,您必须创建一个新的RequestContext。如果重用现有的RequestContext,则会影响后续操作和视图的解析。
var tempRequestContext = new RequestContext(Request.RequestContext.HttpContext, new RouteData());
tempRequestContext.RouteData.DataTokens["Area"] = "";
tempRequestContext.RouteData.DataTokens["Namespaces"] = "YourCompany.Controllers";
var controller = ControllerBuilder.Current.GetControllerFactory()
                .CreateController(tempRequestContext, "ControllerName");

if(controller != null)
{
    //TODO: Implement your logic here
}

嗨,错误略有不同,而且这个答案正是我所需要的,尽管我必须将["Namespaces"]更改为["namespaces"](因为我没有使用过areas,所以我不知道该键是否也需要小写)。谢谢! - mitomed
我在我的代码中使用大写字母,它可以正常工作。我不确定为什么你会在大小写字母方面得到不同的结果。 - Nick Albrecht
在MVC 5中,Namespaces值显然需要一个IEnumerable<string>而不仅仅是一个字符串。因此使用:tempRequestContext.RouteData.DataTokens["Namespaces"] = new List<string> { "YourCompany.Controllers" }; - Peter
它应该接受两个。如果您只传递一个命名空间,您可以直接给出字符串。您不必将其包装在列表中传递。DataTokens["Namespaces"] 期望的类型是 object 类型。 - Nick Albrecht

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接