Rexiology::Work

Microsoft, Information Technologies...

Community

News

  • From Taiwan, living and working at Tokyo, Japan.




Recent Posts

Tags

Microsoft Sites

Other Sites

Blog pools

Bloggers

Archives

Site Info



Locations of visitors to this page




Logos & Chicklets


GeoURL


Rex's Certifications
Rex's Certifications


Creative Commons授權條款
本 著作 係採用
Creative Commons 授權條款



December 2007 - Posts

asp.net: __EVENTVALIDATION is related to page virtual path...

crosspost from http://blogs.msdn.com/rextang

--- #Summary: ---

When using performance test tools to record asp.net pages for test, and later those pages were moved to different path at the same server, not only have to change the recorded test scripts to the correct paths, but also need to capture and replace the new path's "__EVENTVALIDATION" field if the pages were requested with HTTP POST. 

--- #Introduction: ---

In my project I am in charging of doing performance test using Empirix's E-Test Suite. E-Test scripts was recorded and customized for each testing asp.net page and the performance test was going well until something happened the other days.

Due to project requirement some of the asp.net pages were moved to different paths under the same server. although the pages were not modified at all, and I did modified the url path of pages in E-Test scripts, those asp.net pages that E-Test recorded with previous paths were still not working anymore and throwing exceptions as follows:

"The viewstate is invalid for this page and might be corrupted"

and the error target was at form post field "__EVENTVALIDATION".

--- #Solution: ---

The "__EVENTVALIDATION" field was encoded / encrypted using a modifier that's calculated and related to page's virtual path. thus when a page was changed to different path, the modifier will also changes and if submit the page using original "__EVENTVALIDATION" field that's generated using previous page, the event validation check will fail and throw exceptions like above.

To solve this, when pages changed paths, not only have to modify the test scripts to the correct paths, but also need to get the new paths' "__EVENTVALIDATION" field to replace the scripts' ones.

--- #More Information: ---

By looking into System.Web.dll, if Event Validation was set enabled, Page object will call ClientScriptManager object to save the event validation content to "__EVENTVALIDATION" hidden field. that's where the event validation content was generated.

   1: // under System.Web.UI.Page class...
   2: internal void EndFormRender(HtmlTextWriter writer, string formUniqueID)
   3: {
   4:     // ...
   5:  
   6:     if (this.EnableEventValidation)
   7:     {
   8:         this.ClientScript.SaveEventValidationField();
   9:     }
  10:  
  11:     // ...
  12: }
   1: // System.Web.UI.ClientScriptManager.SaveEventValidationField() code.
   2: internal void SaveEventValidationField()
   3: {
   4:     string eventValidationFieldValue = this.GetEventValidationFieldValue();
   5:     if (!string.IsNullOrEmpty(eventValidationFieldValue))
   6:     {
   7:         this.RegisterHiddenField("__EVENTVALIDATION", eventValidationFieldValue);
   8:     }
   9: }
   1: // System.Web.UI.ClientScriptManager.GetEventValidationFieldValue() code
   2: internal string GetEventValidationFieldValue()
   3: {
   4:     if ((this._validEventReferences != null) && (this._validEventReferences.Count != 0))
   5:     {
   6:         return this._owner.CreateStateFormatter().Serialize(this._validEventReferences);
   7:     }
   8:     return string.Empty;
   9: }

