Errore di ViewState su ASP.NET MVC

Anche se il titolo è un po’ fuorviante, devo dire che il messaggio “Invalid viewstate” è apparso realmente; ma procediamo con ordine.
Molti di voi si saranno accorti che ultimamente, quando si accedeva al dettaglio di un post sul mio blog, si verificava in maniera del tutto casuale un errore e la navigazione dell’utente veniva deviata verso una pagina di cortesia.
Purtroppo l’errore non è dovuto a Dexter - dico purtroppo perchè altrimenti l’avrei corretto da tempo - ma ad una serie di fattori che non sono neanche riuscito a riprodurre sistematicamente; sta di fatto che l’applicazione andava in crash quando invocava l’helper AntiForgeryToken, restituendo il seguente stack tracce:

System.Web.HttpException: Error executing child request for handler 'System.Web.Mvc.HttpHandlerUtil+ServerExecuteHttpHandlerWrapper'.

---> System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not supplied or was invalid. --->

System.Web.HttpException: Validation of viewstate MAC failed. If this application is hosted by a Web Farm or cluster, ensure that

configuration specifies the same validationKey and validation algorithm. AutoGenerate cannot be used in a cluster. --->

System.Web.UI.ViewStateException: Invalid viewstate.
    Client IP: 94.86.54.138
    Port: 44787
    User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; it; rv:1.9.1.9) Gecko/20100315 Firefox/3.5.9
    ViewState: eMzLc7Gx/IAC2ALGLNZWrgie4SgDWbcFeooL0JSADQan8USvQo7F0Fgx3u0m4aB4
    Referer:
    Path: /blog/post/welcome-parallel-linq ---> System.Security.Cryptography.CryptographicException: Padding is invalid and cannot

be removed.
   at System.Security.Cryptography.RijndaelManagedTransform.DecryptData(Byte[] inputBuffer, Int32 inputOffset, Int32 inputCount, Byte

[]& outputBuffer, Int32 outputOffset, PaddingMode paddingMode, Boolean fLast)
   at System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock(Byte[] inputBuffer, Int32 inputOffset, Int32

inputCount)
   at System.Security.Cryptography.CryptoStream.FlushFinalBlock()
   at System.Web.Configuration.MachineKeySection.EncryptOrDecryptData(Boolean fEncrypt, Byte[] buf, Byte[] modifier, Int32 start,

Int32 length, IVType ivType, Boolean useValidationSymAlgo)
   at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
   --- End of inner exception stack trace ---
   --- End of inner exception stack trace ---
   at System.Web.UI.ViewStateException.ThrowError(Exception inner, String persistedState, String errorPageMessage, Boolean

macValidationError)
   at System.Web.UI.ObjectStateFormatter.Deserialize(String inputString)
   at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
   --- End of inner exception stack trace ---
   at System.Web.Mvc.AntiForgeryDataSerializer.Deserialize(String serializedToken)
   at System.Web.Mvc.HtmlHelper.GetAntiForgeryTokenAndSetCookie(String salt, String domain, String path)
   at System.Web.Mvc.HtmlHelper.AntiForgeryToken(String salt, String domain, String path)
   at System.Web.Mvc.HtmlHelper.AntiForgeryToken()
   at ASP.themes_default_views_blog_post_aspx.__RenderContent1(HtmlTextWriter __w, Control parameterContainer) in c:\domains

\tostring.it\wwwroot\Themes\Default\Views\Blog\Post.aspx:line 113
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at ASP.themes_default_views_shared_site_master.__Render__control1(HtmlTextWriter __w, Control parameterContainer) in c:\domains

