代码之家  ›  专栏  ›  技术社区  ›  Josh

MVC 2.0、结构映射、区域和重复的控制器名称

  •  0
  • Josh  · 技术社区  · 15 年前

    我有点问题。我有一个区域叫框架。这个区域有一个主控制器。站点的默认设置还有一个主控制器。

    http://example.com/Framed/Account/Index 将显示一个非常基本的版本,只有你的帐户信息用于外部网站。 http://example.com/Account/Index 将显示相同的数据,但在默认站点内。

    我的IoC容器是structuremap。所以,我发现 http://odetocode.com/Blogs/scott/archive/2009/10/19/mvc-2-areas-and-containers.aspx http://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", ""));
                    });
                });
    

    在这里,我通过调试发现的问题是,由于控制器具有相同的名称(home controller),所以它只注册第一个控制器,这是默认的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 ,我使用名称空间作为第四个参数

    应用程序启动,只是为了证明初始化的顺序

    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;
            }
    

    好像MVC完全忽略了我的领域。怎么回事?我做错什么了?

    2 回复  |  直到 15 年前
        1
  •  0
  •   Community Mohan Dere    9 年前

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

    我有一个类ControllerBase,它继承了/controllers中的所有控制器。我有一个AreaController,它继承自ControllerBase,ControllerBase/controllers/Framed中的所有控制器都是从它扩展而来的。

    这是我的区域控制器课程

    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;
            }
        }
    

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

    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
  •  0
  •   Chris    15 年前

    我有一个类似的问题,就是在区域中使用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;
        }
    }
    

    也许有其他方法可以解决这个问题,但这帮我解决了:)