CreateStateFormatter() will return a System.Web.UI.ObjectStateFormatter object to serialize event validation content.

   1: // System.Web.UI.ObjectStateFormatter.Serialize() code.
   2: public string Serialize(object stateGraph)
   3: {
   4:     string str = null;
   5:     MemoryStream memoryStream = GetMemoryStream();
   6:     try
   7:     {
   8:         this.Serialize(memoryStream, stateGraph);
   9:         memoryStream.SetLength(memoryStream.Position);
  10:         byte[] buf = memoryStream.GetBuffer();
  11:         int length = (int) memoryStream.Length;
  12:         if ((this._page != null) && this._page.RequiresViewStateEncryptionInternal)
  13:         {
  14:             buf = MachineKeySection.EncryptOrDecryptData(true, buf, this.GetMacKeyModifier(), 0, length);
  15:             length = buf.Length;
  16:         }
  17:         else if (((this._page != null) && this._page.EnableViewStateMac) || (this._macKeyBytes != null))
  18:         {
  19:             buf = MachineKeySection.GetEncodedData(buf, this.GetMacKeyModifier(), 0, ref length);
  20:         }
  21:         str = Convert.ToBase64String(buf, 0, length);
  22:     }
  23:     finally
  24:     {
  25:         ReleaseMemoryStream(memoryStream);
  26:     }
  27:     return str;
  28: }

Both EncryptOrDecryptData() and GetEncodedDate() use GetMacKeyModifier() to form the crypto modifier.

   1: // System.Web.UI.ObjectStateFormatter.GetMacKeyModifier()
   2: private byte[] GetMacKeyModifier()
   3: {
   4:     if (this._macKeyBytes == null)
   5:     {
   6:         if (this._page == null)
   7:         {
   8:             return null;
   9:         }
  10:         
  11:         //Rex: the num variable used page.TemplateSourceDirectory to get hashcode.
  12:         int num = StringComparer.InvariantCultureIgnoreCase.GetHashCode(this._page.TemplateSourceDirectory) + StringComparer.InvariantCultureIgnoreCase.GetHashCode(this._page.GetType().Name);
  13:         string viewStateUserKey = this._page.ViewStateUserKey;
  14:         if (viewStateUserKey != null)
  15:         {
  16:             int byteCount = Encoding.Unicode.GetByteCount(viewStateUserKey);
  17:             this._macKeyBytes = new byte[byteCount + 4];
  18:             Encoding.Unicode.GetBytes(viewStateUserKey, 0, viewStateUserKey.Length, this._macKeyBytes, 4);
  19:         }
  20:         else
  21:         {
  22:             this._macKeyBytes = new byte[4];
  23:         }
  24:  
  25:         // Rex: use num variable to form the modifier...
  26:         this._macKeyBytes[0] = (byte) num;
  27:         this._macKeyBytes[1] = (byte) (num >> 8);
  28:         this._macKeyBytes[2] = (byte) (num >> 0x10);
  29:         this._macKeyBytes[3] = (byte) (num >> 0x18);
  30:     }
  31:     return this._macKeyBytes;
  32: }

_Page.TemplateSourceDirectory() return page's virtual directory path.

   1: // System.Web.UI.Control.TemplateSourceDirectory property
   2: public virtual string TemplateSourceDirectory
   3: {
   4:     get
   5:     {
   6:         if (this.TemplateControlVirtualDirectory == null)
   7:         {
   8:             return string.Empty;
   9:         }
  10:         return this.TemplateControlVirtualDirectory.VirtualPathStringNoTrailingSlash;
  11:     }
  12: }

