LockRecursionException 从 .Net 4 中的另一个路由的 GetVirtualData 调用 Route.GetVirtualPath

发布于 2024-09-07 21:15:43 字数 1209 浏览 5 评论 0 原文

我在 ASP.Net MVC 2 应用程序中最后定义了一个路由,它将不再使用的旧 url 映射到要重定向到的相应新 url。该路由返回负责实际执行重定向的操作和控制器,并且还返回控制器操作的 url,这是要重定向到的 url。由于路由负责生成要重定向到的新 url,因此它会调用路由器来获取适当的 url。这在 .Net 3.5 上运行得很好,但是当我升级到 .Net 4 时,GetVirtualPath 方法会抛出 System.Threading.LockRecursionException:“此模式下不允许递归读取锁定获取。”。以下代码解决了该问题,但非常难看:

public static string GetActionUrl(HttpContextBase context, string routeName, object routeValues)
    {
        RequestContext requestContext = new RequestContext(context, new RouteData());
        VirtualPathData vp = null;

        try
        {
            vp = _Routes.GetVirtualPath(requestContext, routeName, new RouteValueDictionary(routeValues));
        }
        catch (System.Threading.LockRecursionException)
        {
            var tmpRoutes = new RouteCollection();
            Router.RegisterRoutes(tmpRoutes);
            vp = tmpRoutes.GetVirtualPath(requestContext, routeName, new RouteValueDictionary(routeValues));
        }

        if (vp == null)
            throw new Exception(String.Format("Could not find named route {0}", routeName));

        return vp.VirtualPath;
    }

有人知道 .Net 4 中的哪些更改可能导致此错误吗?另外,从另一条路线的 GetRouteData 方法调用一条路线是否只是不好的做法,我根本不应该这样做?

I have a route defined last in my ASP.Net MVC 2 app that will map old urls that are no longer used to the appropriate new urls to be redirected to. This route returns the action and controller that is responsible for actually performing the redirect and it also returns a url to the controller action which is the url to redirect to. Since the route is responsible for generating the new url to redirect to, it is calling the router to get the appropriate urls. This has worked just fine with .Net 3.5, but when I upgraded to .Net 4, the GetVirtualPath method throws a System.Threading.LockRecursionException: "Recursive read lock acquisitions not allowed in this mode.". The following code resolves the problem but is pretty ugly:

public static string GetActionUrl(HttpContextBase context, string routeName, object routeValues)
    {
        RequestContext requestContext = new RequestContext(context, new RouteData());
        VirtualPathData vp = null;

        try
        {
            vp = _Routes.GetVirtualPath(requestContext, routeName, new RouteValueDictionary(routeValues));
        }
        catch (System.Threading.LockRecursionException)
        {
            var tmpRoutes = new RouteCollection();
            Router.RegisterRoutes(tmpRoutes);
            vp = tmpRoutes.GetVirtualPath(requestContext, routeName, new RouteValueDictionary(routeValues));
        }

        if (vp == null)
            throw new Exception(String.Format("Could not find named route {0}", routeName));

        return vp.VirtualPath;
    }

Does anybody know what changes in .Net 4 might have caused this error? Also, is calling a route from another route's GetRouteData method just bad practice and something I should not be doing at all?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

红墙和绿瓦 2024-09-14 21:15:43

正如您所了解的,不支持从全局路由表中的另一个路由中调用全局路由表中的路由。

全局路由表是一个线程安全的集合,可启用多个读取器或单个路由器。不幸的是,即使在 .NET 3.5 中,您所拥有的代码也从未受到支持,尽管在某些情况下它可能会碰巧起作用。

作为一般说明,路线应该相互独立地运行,所以我不确定您的情况是什么。

As you figured out, it is not supported to call a route in the global route table from within another route in the global route table.

The global route table is a thread-safe collection to enable multiple readers or a single router. Unfortunately the code you have was never supported, even in .NET 3.5, though in some scenarios it may have coincidentally worked.

As a general note, routes should function independent of one another, so I'm not sure what your scenario is here.

梦巷 2024-09-14 21:15:43

v3.5 RouteCollection 使用以下代码:

private ReaderWriterLockSlim _rwLock;
public IDisposable GetReadLock()
{
   this._rwLock.EnterReadLock();
   return new ReadLockDisposable(this._rwLock);
}

v4.0 RouteCollection 使用以下代码:

private ReaderWriterLock _rwLock;
public IDisposable GetReadLock()
{
   this._rwLock.AcquireReaderLock(-1);
   return new ReadLockDisposable(this._rwLock);
}

GetRouteData(HttpContextBase httpContext) 在两个版本中都使用以下代码:

public RouteData GetRouteData(HttpContextBase httpContext)
{
...
   using (this.GetReadLock())
   {

GetVirtualPath 使用相同的逻辑。
v4.0 中使用的 ReaderWriterLock 默认情况下不允许递归读锁,这就是发生错误的原因。

将路由复制到新的 RouteCollection 进行第二次查询,或者通过反射更改 ReaderWriterLock 模式。

v3.5 RouteCollection uses the following code:

private ReaderWriterLockSlim _rwLock;
public IDisposable GetReadLock()
{
   this._rwLock.EnterReadLock();
   return new ReadLockDisposable(this._rwLock);
}

v4.0 RouteCollection uses the following code:

private ReaderWriterLock _rwLock;
public IDisposable GetReadLock()
{
   this._rwLock.AcquireReaderLock(-1);
   return new ReadLockDisposable(this._rwLock);
}

GetRouteData(HttpContextBase httpContext) in both versions use the following code:

public RouteData GetRouteData(HttpContextBase httpContext)
{
...
   using (this.GetReadLock())
   {

GetVirtualPath uses the same logic.
The ReaderWriterLock used in v4.0 does not allow Recursive read locks by default which is why the error is occurring.

Copy routes to a new RouteCollection for second query, or change the ReaderWriterLock mode by reflecting in.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文