我们正在构建一个代码非常少的网站,它主要是提供一堆静态页面。我知道随着时间的推移会发生变化,我们会想要交换更多动态信息,因此我决定继续使用ASP.NET MVC2和Spark视图引擎构建Web应用程序。将有一些控制器必须进行实际工作(如/ products区域),但大多数都是静态的。
我希望我的设计师能够构建和修改网站,而无需每次他们决定添加或移动页面时都要求我编写新的控制器或路由。因此,如果他想添加“http://example.com/News”页面,他只需在Views下创建一个“News”文件夹,并在其中放置一个index.spark页面。然后如果他决定要一个/新闻/社区页面,他可以删除该文件夹中的一个community.spark文件并使其正常工作。
通过使控制器覆盖HandleUnknownAction,我可以拥有一个没有特定操作的视图,但我仍然需要为每个文件夹创建一个控制器。每次他们决定向网站添加区域时,必须添加一个空控制器并重新编译似乎很愚蠢。
有没有办法让这更容易,所以我只需编写一个控制器并重新编译,如果有实际的逻辑要做?某种“主”控制器将处理没有定义特定控制器的任何请求?
答案 0 :(得分:6)
您必须为实际的控制器/操作编写路由映射,并确保默认将索引作为操作,并且id为“catchall”,这样就可以了!
public class MvcApplication : System.Web.HttpApplication {
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "catchall" } // Parameter defaults
);
}
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ControllerBuilder.Current.SetControllerFactory(new CatchallControllerFactory());
}
}
public class CatchallController : Controller
{
public string PageName { get; set; }
//
// GET: /Catchall/
public ActionResult Index()
{
return View(PageName);
}
}
public class CatchallControllerFactory : IControllerFactory {
#region IControllerFactory Members
public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName) {
if (requestContext.RouteData.Values["controller"].ToString() == "catchall") {
DefaultControllerFactory factory = new DefaultControllerFactory();
return factory.CreateController(requestContext, controllerName);
}
else {
CatchallController controller = new CatchallController();
controller.PageName = requestContext.RouteData.Values["action"].ToString();
return controller;
}
}
public void ReleaseController(IController controller) {
if (controller is IDisposable)
((IDisposable)controller).Dispose();
}
#endregion
}
答案 1 :(得分:3)
这link可能会有所帮助,
如果在View \ Public目录中创建cshtml,它将出现在具有相同名称的网站上。我还添加了404页面。
[HandleError]
public class PublicController : Controller
{
protected override void HandleUnknownAction(string actionName)
{
try
{
this.View(actionName).ExecuteResult(this.ControllerContext);
}
catch
{
this.View("404").ExecuteResult(this.ControllerContext);
}
}
}
答案 2 :(得分:1)
你不能为所有静态页面创建一个单独的控制器,并使用MVC路由将所有内容(除了有效的实际控制器除外)重定向到它,并包含路径参数吗?然后在该控制器中,您可以根据路由发送给它的文件夹/路径参数显示正确的视图。
虽然我不知道spark视图引擎处理的事情,它是否必须编译视图?我真的不确定。
答案 3 :(得分:1)
反思保罗的回答。我没有使用任何特殊的视图引擎,但这就是我所做的:
1)创建一个PublicController.cs。
// GET: /Public/
[AllowAnonymous]
public ActionResult Index(string name = "")
{
ViewEngineResult result = ViewEngines.Engines.FindView(ControllerContext, name, null);
// check if view name requested is not found
if (result == null || result.View == null)
{
return new HttpNotFoundResult();
}
// otherwise just return the view
return View(name);
}
2)然后在Views文件夹中创建一个Public目录,并将您想要公开的所有视图放在那里。我个人需要这个,因为我从来不知道客户是否想要创建更多页面而不必重新编译代码。
3)然后修改RouteConfig.cs以重定向到Public / Index操作。
routes.MapRoute(
name: "Public",
url: "{name}.cshtml", // your name will be the name of the view in the Public folder
defaults: new { controller = "Public", action = "Index" }
);
4)然后从你的观点中引用它:
<a href="@Url.RouteUrl("Public", new { name = "YourPublicPage" })">YourPublicPage</a> <!-- and this will point to Public/YourPublicPage.cshtml because of the routing we set up in step 3 -->
不确定这是否比使用工厂模式更好,但在我看来最容易实现和理解。
答案 4 :(得分:0)
我认为您可以创建自己的控制器工厂,始终实例化相同的控制器类。