0

一些背景,我的問題:修補Asp.net MVC2 AntiForgeryToken例外

看來,有在MVC2關於ValidateAntiForgeryTokenAttribute變化/錯誤。

無法轉換類型的對象「System.Web.UI.Triplet」:

當從MVC1升級到MVC2,用戶有活動會話時將它們請求使用ValidateAntiForgeryTokenAttribute一個頁面收到以下錯誤鍵入'System.Object []'。

該問題記錄在here

升級到Mvc2後,我們預計我們會受到這個問題的嚴重影響。我已經編寫了源自代碼的修復(下文記錄爲後代)。此刻,通過創建ControllerAsyncController的子類來覆蓋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

可以在升級前斷開大家? – 2010-09-28 15:38:45

+0

如果可能,我們不希望如此。 – spender 2010-09-28 15:40:38

+0

我知道它並不能幫助你解決問題。我們很幸運能夠在3個月前對我們所有的用戶進行類似升級之前清除緩存/ Cookie。我圍繞着試圖找到潛在問題的可行解決方案。最後(這是一個只有50個用戶的業務應用程序),我們只是通過郵件告知他們如何清除「垃圾」。當然,如果你的網站是公共網站,那麼上述可能是唯一的行動方針。我將密切關注這個問題,因爲我對一些即將開展的工作感興趣。 – 2010-09-28 15:44:35

回答

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 2010-09-28 16:09:24

+0

ok - 在這種情況下,基礎控制器的單個更改不會涓滴到從它繼承的所有內容??。當然,我假設你總是有一個基礎控制器,因此我的偶然建議。否則,我想陪審團仍然沒有: – 2010-09-28 16:14:08

+0

當然......這正是計劃,所以這樣的事情是非常好的控制之下。我真的想知道一般水平,如果這是一個不太乾擾的方法修補不好的代碼。直到有人說不同,我很高興我採取了最好的方法 – spender 2010-09-28 16:18:23