1

想象一个绑定了许多域的站点。fe product1.com, product2.com, ...

当product23 出现故障时,想法是让“landingpagecontroller”为product23.com 提供所有请求。

这个想法是写一个 ActionFilter 来完成这个:

   public class Landingpage : IActionFilter
{

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var DnsSafeHost = filterContext.HttpContext.Request.Url.DnsSafeHost;
        if (DnsSafeHost.NeedsLandingpage())
        {
            //Do actual redirecting
         }
    }
}

NeedsLandingpage() 返回一个布尔值。如果需要登陆页面控制器服务,则为真。情报将在数据库中找到。

我已经添加了到登录页面控制器的路由。

            routes.MapRoute(
            name: "Ladingpage",
            url: "Landingpage/{id}/{*dummy}",
            defaults: new { controller = "LandingPage", action = "Index" }
        );

关于如何从 actionfilter 更改路由设置以触发上述路由或实现目标的更好解决方案的任何提示。

********** 更新 ************

鉴于大家的意见,我想出了以下可行的解决方案,但我对它并不是 100% 满意。因此,欢迎提供更好的解决方案。

我创建了以下 IActionFilter 并将其注册为全局。

public class Landingpage : IActionFilter
    {
        public void OnActionExecuting(ActionExecutingContext filterContext)
        {
            var DnsSafeHost = filterContext.HttpContext.Request.Url.DnsSafeHost;
            var _LandingPage = LandingPage(DnsSafeHost);
            if (_LandingPage != null)
            {
                if ((String)filterContext.RouteData.Values["controller"] != "Landingpage")
                {
                    filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary(new { controller = "Landingpage", action = "Index", id = _LandingPage }));
                    filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
                }
            }
        }
        private String LandingPage(String DnsSafeHost)
        {
            if (DnsSafeHost.Contains("<domain to look for>".ToLower())) return "<viewname>";
            if (DnsSafeHost.Contains("<domain to look for>".ToLower())) return "<viewname>";
            if (DnsSafeHost.Contains("<domain to look for>".ToLower())) return "<viewname>";
            return null;
        }
    }

我不喜欢该解决方案的是检查 (String)filterContext.RouteData.Values["controller"]

这是需要的,否则您会陷入循环,因为。

浏览器 -> 路由 -> 过滤器 -> 重定向 -> 路由 -> 过滤器...

我认为一个可能的解决方案是在 Application_BeginRequest (global.asax) 中做一些事情。但我没有找到“重写”请求的方法。因为如果这可能,流程将是:浏览器 -> BeginRequest -> RewriteRequest -> 路由 -> 控制器。

我猜,如果您遵循最佳实践,那么在 vNext 中,下站点似乎将不再起作用。

过滤器配置文件

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
        filters.Add(new Landingpage());

    }
}

所有“登陆页面”调用都被重定向到 LandingPageController。对 ViewEngine 的调用用于检查从 actionfilter 传递的视图名称是否存在,如果不使用默认值。

   public class LandingpageController : Controller
    {
        public ActionResult Index(string id)
        {
            if (id == null) return View();
            if (ViewEngines.Engines.FindView(ControllerContext, id, null).View == null) return View();
            ViewBag.Title = id;
            return View(id);
        }
    }

视图示例。

@{
    Layout = "_Index_layout.cshtml";
}

<div class="domainname">Landingpage</div>

为了给它一个不同于普通页面的“特殊”布局(没有菜单),我为此页面添加了一个自定义布局。

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
    <style>
--- add some styling here ---
     </style>
</head>

<body>
    @RenderBody()
</body>

</html>
4

2 回答 2

1

我查看了一些我过去用来做类似事情的代码。基本上我是这样做的:

首先,我创建了一个基于的类RedirectToRouteResult(你不必这样做,但我放在这里是为了说明)。

namespace Blah
{
    using System;
    using System.Web.Mvc;
    using System.Web.Routing;

    public class SessionTimeoutRedirectResult : RedirectToRouteResult
    {
        public SessionTimeoutRedirectResult(
            string routeName,
            RouteValueDictionary routeValueDictionary,
            string redirectActionName,
            string redirectControllerName)
            : base(routeName, routeValueDictionary)
        {
            RedirectActionName = redirectActionName;
            RedirectControllerName = redirectControllerName;
        }

        public string RedirectActionName { get; private set; }

        public string RedirectControllerName { get; private set; }

        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException("context");
            }

            RouteValues.Clear();
            RouteValues.Add("action", RedirectActionName);
            RouteValues.Add("controller", RedirectControllerName);

            base.ExecuteResult(context);
        }
    }
}

然后在动作过滤器中,我的代码执行了以下操作:

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    var controller = filterContext.Controller as BaseController;

    if (controller != null)
    {
        if (controller.Session.IsNewSession)
        {
            var routeDictionary = filterContext.RouteData.DataTokens;

            filterContext.Result = new SessionTimeoutRedirectResult(
                "Error500",
                routeDictionary,
                RedirectActionName,
                RedirectControllerName);
        }
    }

    base.OnActionExecuting(filterContext);
}

因此,我的操作过滤器将根据会话重定向路由结果重定向用户。同样,您不必创建基于 的类RedirectToRouteResult,但出于某种原因,我当时就这样做了。

最终关键是设置filterContext.Result为将重定向用户。

于 2015-10-27T08:26:35.753 回答
0

正如我在编辑中提到的,我有一个解决方案,但由于重定向和摆脱重定向循环的肮脏方式,我并不是 100% 满意。

如果您看一下请求处理管道。

http://saulius.sunauskas.com/wp-content/uploads/asp_net__mvc_request_pipeline_4.png

更改请求的地方是流程图上的“IRouteHandler”。

在这里找到了一个很好的创建自定义示例:

http://www.brainthud.com/cards/5218/24821/give-an-example-of-how-you-would-create-a-custom-route-handler-to-reroute-requests-with-a-接受 http-he 中的某些值

最终解决方案的原型是:

  1. 从 MVCRouteHandler 创建一个自定义 IRouteHandler :

    public class LandingPageRouteHandler : MvcRouteHandler
    {
        protected override IHttpHandler GetHttpHandler(RequestContext Context)
        {
            if (  Context.HttpContext.Request.Url.DnsSafeHost.ToLower().Contains("onecityguide"))
            {
                Context.RouteData.Values["controller"] = "LandingPage";
                Context.RouteData.Values["action"] = "Index"; 
                Context.RouteData.Values["id"] = "onecityguide";
            }
            return base.GetHttpHandler(Context);
        }
    }
    
  2. 将自定义 RouteHandler 连接到默认路由。

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    ).RouteHandler = new LandingPageRouteHandler();
    
于 2015-10-29T12:38:55.313 回答