【问题标题】:MVC 2.0, StructureMap, Areas, and Duplicate Controller NamesMVC 2.0、StructureMap、区域和重复的控制器名称
【发布时间】:2011-04-26 00:09:03
【问题描述】:

我有一点问题。我有一个叫做 Framed 的区域。这个区域有一个家庭控制器。该站点的默认设置还有一个家庭控制器。

我想要做的是让每个控制器/动作都有一个适合 IFrame 的版本,以及一个普通站点的版本。我通过母版页执行此操作,并且站点母版页与框架版本相比具有许多不同的内容占位符。出于这个原因,我不能只是交换母版页。例如,http://example.com/Framed/Account/Index 将显示一个非常基本的版本,其中仅包含您的帐户信息,以便在外部站点中使用。 http://example.com/Account/Index 将显示相同的数据,但在默认站点内。

我的 IoC 容器是结构图。所以,我找到了http://odetocode.com/Blogs/scott/archive/2009/10/19/mvc-2-areas-and-containers.aspxhttp://odetocode.com/Blogs/scott/archive/2009/10/13/asp-net-mvc2-preview-2-areas-and-routes.aspx。这是我目前的设置。

结构图初始化

ObjectFactory.Initialize(x =>
            {
                x.AddRegistry(new ApplicationRegistry());
                x.Scan(s =>
                {
                    s.AssembliesFromPath(HttpRuntime.BinDirectory);
                    s.AddAllTypesOf<IController>()
                        .NameBy(type => type.Namespace + "." + type.Name.Replace("Controller", ""));
                });
            });

这里我通过调试发现的问题是,因为控制器同名(HomeController),所以只注册了第一个,也就是默认的home控制器。我有创意并附加了命名空间,以便它可以注册我的所有控制器。

默认路线

routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { area = "", controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
                new[] { "MySite.Controllers" }
                );

区域路线

context.MapRoute(
                "Framed_default",
                "Framed/{controller}/{action}/{id}",
                new { area = "Framed", controller = "Home", action = "Index", id = UrlParameter.Optional },
                new string[] { "MySite.Areas.Framed.Controllers" }
            );

按照Phil Haack 的建议,我使用命名空间作为第四个参数

app启动,只是为了证明初始化的顺序

protected void Application_Start()
        {
            InitializeControllerFactory();

            AreaRegistration.RegisterAllAreas();

            RouteConfiguration.RegisterRoutes();
        }

控制器工厂

protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
        {
            IController result = null;
            if (controllerType != null)
            {
                result = ObjectFactory.GetInstance(controllerType)
                    as IController;
            }
            return result;
        }

所以,当我点击 /Home/Index 时,它会传入正确的控制器类型。当我点击 /Framed/Home/Index 时,controllerType 为空,这是因为没有返回控制器而出错。

就好像 MVC 完全忽略了我的领域。这里发生了什么?我做错了什么?