\tostring.it\wwwroot\Themes\Default\Views\Shared\Site.Master:line 113
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Control.RenderChildrenInternal(HtmlTextWriter writer, ICollection children)
   at System.Web.UI.Page.Render(HtmlTextWriter writer)
   at System.Web.Mvc.ViewPage.Render(HtmlTextWriter writer)
   at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
   at System.Web.UI.Page.ProcessRequest()
   at System.Web.UI.Page.ProcessRequest(HttpContext context)
   at System.Web.Mvc.ViewPage.ProcessRequest(HttpContext context)
   at ASP.themes_default_views_blog_post_aspx.ProcessRequest(HttpContext context) in c:\windows\Microsoft.NET

\Framework64\v2.0.50727\Temporary ASP.NET Files\root\878362b4\44ad105e\App_Web_qkslf0lt.1.cs:line 0
   at System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.<>c__DisplayClass1.b__0()
   at System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.<>c__DisplayClass4.b__3()
   at System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.Wrap[TResult](Func`1 func)
   at System.Web.Mvc.HttpHandlerUtil.ServerExecuteHttpHandlerWrapper.Wrap(Action action)
   at System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean

setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride)
   --- End of inner exception stack trace ---
   at System.Web.HttpServerUtility.ExecuteInternal(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean

setPreviousPage, VirtualPath path, VirtualPath filePath, String physPath, Exception error, String queryStringOverride)
   at System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm, Boolean setPreviousPage)
   at System.Web.HttpServerUtility.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
   at System.Web.HttpServerUtilityWrapper.Execute(IHttpHandler handler, TextWriter writer, Boolean preserveForm)
   at System.Web.Mvc.ViewPage.RenderView(ViewContext viewContext)
   at System.Web.Mvc.ViewResultBase.ExecuteResult(ControllerContext context)
   at System.Web.Mvc.ControllerActionInvoker.<>c__DisplayClass14.b__11()
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1

continuation)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultFilter(IResultFilter filter, ResultExecutingContext preContext, Func`1

continuation)
   at System.Web.Mvc.ControllerActionInvoker.InvokeActionResultWithFilters(ControllerContext controllerContext, IList`1 filters,

ActionResult actionResult)
   at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at Dexter.Web.Mvc.Controllers.DexterActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
   at System.Web.Mvc.Controller.ExecuteCore()
   at System.Web.Mvc.MvcHandler.<>c__DisplayClass8.b__4()
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass1.b__0()
   at System.Web.Mvc.Async.AsyncResultWrapper.<>c__DisplayClass8`1.b__7(IAsyncResult _)
   at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
   at System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
ASPIMPERSONATING:

Sinceramente non so se sono riuscito a risolvere il problema: di fatto questo post è anche un appello a chi ha avuto questa problematica e l’ha risolta.

In tutte le righe del log veniva riportato come user agent quello di Internet Explorer 8 e, inizialmente, mi sono concentrato su di lui per capire la problematica; poi, guardando un po’ i logs e grazie all’aiuto del buon Giorgio ed Andrea, ci siamo accorti che il problema era su ASP.NET MVC e non su IE8 (il log mostrava sempre IE8 per il semplice motivo che il browser di casa Microsoft è molto più diffuso rispetto alla concorrenza).

Cercando in rete ho provato questa soluzione, sperando che dia i suoi frutti.
Nello specifico consiste nel registrare a mano i valori del MachineKey all’interno del nostro web.config. Ovviamente i valori da registrare sono diversi, ma fortunatamente esiste questo Generator" href="http://aspnetresources.com/tools/keycreator.aspx" rel=nofollow target=_blank>sito che ci autogenera l’apposita sezione del file di configurazione da insaaerire.

Il risultato finale del web.config dovrebbe essere una cosa del genere:

<machinekey decryption="AES" decryptionkey="CB5A09CB8CAF8CD33A97F1099A451D7C80C9CC175F34DDAFA925BA55043570CB" validation="SHA1" validationkey="E7E40ADAC94F3D467AAB86AEA2561E246A6323C69A0B32BF808587694E1CB387265CC6F2C46420F315831B54F683FA82F08A8E95E00B93BFEC3CD91DF65FEE8C"></machinekey>

stay tuned!
.u


Comments