C# MVC Routing With RouteBase
本文关键字:RouteBase With Routing MVC | 更新日期: 2023-09-27 18:15:48
我有一个自定义路由系统在我的web应用程序,我有一个数据库与我的路由(url
, Controller
, Action
和一些更多的信息)。向服务器发出的每个请求都进入数据库,通过url查询该路由并返回一组我需要为未来渲染Filter
, Controller
和View
保持可访问性的内容,我将此数据保存在全局变量中。asax文件:
public static class GlobalVars
{
public static Redirect reqContext { get; set; }
public static UnidadeHotSite HotSite { get; set; }
}
我的问题是,现在这个信息是通过用户混合,有时当我在我的浏览器,我有3个打开的选项卡,我刷新他们在"几乎"同一时间,最后一个将获得前一个加载的路由数据。
例如,我的HotSite
var保留了一些子网站信息,如name
, url
, ID
等,子网站的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;
}
}
这是在DB
上进行搜索的控制器[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回答工作与区域和其他一切我需要的,我不打算在这里张贴,因为它有点大,所以这里是代码:http://pastebin.com/yTdWKMp4
编辑2
我已经更新了pastebin上的文件与一些变化,以提高速度和可用性:http://pastebin.com/yTdWKMp4
你的方法有几个问题:
- 永远不要扩展
MvcRouteHandler
来创建自定义URL方案。URL路由是一个双向过程,路由处理程序只能处理传入路由,但不能构建传出的URL。 - 你实际上不是"路由"在这里。路由意味着您正在将传入的请求映射到资源。您所做的是允许请求进入,决定如何处理它,然后将浏览器重定向到另一个URL。这会导致不必要的服务器往返,这对性能和搜索引擎优化不利。
- OutputCache属性只作用于控制器动作方法,并且它只适用于缓存视图的内容。它不适用于缓存数据。
如果你想有数据库驱动的路由,你应该子类化RouteBase
。这让你有机会将URL映射到一组路由值(代表控制器动作和参数),也可以将路由值映射回URL(因此ActionLink
和RouteLink
将在你的视图中正确工作)。
看看这个答案,找到一个可靠的方法。它还包括URL数据的缓存和线程锁定,以确保缓存过期时仅由单个线程更新缓存(并且数据库仅被调用一次)。
如果你需要使它更可重用(也就是说,使用更多的控制器和动作方法),你可以使它更通用类似于这个MVC 6样例通过传递控制器和动作信息和一个数据提供程序实例,通过您的自定义RouteBase
的构造函数,并在您的配置中注册路由多次(当然,使用不同的参数)。
您正在使用static
属性…通常不是一个好主意,除非你能做出一定的保证——在这种情况下,有一个保证,这个数据将被您的应用程序域的所有用户共享。
基本上,使用Session
存储来跟踪单个用户的设置(有关更多信息,请参阅本文)。另外,作为题外话,我注意到你在BuscaURLWS
和BuscaURLHS
中重复了代码——不要这样做!请参阅DRY了解为什么不可以。此外,你正在做你的URL标记化手动;有很多工具可以轻松地做到这一点(有关更多信息,请参阅Uri)。