finally, EncryptOrDecryptData() form the string of "__EVENTVALIDATION", also append the modifier in the end of the string. if it's on decryption mode, it verifies the modifier to see if postback-ed modifier matched currently calculated one (which is related to page url path), if page url changed, the modifier will also change, and then match operation will fail and throw exception.

   1: // System.Web.Configuration.MachineKeySection.EncryptOrDecryptData() code
   2: internal static byte[] EncryptOrDecryptData(bool fEncrypt, byte[] buf, byte[] modifier, int start, int length, bool useValidationSymAlgo)
   3: {
   4:     EnsureConfig();
   5:     MemoryStream stream = new MemoryStream();
   6:     ICryptoTransform cryptoTransform = GetCryptoTransform(fEncrypt, useValidationSymAlgo);
   7:     CryptoStream stream2 = new CryptoStream(stream, cryptoTransform, CryptoStreamMode.Write);
   8:     stream2.Write(buf, start, length);
   9:     if (fEncrypt && (modifier != null))
  10:     {
  11:         // Rex: Append the modifier to the end of content
  12:         stream2.Write(modifier, 0, modifier.Length);
  13:     }
  14:     stream2.FlushFinalBlock();
  15:     byte[] src = stream.ToArray();
  16:     stream2.Close();
  17:     ReturnCryptoTransform(fEncrypt, cryptoTransform, useValidationSymAlgo);
  18:     if ((fEncrypt || (modifier == null)) || (modifier.Length <= 0))
  19:     {
  20:         return src;
  21:     }
  22:     for (int i = 0; i < modifier.Length; i++)
  23:     {
  24:         // Rex: compare the modifier to see if it matches...
  25:         // Rex: modifier is related to page url path.
  26:         // Rex: if url changed, the match will fail the exception will be thrown...
  27:         if (src[(src.Length - modifier.Length) + i] != modifierIdea)
  28:         {
  29:             throw new HttpException(SR.GetString("Unable_to_validate_data"));
  30:         }
  31:     }
  32:     byte[] dst = new byte[src.Length - modifier.Length];
  33:     Buffer.BlockCopy(src, 0, dst, 0, dst.Length);
  34:     return dst;
  35: }

This concluded that "__EVENTVALIDATION" field is related to page url path.

--- #End ---

Posted: 2007/12/26 19:43 by rextangtw | with no comments
Filed under: ,
When you suddenly rotated your Vista Screen...

crosspost from http://blogs.msdn.com/rextang

Ok, so I just did it again... and don't know how to put it back... orz

In Vista, when you suddenly put your screen rotated by pressing some key-combination that you don't even know, here is the answer...

In Vista when you want to rotate your screen, use Ctrl + Alt + Cursor key combination...

I might just pressed Ctil + Alt + → that I didn't even notice so my screen just became portrait and didn't know how to put it back. later found the answer and by press Ctrl + Alt + ↑, it came back landscape...

Last time when I encountered this situation, I re-installed my video drivers... *sigh*

Technorati Tags: ,,,,

Posted: 2007/12/20 19:58 by rextangtw | with no comments
Filed under:
SQL Server 2008 CTP Download place...

crosspost from http://blogs.msdn.com/rextang

just for a quick memo of the download url found in Microsoft website, since in the time now there was no ISO image but only Virtual Machine VHD image that's available on MSDN Subscription download...

SQL Server 2008 CTP download page (right now English only)

FYI.

Technorati Tags: ,,,,

Windows 2008 Server built-in PowerShell and Vista Theme...

crosspost from http://blogs.msdn.com/rextang

Too busy to play new stuffs for a while. In Japan people work like crazy...

Just got the latest Windows 2008 Server RC1 installed inside VMWare Workstation. the install speed was fast and there was only a few input parameters needed in the front of installation, pretty smooth.

After installed the base components, I was wondering where the built-in PowerShell is but didn't found it at first. Later knew that it's a optional feature and had to install it via "Server Manager" -> Features ...

Also if you want to have Vita-like UI, remember also to add Desktop Experience feature (refer to this post). by doing that when you are changing windows theme, there will be Vista theme on it. but you won't see this option if you are setting it by terminal service to your windows 2008 server. can only see the theme on console.

IIS7 was also a non-default feature and needed to be installed separately (via the same "Features" place) .

Upon the Windows 2008 Server base, I installed RTM Visual Studio 2008 Team Suite. and now my new playing sandbox is done. although still got some problems on the new Windows Firewall with Advanced Security settings. Seems Firewall settings on Vista and new Windows 2008 are not very intuitive...

Download url of TFS explorer 2008...

crosspost from http://blogs.msdn.com/rextang

ScottGu wrote a simple general FAQ of newly released Visual Studio 2008 and TFS 2008. the good news is that VS2005 can access TFS 2008 and vise versa VS2008 can also access TFS2005.

what I need from this FAQ is the download url of VS2008 Team Explorer!

lazy to extract from TFS Server image...