无需编写控制器的简单 ASP.NET MVC 视图

发布于 2024-09-04 13:42:31 字数 645 浏览 2 评论 0原文

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

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

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

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

We're building a site that will have very minimal code, it's mostly just going to be a bunch of static pages served up. I know over time that will change and we'll want to swap in more dynamic information, so I've decided to go ahead and build a web application using ASP.NET MVC2 and the Spark view engine. There will be a couple of controllers that will have to do actual work (like in the /products area), but most of it will be static.

I want my designer to be able to build and modify the site without having to ask me to write a new controller or route every time they decide to add or move a page. So if he wants to add a "http://example.com/News" page he can just create a "News" folder under Views and put an index.spark page within it. Then later if he decides he wants a /News/Community page, he can drop a community.spark file within that folder and have it work.

I'm able to have a view without a specific action by making my controllers override HandleUnknownAction, but I still have to create a controller for each of these folders. It seems silly to have to add an empty controller and recompile every time they decide to add an area to the site.

Is there any way to make this easier, so I only have to write a controller and recompile if there's actual logic to be done? Some sort of "master" controller that will handle any requests where there was no specific controller defined?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

温柔少女心 2024-09-11 13:42:31

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

You will have to write a route mapping for actual controller/actions and make sure the default has index as an action and the id is "catchall" and this will do it!

    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
    }
做个少女永远怀春 2024-09-11 13:42:31

这个 链接可能会有所帮助,

如果您在 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);
            }
        }
    }

This link might be help,

If you create cshtml in View\Public directory, It will appears on Web site with same name. I added also 404 page.

[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);
            }
        }
    }
长途伴 2024-09-11 13:42:31

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

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

Couldn't you create a separate controller for all the static pages and redirect everything (other than the actual controllers which do work) to it using MVC Routes, and include the path parameters? Then in that controller you could have logic to display the correct view based on the folder/path parameter sent to it by the routes.

Allthough I don't know the spark view engine handles things, does it have to compile the views? I'm really not sure.

神妖 2024-09-11 13:42:31

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

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

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

Reflecting on Paul's answer. I'm not using any special view engines, but here is what I do:

1) Create a 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) Then create a Public directory in the Views folder, and put all of your views there that you want to be public. I personally needed this because I never knew if the client wanted to create more pages without having to recompile the code.

3) Then modify RouteConfig.cs to redirect to the Public/Index action.

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) Then just reference it from your views like this:

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

Not sure if this is any better than using a factory pattern, but it seems to me the easiest to implement and to understand.

请你别敷衍 2024-09-11 13:42:31

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

I think you can create your own controller factory that will always instantiate the same controller class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文