如何将所有路由复制为伪装子目录

时间:2011-06-29 10:17:48

标签: c# asp.net-mvc asp.net-mvc-3 razor

要创建网站的移动版本,我想重用我的控制器,一些视图等,但创建看起来像移动版本的子目录。所以你可以有以下网址:

       /Controller/Action/Id
/mobile/Controller/Action/Id
etc.

理想情况下,这些路径将映射到同一个控制器,然后我可以查看路径数据中的某个位置以查看该URL是否为移动路径。我可以在视图中使用@Html.ActionLink()等,默认情况下保留在移动版或桌面版上,而不必指定此内容,但可以强制执行其中一个。

我可以通过在每条路线的前面设置一个可选参数来实现这样的目的,例如:

routes.MapRoute(
        "Default",
        "{mobile}/{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional, mobile = UrlParameter.Optional },
        new { mobile = "mobile|" }
      );

然后按预期工作:

Takes you to either / or /mobile version depending on where you are currently:
@Html.ActionLink("Current", "Index"); 

/ version
@Html.ActionLink("Desktop", "Index", new { mobile = "" });

/mobile version
@Html.ActionLink("Mobile", "Index", new { mobile = "mobile" });

然而,这似乎是一个非常蹩脚的解决方案,因为我真的不想将它添加到每条路线的前面。有没有什么好办法可以更好的方式做到这一点,例如在所有路由中添加可选的/mobile前缀并使其正常工作?或者是否有一种完全不同的方式可以解决整个问题,这会更有意义呢?

希望这不是太模糊,任何建议都会非常感激。

4 个答案:

答案 0 :(得分:2)

对于传入请求,这很简单,你只需要两组ruotes,一组所有路由都以mobile/开头。问题在于URL生成,为了解决这个问题,您需要实现仅在URL生成上执行的IRouteConstraint,并检查(当前HTTP请求的)当前路由是否以mobile/开头,并将其与正在测试的路线进行比较。我在MvcCodeRouting库中使用了类似的方法。

答案 1 :(得分:1)

你见过这个:http://51degrees.codeplex.com/

非常适合在同一代码库中使用移动/浏览器

答案 2 :(得分:1)

我已经在用于“常见”浏览器的asp.net mvc + jquery和用于移动浏览器的asp.net mvc + jqueryMobile的web项目中执行此操作。我不需要在我的全局asax中创建新路由。这些是移动重定向的漂亮网站:

Mobile enabled web apps with ASP.NET MVC 3 and jQuery Mobile(如果你使用mvc3要容易得多) Walkthrough: Creating an ASP.NET MVC Areas Application Using Multiple Projects A First Look at ASP.NET MVC 2

所以,在我的解决方案中,我使用了移动重定向属性,我在控制器的操作中标记了我想要检查重定向。我在你的解决方案中看到你“问”用户点击正确的链接,取决于用户并且不好(也许我没有抓住你的意图)。但是,在此解决方案中,您检查请求中的用户代理,以了解对您的站点执行请求的浏览器:

/// <summary>
    /// Attribute for Mobile Redirection when the request action comes from a mobile device.
    /// </summary>
    public class MobileRedirectAttribute : AuthorizeAttribute
    {
        private const string defaultMobileController = "Mobile";

        #region Properties

        /// <summary>
        /// Gets or sets the action.
        /// </summary>
        /// <value>The action.</value>
        private string Action { get; set; }

        /// <summary>
        /// Gets or sets the controller.
        /// </summary>
        /// <value>The controller.</value>
        private string Controller { get; set; }

        private UrlHelper _urlHelper;
        /// <summary>
        /// Sets the URL helper.
        /// </summary>
        /// <value>The URL helper.</value>
        internal UrlHelper UrlHelper { set { this._urlHelper = value; } }

        /// <summary>
        /// Gets or sets the last URL redirected.
        /// </summary>
        /// <value>The last URL redirected.</value>
        internal string RedirectedTo { get; private set; }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is mobile device.
        /// </summary>
        /// <value>
        ///     <c>true</c> if this instance is mobile device; otherwise, <c>false</c>.
        /// </value>
        internal bool IsMobileDevice { get; private set; }

        #endregion

        #region Methods

        /// <summary>
        /// Determines whether the specified controller is mobile.
        /// </summary>
        /// <param name="controller">The controller.</param>
        /// <returns>
        ///     <c>true</c> if the specified controller is mobile; otherwise, <c>false</c>.
        /// </returns>
        private bool IsMobile(Controller controller)
        {
            bool isMobile = controller.Request.Browser.IsMobileDevice;
            string userAgent = controller.Request.UserAgent.ToLower();

            return (isMobile || userAgent.Contains("iphone") || userAgent.Contains("ipod") || userAgent.Contains("blackberry") || userAgent.Contains("mobile")
                             || userAgent.Contains("opera mini") || userAgent.Contains("palm"));
        }

        /// <summary>
        /// Called when [authorization].
        /// </summary>
        /// <param name="filterContext">The filter context.</param>
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            Controller controller = filterContext.Controller as Controller;
            this.IsMobileDevice = IsMobile(controller); //test porpouse
            if (this.IsMobileDevice)
            {
                this.RedirectedTo = GetUrlRedirectAction(filterContext.RequestContext);
                filterContext.Result = new RedirectResult(this.RedirectedTo);
            }
        }

        /// <summary>
        /// Gets the URL redirect action.
        /// </summary>
        /// <param name="requestContext">The request context.</param>
        /// <returns></returns>
        private string GetUrlRedirectAction(RequestContext requestContext)
        {
            UrlHelper urlHelper = _urlHelper;
            if (urlHelper == null) //mocking porpouse;
                urlHelper = new UrlHelper(requestContext);

            return urlHelper.Action(this.Action, this.Controller, requestContext.RouteData.Values);
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Initializes a new instance of the <see cref="MobileRedirectAttribute"/> class.
        /// </summary>
        /// <param name="action">The action.</param>
        public MobileRedirectAttribute(string action)
        {
            this.Action = action;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="MobileRedirectAttribute"/> class.
        /// </summary>
        /// <param name="controller">The controller.</param>
        /// <param name="action">The action.</param>
        public MobileRedirectAttribute(string controller, string action)
        {
            this.Action = action;
            this.Controller = controller;
        }

        #endregion

    }

因此,在此之后,您唯一需要做的就是标记您想要重定向到不同视图的控制器操作。控制器逻辑可以重构并将其提取为常用方法。

// GET: /MyController/
[MobileRedirectAttribute("MyController","IndexMobile")]
public ActionResult Index(string guid)

希望能提供帮助,询问您是否有任何疑问。

答案 3 :(得分:0)

这不起作用:

routes.MapRoute(
                "Mobile", // Mobile route
                "mobile/{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

routes.MapRoute(
                "Default", // Default route
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );

我相信当路由匹配时,使用ActionLink创建的链接会考虑匹配的路由并为其构建链接吗?

我可能错了 - 我实际上没有测试过它。