0

Некоторые фон в мой вопрос:заплат Asp.net MVC2 AntiForgeryToken исключение

Оказывается, что есть изменение/ошибка в MVC2 относительно ValidateAntiForgeryTokenAttribute.

При обновлении с Mvc1 до MVC2, пользователи с активной сессии будет получить следующее сообщение об ошибке при запросе страницы с помощью ValidateAntiForgeryTokenAttribute:

Невозможно привести объект типа «» System.Web.UI.Triplet для ввода «System.Object []».

Проблема документирована here.

После обновления до Mvc2 мы ожидаем, что эта проблема будет серьезно затронута. Я закодировал исправление, полученное из кода в комментариях (ниже описано ниже для потомков). В настоящий момент этот код вызывается путем создания подкласса Controller и AsyncController, переопределяя метод Initialize, чтобы исправить проблему. например

public class FixedController:Controller 
{ 
    protected override void Initialize(RequestContext requestContext) 
    { 
     base.Initialize(requestContext); 
     this.FixAntiForgeryTokenMvc1ToMvc2(requestContext); //extension 
    } 
} 

internal static class ControllerEx 
{ 
    public static void FixAntiForgeryTokenMvc1ToMvc2(
     this Controller controller, 
     RequestContext requestContext) 
    { 
     var cc = new ControllerContext(requestContext, 
             controller); 
     var antiForgeryAttribute = new ValidateAntiForgeryTokenAttribute(); 
     try 
     { 
      antiForgeryAttribute.OnAuthorization(new AuthorizationContext(cc)); 
     } 
     catch (HttpAntiForgeryException forgeryException) 
     { 
      var castException = forgeryException.InnerException; 
      if (castException != null 
       && castException is InvalidCastException 
       && castException.Message.StartsWith(
         "Unable to cast object of type" 
         + " 'System.Web.UI.Triplet' to type" 
         + " 'System.Object[]'")) 
      { 
       var responseTokenCookieNames = 
        controller 
         .Response 
         .Cookies 
         .Cast<Cookie>() 
         .Select(c => c.Name) 
         .Where(n => n.Contains("RequestVerificationToken")); 
       foreach (var s in responseTokenCookieNames) 
       { 
        var cookie = controller.Response.Cookies[s]; 
        if (cookie != null) 
        { 
         cookie.Value = ""; 
        } 
       } 
       var requestTokenCookieNames = 
        controller 
         .Request 
         .Cookies 
         .Cast<String>() 
         .Where(n => n.Contains("RequestVerificationToken")) 
         .ToList(); 
       foreach (var c in requestTokenCookieNames) 
       { 
        controller.Request.Cookies.Remove(c); 
       } 
      } 
     } 
    } 
} 

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

Итак, подойдя к моему вопросу, я хотел бы знать, существует ли менее навязчивое средство для исправления существующих классов, так что нисходящие пользователи этого класса не должны быть изменены, возможно, используя отражение?

+0

Можете ли вы отключить всех до обновления? –

+0

Мы предпочли бы, если это возможно. – spender

+0

Я знаю, что это не поможет вам в ваших поисках. нам повезло, что мы смогли сообщить всем нашим пользователям очистить их кеш/файлы cookie, прежде чем мы сделали аналогичное обновление около 3 месяцев назад. я обошел круги, пытаясь найти жизнеспособное решение потенциальных проблем. в конце (это была линейка бизнес-приложений с 50 пользователями), мы просто наняли их инструкциями о том, как очистить «мусор». конечно, если ваш сайт является общедоступным, то, возможно, это единственный способ действий. я буду внимательно следить за этим, поскольку исправление в одном месте для какой-то работы и предстоящей работы представляет интерес для меня. –

ответ

1

Спендер,

вместо кода каждый контроллер, используйте basecontroller и наследовать от вдоль линий:

public abstract class BaseController : Controller 
{ 
    protected override void Initialize(RequestContext requestContext) 
    { 
     base.Initialize(requestContext); 
     FixAntiForgeryTokenMvc1ToMvc2(this, requestContext); 
    } 
    private static void FixAntiForgeryTokenMvc1ToMvc2(
     Controller controller, RequestContext requestContext) 
    { 
     // stuff .... 
    } 
} 

и в ваших 'нормальных' контроллеров, просто:

public class NormalController : BaseController 
{ 
    // all the previous stuff 
} 

дайте это ...

+0

Это то, что я делаю. Он по-прежнему требует изменения всех контроллеров для получения новой базы. – spender

+0

ok - в этом случае, не будет ли одно изменение вашего базового контроллера просачиваться во все, что унаследовано от него?. конечно, я предполагаю, что у вас всегда есть базовый контроллер, поэтому мое случайное предложение. в противном случае, я думаю, что жюри все еще вышло :( –

+0

Конечно ... это точно такой план, так как такие вещи довольно хорошо под контролем. Мне действительно было интересно на общем уровне, если theres менее навязчивый метод исправления плохого кода. Пока кто-то не говорит по-другому, я довольно счастлив, что нашел наилучший подход. – spender

Смежные вопросы