使用 RouteBase 的 C# MVC 路由
C# MVC Routing With RouteBase
我的 Web 应用程序上有一个自定义路由系统,其中有一个包含我的路由的数据库(url
、Controller
、Action
和更多信息)。对服务器发出的每个请求都会进入数据库,通过 url 和 returns 查询该路由,我需要为将来的渲染保持可访问性 Filter
,Controller
和 View
,我将这些数据保存在我的 Global.asax 文件中的全局变量中:
public static class GlobalVars
{
public static Redirect reqContext { get; set; }
public static UnidadeHotSite HotSite { get; set; }
}
我的问题是,现在这些信息在用户之间混杂在一起,有时当我在浏览器中打开 3 个标签时,我会在 "almost" 刷新它们,同时最后一个会获取上一个加载的路由数据
例如,我的 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;
}
}
这是在数据库上进行搜索的控制器
[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)。
此外,顺便说一句,我注意到您在 BuscaURLWS
和 BuscaURLHS
中重复了代码——不要那样做!有关详细信息,请参阅 DRY for why not. Also, you're doing your URL tokenization manually; there are plenty of tools for doing that easily (see Uri。
您的方法存在几个问题:
- 切勿扩展
MvcRouteHandler
来制作自定义 URL 方案。 URL 路由是一个双向进程,路由处理程序只能处理传入路由,但不能构建传出路由 URL。
- 你实际上 "routing" 不在这里。路由意味着您正在将传入请求映射到资源。您正在做的是允许请求进入,决定如何处理它,然后 将浏览器重定向 到另一个 URL。这会导致另一个不必要的服务器往返,这对性能和 SEO 不利。
- OutputCache 属性仅适用于控制器操作方法,并且仅适用于视图的缓存 content。它不适用于缓存数据。
如果你想要数据库驱动的路由,你应该继承 RouteBase
。这使您有机会将 URL 映射到一组路由值(代表控制器操作和参数),并将路由值映射回 URL(因此 ActionLink
和 RouteLink
将在您的视图中正常工作)。
查看 以获得可靠的方法。它还包括 URL 数据缓存和线程锁定,以确保在缓存过期时仅由单个线程更新缓存(并且数据库仅调用一次)。
如果您需要使其更具可重用性(即使用更多控制器和操作方法),您可以通过传递控制器和操作信息以及数据使其更通用,类似于此 通过自定义 RouteBase
的构造函数提供提供程序实例,并在您的配置中多次注册路由(当然使用不同的参数)。
我的 Web 应用程序上有一个自定义路由系统,其中有一个包含我的路由的数据库(url
、Controller
、Action
和更多信息)。对服务器发出的每个请求都会进入数据库,通过 url 和 returns 查询该路由,我需要为将来的渲染保持可访问性 Filter
,Controller
和 View
,我将这些数据保存在我的 Global.asax 文件中的全局变量中:
public static class GlobalVars
{
public static Redirect reqContext { get; set; }
public static UnidadeHotSite HotSite { get; set; }
}
我的问题是,现在这些信息在用户之间混杂在一起,有时当我在浏览器中打开 3 个标签时,我会在 "almost" 刷新它们,同时最后一个会获取上一个加载的路由数据
例如,我的 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;
}
}
这是在数据库上进行搜索的控制器
[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)。
此外,顺便说一句,我注意到您在 BuscaURLWS
和 BuscaURLHS
中重复了代码——不要那样做!有关详细信息,请参阅 DRY for why not. Also, you're doing your URL tokenization manually; there are plenty of tools for doing that easily (see Uri。
您的方法存在几个问题:
- 切勿扩展
MvcRouteHandler
来制作自定义 URL 方案。 URL 路由是一个双向进程,路由处理程序只能处理传入路由,但不能构建传出路由 URL。 - 你实际上 "routing" 不在这里。路由意味着您正在将传入请求映射到资源。您正在做的是允许请求进入,决定如何处理它,然后 将浏览器重定向 到另一个 URL。这会导致另一个不必要的服务器往返,这对性能和 SEO 不利。
- OutputCache 属性仅适用于控制器操作方法,并且仅适用于视图的缓存 content。它不适用于缓存数据。
如果你想要数据库驱动的路由,你应该继承 RouteBase
。这使您有机会将 URL 映射到一组路由值(代表控制器操作和参数),并将路由值映射回 URL(因此 ActionLink
和 RouteLink
将在您的视图中正常工作)。
查看
如果您需要使其更具可重用性(即使用更多控制器和操作方法),您可以通过传递控制器和操作信息以及数据使其更通用,类似于此 RouteBase
的构造函数提供提供程序实例,并在您的配置中多次注册路由(当然使用不同的参数)。