使用 RouteBase 的 C# MVC 路由

C# MVC Routing With RouteBase

我的 Web 应用程序上有一个自定义路由系统,其中有一个包含我的路由的数据库(urlControllerAction 和更多信息)。对服务器发出的每个请求都会进入数据库,通过 url 和 returns 查询该路由,我需要为将来的渲染保持可访问性 FilterControllerView,我将这些数据保存在我的 Global.asax 文件中的全局变量中:

public static class GlobalVars
{
    public static Redirect reqContext { get; set; }
    public static UnidadeHotSite HotSite { get; set; }
}

我的问题是,现在这些信息在用户之间混杂在一起,有时当我在浏览器中打开 3 个标签时,我会在 "almost" 刷新它们,同时最后一个会获取上一个加载的路由数据

例如,我的 HotSite var 保留了一些子站点信息,如 nameurlID 等,子站点 url 将是: abc.com/subsite。当我加载第一个选项卡时,我得到了正确的数据,即子站点数据,第二个选项卡不在子站点区域,abc.com,我得到的数据与上次加载的选项卡相同。

现在,可能是什么问题?我已经在 OutputCache 上使用了 NoStore 并尝试禁用会话,但似乎没有任何效果。

这是我的路由处理程序:

[OutputCache( NoStore = true, Duration = 0 )]
public class RouteHandler : MvcRouteHandler
{
    private static string RedirectAction { get; set; }
    private static string UnidadeURL { get; set; }

    protected override IHttpHandler GetHttpHandler( RequestContext requestContext )
    {
        var friendlyUrl = (string)requestContext.RouteData.Values["RedirectUrl"];
        var objRet      = BuscaURL( friendlyUrl, requestContext );

        GlobalVars.reqContext = objRet[0] as Redirect;

        return base.GetHttpHandler(objRet[1] as RequestContext);
    }

    private static object[] BuscaURL( string pURL, RequestContext reqContext )
    {
        RedirectAction = "Index";
        var isHotSite  = BuscaHotSiteInfo( pURL );

        var tRedirect = !isHotSite ? BuscaURLWS( pURL ) : BuscaURLHS( pURL );

        if( tRedirect == null || "NotFound".Equals( tRedirect.controller ) )
        {
            Configuracoes.GeraLog( "pURL", pURL );
            if(tRedirect == null)
                Configuracoes.GeraLog( "tRedirect", "NULL" );
            else
                HelperController.GeraLog( tRedirect );

            tRedirect      = RedirectController.BuscaPaginaPorUrlWS( 5 );
            RedirectAction = "Index";

            reqContext.RouteData.DataTokens["Namespaces"] = "Site.Controllers";
        }

        if( tRedirect != null && tRedirect.paginaId > 0 && RedirectAction == "Index" )
        {
            using( var db = new SkillSite() )
            {
                var pagina = db.Pagina.First( x => x.ID == tRedirect.paginaId && x.ativo == 1 );
                RedirectAction = pagina.action;
            }
        }

        reqContext.RouteData.Values["controller"] = tRedirect.controller;
        reqContext.RouteData.Values["action"]     = RedirectAction;
        reqContext.RouteData.Values["id"]         = tRedirect.ID;

        return new object[] { tRedirect, reqContext };
    }

    private static Redirect BuscaURLHS( string pUrl )
    {
        Redirect redirect = null;

        pUrl = pUrl.Replace( UnidadeURL, "" ).Replace( "teste", "" ).TrimStart( '/' ).TrimEnd( '/' );

        if( !string.IsNullOrEmpty( pUrl ) && !string.IsNullOrWhiteSpace( pUrl ) )
        {
            var splitUrl = pUrl.Split( '/' ).ToList();

            if( splitUrl.Count > 1 )
            {
                if( "cursos".Equals( splitUrl[0] ) )
                {
                    if( splitUrl.Count == 2 )
                    {
                        redirect = RedirectController.SearchPageByUrlWS( 1, splitUrl[1] );
                    }
                    else if( splitUrl.Count == 3 )
                    {
                        redirect = RedirectController.SearchPageByUrlWS( 2, splitUrl[1], splitUrl[2] );
                    }
                }
            }
            else
            {
                redirect = RedirectController.SearchPageByUrlWS( 0, "", "", splitUrl[0] );
            }
        }
        else
        {
            redirect = RedirectController.SearchPageByUrlWS( 0, "", "", "home" );
        }

        return redirect;
    }

