如何重定向MVC操作而不返回301?(使用MVC 4测试版)

本文关键字:MVC 使用 测试版 返回 重定向 操作 | 更新日期: 2023-09-27 18:26:34

我正在开发一个具有许多不同菜单的ASP.NET MVC解决方案。要显示的菜单取决于当前登录用户的角色。

在MVC 3中,我有一些自定义代码来支持这种场景,通过使用一个返回正确菜单的控制器方法。它将通过将请求推迟到适当的控制器并根据当前用户采取行动来实现这一点。

这段代码似乎在MVC 4中被破坏了,我正在寻求帮助来修复它

首先,我添加了一个TransferResult帮助类来执行重定向:

public class TransferResult : RedirectResult
{
    #region Transfer to URL
    public TransferResult( string url ) : base( url )
    {
    }
    #endregion
    #region Transfer using RouteValues
    public TransferResult( object routeValues ) : base( GetRouteUrl( routeValues ) )
    {
    }
    private static string GetRouteUrl( object routeValues )
    {
        var url = new UrlHelper( new RequestContext( new HttpContextWrapper( HttpContext.Current ), new RouteData() ), RouteTable.Routes );
        return url.RouteUrl( routeValues );
    }
    #endregion
    #region Transfer using ActionResult (T4MVC only)
    public TransferResult( ActionResult result ) : base( GetRouteUrl( result.GetT4MVCResult() ) )
    {
    }
    private static string GetRouteUrl( IT4MVCActionResult result )
    {
        var url = new UrlHelper( new RequestContext( new HttpContextWrapper( HttpContext.Current ), new RouteData() ), RouteTable.Routes );
        return url.RouteUrl( result.RouteValueDictionary );
    }
    #endregion
    public override void ExecuteResult( ControllerContext context )
    {
        HttpContext httpContext = HttpContext.Current;
        httpContext.RewritePath( Url, false );
        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest( HttpContext.Current );
    }
}

其次,我修改了T4MVC以发出一些控制器助手方法,导致每个控制器都有这个方法:

protected TransferResult Transfer( ActionResult result )
{
    return new TransferResult( result );
}

这使我可以使用共享控制器操作来返回菜单,而不必用任何条件逻辑扰乱视图:

public virtual ActionResult Menu()
{
    if( Principal.IsInRole( Roles.Administrator ) )
        return Transfer( MVC.Admin.Actions.Menu() );
    return View( MVC.Home.Views.Partials.Menu );
}

然而,TransferResult类中ExecuteResult中的代码似乎不适用于MVC 4的当前预览版本。它给了我以下错误(指向"httpHandler.ProcessRequest"行):

'HttpContext.SetSessionStateBehavior' can only be invoked before
'HttpApplication.AcquireRequestState' event is raised.

知道怎么解决这个问题吗?

PS:我意识到我可以使用一个简单的HtmlHelper扩展来实现同样的目的,这就是我目前使用的解决方法。然而,在许多其他场景中,这种方法允许我混合和重用操作,并且在迁移到MVC 4时,我不愿意放弃这种灵活性。

如何重定向MVC操作而不返回301?(使用MVC 4测试版)

有时我认为"MVC"应该被称为"路由器-控制器模型视图"的"RCMV",因为这确实是事情发生的顺序。此外,由于它只是"MVC",人们总是倾向于忘记路由。MVC的伟大之处在于路由是可配置和可扩展的。我相信您尝试做的事情可以通过自定义路由处理程序来解决。

我还没有测试过,但你应该可以做这样的事情:

routes.Add(
   new Route(
       "{controller}/{action}/{id}", 
       new RouteValueDictionary(new { controller = "Home", action = "Menu" }), 
       new MyRouteHandler(Roles.Administrator, new { controller = "Admin" })));

然后你的路线处理程序会是这样的:

public class MyRouteHandler : IRouteHandler
{
    public string Role { get; set; }
    public object RouteValues { get; set; }
    public MyRouteHandler(string role, object routeValues)
    {
        Role = role;
        RouteValues = routeValues;
    }
    public IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        return new MyHttpHandler(Role, RouteValues);
    }
}

最后在HttpHandler中处理重新路由:

public class MyHttpHandler : IHttpHandler
{
    public string Role { get; set; }
    public object RouteValues { get; set; }
    public MyHttpHandler(string role, object routeValues)
    {
        Role = role;
        RouteValues = routeValues;
    }
    public void ProcessRequest(HttpContext httpContext)
    {
        if (httpContext.User.IsInRole(Role))
        {
            RouteValueDictionary routeValues = new RouteValueDictionary(RouteValues);
            // put logic here to create path similar to what you were doing
            // before but you will need to replace any keys in your route 
            // with the values from the dictionary created above.
            httpContext.RewritePath(path);
        }
        IHttpHandler handler = new MvcHttpHandler();
        handler.ProcessRequest(httpContext);
    }
}

这可能不是100%正确的,但它应该让你朝着正确的方向前进,而不应该在MVC4中遇到任何不推荐的东西。

我认为TransferResult应该包含在框架中,而不是每个开发人员都在崩溃时为不同的版本重新实现它。(就像在这个线程中,例如下面的线程:在MVC 3 RC中实现TransferResult-不起作用)。

如果你同意我的观点,我只想鼓励你投票支持"Server.Transfer"被纳入MVC框架本身:http://aspnetwebstack.codeplex.com/workitem/798