【问题标题】:Simple ASP.NET MVC views without writing a controller无需编写控制器的简单 ASP.NET MVC 视图
【发布时间】:2011-03-01 20:09:15
【问题描述】:

我们正在构建一个代码非常少的网站,它主要是提供一堆静态页面。我知道随着时间的推移会发生变化,我们会想要交换更多动态信息,所以我决定继续使用 ASP.NET MVC2 和 Spark 视图引擎构建一个 Web 应用程序。将有几个控制器必须进行实际工作(例如在 /products 区域中),但其中大部分将是静态的。

我希望我的设计师能够构建和修改网站,而不必在每次他们决定添加或移动页面时都要求我编写新的控制器或路由。因此,如果他想添加一个“http://example.com/News”页面,他可以在 Views 下创建一个“News”文件夹并在其中放置一个 index.spark 页面。之后,如果他决定想要一个 /News/Community 页面,他可以将 community.spark 文件放到该文件夹​​中并让它工作。

我可以通过让我的控制器覆盖 HandleUnknownAction 来获得没有特定操作的视图,但我仍然必须为每个文件夹创建一个控制器。每次他们决定向站点添加区域时都必须添加一个空控制器并重新编译,这似乎很愚蠢。

有什么方法可以让这更容易,所以我只需要编写一个控制器并在需要完成实际逻辑时重新编译吗?某种“主”控制器将处理没有定义特定控制器的任何请求?

【问题讨论】:

  • +1 用于提及 HandleUnknownAction。这对我有帮助。

标签: asp.net-mvc-2 spark-view-engine


【解决方案1】:

您必须为实际的控制器/动作编写路由映射,并确保默认将索引作为动作并且 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
    }

【讨论】:

    【解决方案2】:

    这个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);
                }
            }
        }
    

    【讨论】:

      【解决方案3】:

      您不能为所有静态页面创建一个单独的控制器并使用 MVC 路由将所有内容(除了实际工作的控制器之外)重定向到它,并包含路径参数吗?然后在该控制器中,您可以有逻辑根据路由发送给它的文件夹/路径参数显示正确的视图。

      虽然我不知道 spark 视图引擎处理事情,但它必须编译视图吗?我真的不确定。

      【讨论】:

        【解决方案4】:

        反思保罗的回答。我没有使用任何特殊的视图引擎,但这是我所做的:

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

        不确定这是否比使用工厂模式更好,但在我看来它是最容易实现和理解的。

        【讨论】:

          【解决方案5】:

          我认为您可以创建自己的控制器工厂,始终实例化相同的控制器类。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-04-15
            • 1970-01-01
            相关资源
            最近更新 更多