使用RouteBase进行C#MVC路由

时间:2015-10-01 20:40:22

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

我在我的网络应用程序上有一个自定义路由系统,我有一个包含我的路由的数据库(urlControllerAction以及更多信息)。对服务器发出的每个请求都会转到数据库,查询按网址路由并返回一组我需要保持可访问的内容,以便将来呈现FilterController和{{1}我将此数据保存在Global.asax文件的全局变量中:

View

我的问题是,现在这个信息正在通过用户混合,有时当我在我的浏览器并且我有3个打开的标签并且我在“几乎”同时刷新它们同时最后一个将获得路由数据之前加载过的。

例如,我的public static class GlobalVars { public static Redirect reqContext { get; set; } public static UnidadeHotSite HotSite { get; set; } } var会保留一些子网站信息,例如HotSitenameurl等,子网址网址为:abc.com/subsite。当我加载第一个选项卡时,我获得了正确的数据,即子网站数据,第二个选项卡不在子网站区域abc.com,我得到的数据与上次加载的选项卡相同。

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

这是我的路线处理程序:

OutputCache

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

[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;
    }
}

修改

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

编辑2

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

2 个答案:

答案 0 :(得分:2)

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

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

另外,我还是注意到BuscaURLWSBuscaURLHS中的代码重复了 - 请不要这样做!有关原因,请参阅DRY。此外,您手动进行URL标记化;有很多工具可以轻松完成这项工作(有关详细信息,请参阅Uri)。

答案 1 :(得分:2)

您的方法存在一些问题:

  1. 永远不要扩展MvcRouteHandler以制作自定义网址方案。 URL路由是一个双向进程,路由处理程序只能处理传入的路由,但不构建传出的URL。
  2. 你实际上并没有“路由”。路由意味着您将传入的请求映射到资源。您正在做的是允许请求进入,决定如何处理它,然后将浏览器重定向到另一个URL。这导致另一次不必要的往返服务器,这对性能和SEO都不利。
  3. OutputCache属性仅适用于控制器操作方法,并且仅适用于缓存视图的内容。它不适用于缓存数据。
  4. 如果要使用数据库驱动的路由,则应该将RouteBase子类化。这使您有机会将URL映射到一组路由值(表示控制器操作和参数),并将路由值映射回URL(因此ActionLinkRouteLink将正常工作你的意见)。

    了解this answer的可靠方法。它还包括URL数据和线程锁定的缓存,以确保缓存仅在缓存过期时由单个线程(以及仅调用一次的数据库)更新。

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