Tuesday, April 17, 2007

ASP.NET Ajax - ‘AJAXControlToolkit is undefined’ - cachePolicy.SetLastModified((DateTime)GetAssemblyInfo(assembly).Second)

Problem declares itself as ‘AJAXControlToolkit is undefined’ on the client side (with few other client side exceptions before that). Server side exception info though provide enough insight into the problem...

That is another tricky one you can found in the ScriptResourceHandler.cs in the current ASP.NET Ajax.
Setting of the LastModified to anything that is newer than now from the server view is illegal (you will get ArgumentOutOfRangeException).
Though, how the GetAssemblyInfo(assembly).Second works?



private static DateTime GetLastWriteTime(Assembly assembly) {
string codeBase = GetCodeBaseWithAssert(assembly);
Uri codeBaseUri = new Uri(codeBase);
if (!codeBaseUri.IsFile) return DateTime.MinValue;
string localPath = codeBaseUri.LocalPath;

FileIOPermission p = new FileIOPermission(FileIOPermissionAccess.Read, localPath);
p.Assert();
return File.GetLastWriteTime(localPath);
}




The above takes the assembly the script located into and looks for it LastWriteTime.
Beware if you have that assembly copied from somewhere where this date may go ahead of the server time! That happens to us all the time when copying from Europe to USA :)!

P.S. Exception text on the server is like:

Event Type: Warning
Event Source: ASP.NET 2.0.50727.0
Event Category: Web Event
...
User: N/A
Computer: ... Description: Event code: ...
Event message: An unhandled exception has occurred.
....
Event sequence: 9 Event occurrence: 1 Event detail code: 0

Application information:
....

Process information: Process ID: ... Process name: ... Account name: ...

Exception information:
Exception type: ArgumentOutOfRangeException
Exception message: Specified argument was out of the range of valid values.
Parameter name: utcDate

Request information: Request URL: .../ScriptResource.axd?....
....

Stack trace: at System.Web.HttpCachePolicy.UtcSetLastModified(DateTime utcDate)
at System.Web.HttpCachePolicy.SetLastModified(DateTime date)
at System.Web.Handlers.ScriptResourceHandler.PrepareResponseCache(HttpResponse response, Assembly assembly)
at System.Web.Handlers.ScriptResourceHandler.ProcessRequest(HttpContext context)
at System.Web.Handlers.ScriptResourceHandler.System.Web.IHttpHandler.ProcessRequest(HttpContext context)
at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)

What would be the solution? - Touch the file your script resource is inside. There are few programs to do it, or you can just use simple .net console application for that:

class Program
    {
        static void Main(string[] args)
        {
            try
            {
                if (args.Length < 1)
                {
                    Console.WriteLine(String.Format(CultureInfo.InvariantCulture,
                        "Usage: SetFileModifiedDate \"FilePath\""));
                    return;

                }
                string filePath = args[0];

                if (!File.Exists(filePath))
                {
                    Console.WriteLine("File: \"" + filePath + "\" doesn't exist!");
                    return;

                }
                FileAttributes attr = File.GetAttributes(filePath);

                if ((attr & FileAttributes.ReadOnly) > 0)
                {
                    Console.WriteLine("File: \"" + filePath + "\" is readonly!");
                    return;
                }
                FileInfo fi = new FileInfo(filePath);
                fi.LastWriteTime = DateTime.Now.AddDays(-1);

                Console.WriteLine("Modified date is now set to: " + fi.LastWriteTime.ToString("ddMMMyyTHH:mm:ss fff"));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }
    }

The only principal lines you can shorten your solution to:

FileInfo fi = new FileInfo(filePath);
fi.LastWriteTime = DateTime.Now.AddDays(-1);

That should be only few lines of powershell script as well.


 

8 comments:

rottytooth said...

Thank you! I ran into this problem today and spent quite a long time trying to figure it out. In the end, I set the time back on the development machine, rebuilt the code and copied it back to the server.

Prashanth said...

Thanks! This post helped me a lot.

Anonymous said...

Thank you so much , you saved my life !

Darcy said...

I tried your solution to create the console app and updated the ajaxcontroltoolkit.dll's last modified date to system's date but I still get this error. Do I need to update any other dll's? please, help!

Stanislav Dvoychenko said...

Hi Darcy,
same issue affects assemblies that contain your own ajax extenders or behaviours. Check the date on those as well.

noam said...

Thank you Thank you Thank you!

Anonymous said...

I thought I was going nuts because it would start to work if I waited awhile - the server was in a later timezone than my dev box -thanks so much!!

Eran Smith said...

Awesome blog man, the things you have mentioned above are really informative and are examples of your awesome writing skills and a good blog.
.net Obfuscator