Исключение LockRecursionException, вызывающее Route.GetVirtualPath из GetVirtualData другого маршрута в .Net 4 - PullRequest
0 голосов
/ 29 июня 2010

В моем приложении 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 другого маршрута просто плохой практикой и что-то, что я вообще не должен делать?

Ответы [ 2 ]

1 голос
/ 07 декабря 2011

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 использует ту же логику. ReaderWriterLock, используемый в v4.0, по умолчанию не допускает рекурсивные блокировки чтения, поэтому возникает ошибка.

Скопируйте маршруты в новую коллекцию RouteCollection для второго запроса или измените режим ReaderWriterLock, указав в.

1 голос
/ 11 июля 2010

Как вы выяснили, не поддерживается вызов маршрута в глобальной таблице маршрутов из другого маршрута в глобальной таблице маршрутов.

Таблица глобальных маршрутов - это потокобезопасная коллекция для включения нескольких считывателей или одного маршрутизатора. К сожалению, ваш код никогда не был поддержан, даже в .NET 3.5, хотя в некоторых случаях он мог работать по совпадению.

Как общее примечание, маршруты должны функционировать независимо друг от друга, поэтому я не уверен, какой у вас здесь сценарий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...