【问题讨论】:

    标签: c# asp.net-mvc-2 structuremap asp.net-mvc-areas


    【解决方案1】:

    如果有人尝试做类似的事情,我使用了这篇文章中的想法:Categories of controllers in MVC Routing? (Duplicate Controller names in separate Namespaces) 我不得不完全放弃使用区域并自己实现一些东西。

    我有 Controllers/HomeController.cs 和 Controllers/Framed/HomeController.cs

    我有一个 ControllerBase 类,/Controllers 中的所有控制器都继承自该类。我有继承自 /Controllers/Framed 中的所有控制器的 ControllerBase 的 AreaController。

    这是我的区域控制器类

    public class AreaController : ControllerBase
        {
            private string Area
            {
                get
                {
                    return this.GetType().Namespace.Replace("MySite.Controllers.", "");
                }
            }
            protected override ViewResult View(string viewName, string masterName, object model)
            {
                string controller = this.ControllerContext.RequestContext.RouteData.Values["controller"].ToString();
    
                if (String.IsNullOrEmpty(viewName))
                    viewName = this.ControllerContext.RequestContext.RouteData.Values["action"].ToString();
    
                return base.View(String.Format("~/Views/{0}/{1}/{2}.aspx", Area, controller, viewName), masterName, model);
            }
    
            protected override PartialViewResult PartialView(string viewName, object model)
            {
                string controller = this.ControllerContext.RequestContext.RouteData.Values["controller"].ToString();
    
                if (String.IsNullOrEmpty(viewName))
                    viewName = this.ControllerContext.RequestContext.RouteData.Values["action"].ToString();
    
                PartialViewResult result = null;
    
                result = base.PartialView(String.Format("~/Views/{0}/{1}/{2}.aspx", Area, controller, viewName), model);
    
                if (result != null)
                    return result;
    
                result = base.PartialView(String.Format("~/Views/{0}/{1}/{2}.ascx", Area, controller, viewName), model);
    
                if (result != null)
                    return result;
    
                result = base.PartialView(viewName, model);
    
                return result;
            }
        }
    

    我不得不重写 view 和 partialview 方法。这样,我“区域”中的控制器可以使用视图和局部视图的默认方法,并支持添加的文件夹结构。

    至于视图,我有 Views/Home/Index.aspx 和 Views/Framed/Home/Index.aspx。我使用帖子中显示的路由,但这是我的参考方式:

    var testNamespace = new RouteValueDictionary();
                testNamespace.Add("namespaces", new HashSet<string>(new string[] 
                { 
                    "MySite.Controllers.Framed"
                }));
    
                //for some reason we need to delare the empty version to support /framed when it does not have a controller or action
                routes.Add("FramedEmpty", new Route("Framed", new MvcRouteHandler())
                {
                    Defaults = new RouteValueDictionary(new
                    {
                        controller = "Home",
                        action = "Index",
                        id = UrlParameter.Optional
                    }),
                    DataTokens = testNamespace
                });
    
                routes.Add("FramedDefault", new Route("Framed/{controller}/{action}/{id}", new MvcRouteHandler())
                {
                    Defaults = new RouteValueDictionary(new
                    {
                        //controller = "Home",
                        action = "Index",
                        id = UrlParameter.Optional
                    }),
                    DataTokens = testNamespace
                });
    
    var defaultNamespace = new RouteValueDictionary();
                defaultNamespace.Add("namespaces", new HashSet<string>(new string[] 
                { 
                    "MySite.Controllers"
                }));
    
    routes.Add("Default", new Route("{controller}/{action}/{id}", new MvcRouteHandler())
                    {
                        Defaults = new RouteValueDictionary(new
                        {
                            controller = "Home",
                            action = "Index",
                            id = UrlParameter.Optional
                        }),
                        DataTokens = defaultNamespace
                    });
    

    现在我可以在同一个站点上转到 /Home/Index 或 /Framed/Home/Index 并使用共享控件获得两个不同的视图。理想情况下,我希望一个控制器返回 2 个视图之一,但我不知道如何在没有 2 个控制器的情况下使其工作。

    【讨论】:

      【解决方案2】:

      我在使用带有区域的 Structuremap 时遇到了类似的问题。我有一个名为 Admin 的区域,每当您尝试访问 /admin 时,它都会到达带有空控制器类型的 StructureMap 控制器工厂。

      我按照这篇博文修复了它: http://stephenwalther.com/blog/archive/2008/08/07/asp-net-mvc-tip-30-create-custom-route-constraints.aspx

      如果控制器是管理员,则必须在默认路由上添加一个不匹配的约束。

      这是我的默认路由定义:

      routes.MapRoute(
          "Default",
          "{controller}/{action}/{id}",
          new { controller = "MyController", action = "AnAction", id = UrlParameter.Optional },
          new { controller = new NotEqualConstraint("Admin")},
          new string[] {"DailyDealsHQ.WebUI.Controllers"} 
      );
      

      这里是 NotEqualConstraint 的实现:

      public class NotEqualConstraint : IRouteConstraint
      {
          private string match = String.Empty;
      
          public NotEqualConstraint(string match)
          {
              this.match = match;
          }
      
          public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
          {
              return String.Compare(values[parameterName].ToString(), match, true) != 0;
          }
      }
      

      可能还有其他方法可以解决此问题,但这为我解决了问题:)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-03
        • 1970-01-01
        • 1970-01-01
        • 2010-12-12
        相关资源
        最近更新 更多