    private static Redirect BuscaURLWS( string pUrl )
    {
        Redirect redirect = null;

        if( !string.IsNullOrEmpty( pUrl ) && !string.IsNullOrWhiteSpace( pUrl ) )
        {
            var splitUrl = pUrl.TrimEnd( '/' ).Split( '/' ).ToList();

            if( splitUrl.Count > 1 )
            {
                if( "cursos".Equals( splitUrl[0] ) )
                {
                    if( splitUrl.Count == 2 )
                    {
                        redirect = RedirectController.SearchPageByUrlHS( 1, splitUrl[1] );
                    }
                    else if( splitUrl.Count == 3 )
                    {
                        redirect = RedirectController.SearchPageByUrlHS( 2, splitUrl[1], splitUrl[2] );
                    }
                }
            }
            else
            {
                redirect = RedirectController.SearchPageByUrlHS( 0, "", "", splitUrl[0] );
            }
        }
        else
        {
            redirect = RedirectController.SearchPageByUrlHS( 0, "", "", "home" );
        }

        return redirect;
    }
}

这是在数据库上进行搜索的控制器

[OutputCache( NoStore = true, Duration = 0 )]
public class RedirectController
{
    public static Redirect SearchPageByUrlWS( int tipo, string cursoCURL = "", string cursoURL = "", string redirectURL = "", string redirectURLTwo = "" )
    {
        using( var db = new Site() )
        {
            IQueryable<Redirect> redirects;

            if( tipo == 1 )
            {
                redirects = from redirect in db.Redirect
                            where redirect.url == cursoCURL && redirect.cursoCatId > 0
                            select redirect;
            }
            else
            {
                redirects = from redirect in db.Redirect
                            where redirect.url == redirectURL &&
                            redirect.cursoCatId == 0 &&
                            redirect.regulamentoId == 0 &&
                            redirect.noticiaId == 0 &&
                            redirect.ebookId == 0 &&
                            redirect.conhecaId == 0
                            select redirect;
            }

            return (redirects.ToList().Count > 0) ? redirects.ToList()[0] : null;
        }
    }

    public static HS_Redirect SearchPageByUrlHS( int tipo, string cursoCURL = "", string cursoURL = "", string redirectURL = "", string redirectURLTwo = "" )
    {
        using( var dbHS = new HS() )
        {
            IQueryable<HS_Redirect> redirects;

            if( tipo == 4 )
            {
                redirects = from redirect in dbHS.HS_Redirect
                            where redirect.url == redirectURL && redirect.noticiaId > 0 && redirect.unidadeCE == GlobalVars.HotSite.unidadeHS.unidadeCE
                            select redirect;
            }
            else
            {
                redirects = from redirect in dbHS.HS_Redirect
                            where
                                redirect.url           == redirectURL &&
                                redirect.cursoCatId    == 0 &&
                                redirect.regulamentoId == 0 &&
                                redirect.noticiaId     == 0 &&
                                redirect.ebookId       == 0 &&
                                redirect.conhecaId     == 0
                            select redirect;
            }

            return ( redirects.ToList().Count > 0 ) ? redirects.ToList()[0] : null;
        }
    }
}

编辑:

我设法让@NightOwl888 的回答与区域和我需要的其他一切一起工作,我不会在这里 post 因为它有点大所以这里是代码:http://pastebin.com/yTdWKMp4

编辑 2

我更新了 pastebin 上的文件,进行了一些更改以提高速度和可用性:http://pastebin.com/yTdWKMp4

您正在使用 static 属性...通常不是一个好主意,除非您可以做出某些保证 - 在这种情况下,可以保证此数据将在您的应用程序的所有用户之间共享域名。

基本上,使用 Session 存储来跟踪 个人用户的 设置(有关详细信息,请参阅 this article)。

此外,顺便说一句,我注意到您在 BuscaURLWSBuscaURLHS 中重复了代码——不要那样做!有关详细信息,请参阅 DRY for why not. Also, you're doing your URL tokenization manually; there are plenty of tools for doing that easily (see Uri

您的方法存在几个问题:

  1. 切勿扩展 MvcRouteHandler 来制作自定义 URL 方案。 URL 路由是一个双向进程,路由处理程序只能处理传入路由,但不能构建传出路由 URL。
  2. 你实际上 "routing" 不在这里。路由意味着您正在将传入请求映射到资源。您正在做的是允许请求进入,决定如何处理它,然后 将浏览器重定向 到另一个 URL。这会导致另一个不必要的服务器往返,这对性能和 SEO 不利。
  3. OutputCache 属性仅适用于控制器操作方法,并且仅适用于视图的缓存 content。它不适用于缓存数据。

如果你想要数据库驱动的路由,你应该继承 RouteBase。这使您有机会将 URL 映射到一组路由值(代表控制器操作和参数),并将路由值映射回 URL(因此 ActionLinkRouteLink 将在您的视图中正常工作)。

查看 以获得可靠的方法。它还包括 URL 数据缓存和线程锁定,以确保在缓存过期时仅由单个线程更新缓存(并且数据库仅调用一次)。

如果您需要使其更具可重用性(即使用更多控制器和操作方法),您可以通过传递控制器和操作信息以及数据使其更通用,类似于此 通过自定义 RouteBase 的构造函数提供提供程序实例,并在您的配置中多次注册路由(当然使用不同的参数)。