我有点问题。我有一个名为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.aspx和http://odetocode.com/Blogs/scott/archive/2009/10/13/asp-net-mvc2-preview-2-areas-and-routes.aspx。这是我目前的设置。
Structuremap Init
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),它只注册第一个,这是默认的家庭控制器。我有创意并附加了命名空间,以便它可以注册我的所有控制器。
默认路线
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的建议,我使用命名空间作为第4个参数
app start,只是为了证明初始化的顺序
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为null,因为没有返回控制器而导致错误。
好像MVC完全无视我的区域。这里发生了什么?我做错了什么?
答案 0 :(得分:0)
如果有人试图做类似的事情,我使用了这篇文章中的想法:Categories of controllers in MVC Routing? (Duplicate Controller names in separate Namespaces)我不得不完全使用区域转储并自己实现。
我有Controllers / HomeController.cs和Controllers / Framed / HomeController.cs
我有一个类ControllerBase,/ Controllers中的所有控制器都继承自。我有一个继承自ControllerBase的AreaController,/ 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方法。这样,我的“区域”中的控制器可以使用视图和局部的默认方法,并支持添加的文件夹结构。
至于视图,我有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个控制器的情况下完成这项工作。
答案 1 :(得分:0)
我在使用带有区域的Structuremap时遇到了类似的问题。我有一个名为Admin的区域,每当你试图进入/ admin时,它都会进入带有空控制器类型的StructureMap Controller Factory。
我按照以下博文修改了它: 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;
}
}
可能有其他方法可以解决这个问题,但这对我来说是固定的:)