I made a few controls that loaded and included a resource js file. And it all worked well, until I wanted to load the js file from the Page object. The generated url was invalid. After hours of nervewrecking attempts I realised that the problem was I was using control.GetType() to get the type required as a parameter in GetWebResourceUrl. And the page, even if inheriting from a custom page object that resided in the assembly where the embedded resources were, was of the site assembly.

Solution: use GetWebResourceUrl(typeof(knownClassInTheAssembly),resourceName);

Warning: my object was inherited from Page and placed in the necessary assembly. And it still didn't work. It is good to remember that ASP.Net pages are not of the type they inherit from, but a class with the name of the page and that resides in the dynamically generated assembly of the site! So be careful where you use this.GetType()

So you have some embedded resources in your ASP.Net control library and you want to use them. But instead, nothing works. Scripts are not loaded and images are not displayed.

Look in the IIS log files and check for an error like this: "Exception information: Exception type: ArgumentOutOfRangeException Exception message: Specified argument was out of the range of valid values. Parameter name: utcDate".

If you see it, then your assembly where the resources are embedded has the build date into the future! This also applies to the code you just built and the date is correct and the date of the server where you want to copy it to is in the past. It also applies when the time is in the past, as when you are copying it on a server in a different timezone!

Update: There are other reasons why axd files are not loaded. One of them is that some other IHttpHandler (defined in web.config) is messing up with your settings.

Another is that the .axd extension is not defined in the virtual directory mappings (You get the dreaded Webform_PostBackOptions is undefined javascript error). Go to IIS manager to the properties of the virtual directory, click on the Configuration button, select the Mappings tab. You have to have the axd extension defined to open with aspnet_isapi.dll. Warning: there is a checkbox in the properties for the extension mapping called Check that file exists. Make sure it is unchecked, as the WebResource.axd and ScriptResource.axd are not actual files, so the mapping will fail if the check is set! On Windows 2003 there is also a listbox at the bottom of the Mappings tab. Edit it and look for yet another Check that file exists checkbox and, of course, uncheck it.

As you have probably noticed, a lot of my recent posts have been about WPF. Having to do a demo in this new (for me) technology I had a lot of thing to learn and a lot of brick walls to hit. It was exciting, but also difficult, with new concepts that felt awkward, mind twisting. I even burst one day shouting "I hate WPF".

However, I am now working, temporarily, with ASP.Net (no Silverlight) again. And guess what? At every step where I need to design something, I think in the WPF way and find the web way lacking. Riddle me this, riddle me that. :)

Of course, some might say that this is another proof of my whiny personality. I hate when people say that about me!

I only met this while working on a Menu control, but who knows, maybe it occurs in other situations as well. Bottom line I wanted to create a CSS friendly Menu without using an adapter. So I inherited from Menu, did some stuff, then Kaboom! "A PopEndTag was called without A corresponding PushEndTag" error.

I could not determine where it cam from. The only helpful article on the net seemed to be one from a guy that also wanted to inherit from Menu. Strangely enough his problem only appeared in Design mode, while mine was a runtime thing. And weirder still, the problem was "solved" by the same ridiculous fix, that of calling an extra
base.RenderBeginTag(writer);
in my RenderBeginTag method override. However, his explanation that is all came from IControlDesignerAccessor did not solve anything for me. Menu only overrides the SetDesignModeState and GetDesignModeState methods from IControlDesignerAccessor and when I also overrode them and removed any code inside, I still got the error.

So, after an hour of searching, I solved it by overriding the Render method with
protected override void Render(HtmlTextWriter writer)
{
if (this.Page != null)
{
this.Page.VerifyRenderingInServerForm(this);
}
if (this.Items.Count > 0)
{
this.RenderBeginTag(writer);
this.RenderContents(writer);
this.RenderEndTag(writer);
}
}
which is the exact implementation from the original Menu source code, but without the 'false' parameter in RenderContents and RenderEndTag.

Hope it helps someone.

Yay! The patch list for the Ajax Control Toolkit shows my two patches (for the dynamical adding of TabPanels to a TabContainer and the one for the zIndex of the PopupExtender) were 'applied in change set 54957'!

I don't know when the next official release of the ACT will be available, but you can always get the latest 'unstable' version (with the patches) here.

This is only a bookmark. If you want to know how to do this, read this link from Microsoft: Walkthrough: Using ASP.NET Routing in a Web Forms Application.

The scenario is this: You use a ScriptManager, a TextBox and a Button and your project is at least referencing the Ajax Control Tookit library. You expect when pressing Enter in the TextBox to get to the button Click event. Instead you get the Microsoft JScript runtime error: ‘this._postBackSettings.async’ is null or not an object javascript error.

I found the solution here: JScript Exception in AJAX Control Toolkit. Basically, put the textbox and the button in a Panel and set the DefaultButton property to the button id.

Today a new AjaxControlToolkit was released. I had hoped that at least they noticed the patch I made the effort of sending them, the one that fixed the dynamic TabPanel issue. But no. Three more controls and probably most of the same old bugs.

Here are more details: New release of the Ajax Control Toolkit

VirtualPathUtility.ToAbsolute("~/") = /Site/
HostingEnvironment.MapPath("~/") = c:\InetPub\wwwroot\Site\.
new Uri(HttpContext.Current.Request.Url,VirtualPathUtility.ToAbsolute("~/")).AbsoluteUri = http://server/Site/

I have seen a small video presentation about the new ASP.Net 3.5 SP1 Script Combining feature. Basically you take a bunch of scripts (like the ones from AjaxControlToolkit) and you bundle them together in a single cacheable file. This decreases the number of concurrent connections on your production site.

The problem was that you had to use some component to see what script files were being loaded and then manually add them to the ScriptManager CompositeScript Scripts collection. And this applies only to correctly registered scripts, not stuff that is embedded in the HTML or what not. Isn't it easier to just parse the generated HTML and then replace the script tags, I thought?

Well, I did a small Response filter/IHttpHandler in about two hours. It would take all consecutive external file references and combine them in a single cached and cacheable call. Then I tested it with Asynchronous postbacks. Epic Fail! The main problem was that the combined scripts would re-register themselves at postback and throw all kinds of errors therefore. But how did they know if they were registered or not before?!

I vaguely remembered an old post of mine about the notifyScriptLoaded function that must be called at the end of every external javascript registrations. Examining the system a little I realised that the flow was like this:
  1. register the script (either include it in the HTML in regular render or sending it to the UpdatePanel javascript engine to be registered as a new dynamically script element in the Head page section)
  2. if the registration is an async dynamic one, check in an array if the script is loaded and if it is, don't register it
  3. in the script call Sys.Application.notifyScriptLoaded() which would take the src of the script element and use it as a key in the above mentioned array to declare it has been loaded


Of course, that means combining all the scripts in a single file registers only that file and you get the original files registered again. Then you get errors like 'Type [something] has already been registered.' or (because there are more than one script file bundled together) 'The script [something] contains multiple calls to Sys.Application.notifyScriptLoaded(). Only one is allowed.'.

Well, I did manage to solve the problem by following these steps:
  1. forcefully remove Sys.Application.notifyScriptLoaded() from bundled scripts
  2. add Sys.Application.notifyScriptLoaded() at the end of all scripts
  3. surround the various scripts with a code that looks like
    sb.AppendFormat(@"if (!window.Sys||!Sys._ScriptLoader||!Sys._ScriptLoader.isScriptLoaded('{0}')) {{
    {1}
    if (window.Array&&Array.add&&window.Sys&&Sys._ScriptLoader) Array.add(Sys._ScriptLoader._getLoadedScripts(), '{2}');
    }}
    ", HttpUtility.HtmlEncode(src), content.Replace("Sys.Application.notifyScriptLoaded();", ";"),src);
.

With problem solved, the AutoScriptCombiner works, but it feels wrong. I wanted to post it on Github, you see, but in the end I've decided not to. However I did learn something about how the Asp.Net Ajax framework functions internally and I wanted to share it with you.

First off, I have to say something about forums: stop copying content from one another, jerks!. I have been trying to find a solution for this problem and I found a zillion forum pages with the same "problems" and the same "solutions" again and again and again!

Much better! Now, I have been trying for an hour to understand why setting customErrors="Off" in the web.config of my ASP.Net application would not work. I tried just about anything, including the bloody forums. customErrors Off did not work!.

In the end I found one little comment for a StackOverflow question: set the retail setting in the machine.config file to "false"!! So, go to %WINDOWS%\Microsoft.NET\Framework\v2.0.50727\CONFIG\machine.config and set retail to false!. Setting it to true means it will NEVER show you any useful debugging message.

A while ago I wrote a post detailing a fix for Very slow UpdatePanel refresh when containing big ListBoxes of DropDownLists. I have restructured the fix into a ControlAdapter and placed it on Github.

Enjoy!

This error can happen in several situations. One of them is when you are trying to access a web service, another is when trying to call a classic asp page. Most of the time, this happens in situations related to URL rewriting. It may happen in Windows XP or Windows 2000, on IIS 5.0 or IIS 5.1.

Well, first of all, in order to do URL rewriting you need to make ASP.Net process ALL URLs, not only .aspx pages. To do that in IIS5, you need to go to the ISAPI extensions and add a new one for '*' that maps to the ASP.Net dll (aspnet_isapi.dll). This process is detailed in this Microsoft page: HOW TO: Use ASP.NET to Protect File Types. What that means is that when you see a GIF image, it will pass through the ASP.Net engine, firing all the usual events.

However, after you do that, you see that web services start behaving strangely. Why is that? One explanation says that "405 mostly comes about when you try to POST against a URL that is not considered dynamic by IIS". It doesn't much makes sense to me.

I have searched a lot for an elegant solution. The only one that actually applied was using a piece of code in the BeginRequest event in Global.asax (or maybe in a HttpModule that one has to register in web.config). It came from this forum: HTTP verb POST not allowed. Here is the code:

//The BeginRequest event is fired for every hit to every page in the site
void Application_BeginRequest(Object Sender, EventArgs e)
{
var extensions = new[] {".asmx", ".svc"};
foreach (var ext in extensions)
{
var index = Context.Request.Path.IndexOf(ext, StringComparison.CurrentCultureIgnoreCase);
if (index <0) continue;

var path = Context.Request.Path.Substring(0, index + ext.Length);
var pathInfo = Context.Request.Path.Substring(index + ext.Length);
var query = Context.Request.Url.Query ?? "";
if (query.StartsWith("?")) query = query.Substring(1);
Context.RewritePath(path, pathInfo, query);
break;
}
}

I needed a dynamic menu control for my site. So, of course, I tried to use the ASP.Net Menu control (with its many failings when following CSS standards). It was a painful failure. It didn't work in either Internet Explorer 8 or FireFox 3! That was especially strange since I had used the control in a bunch of sites and it worked back then!

Long story short:
<DynamicMenuStyle CssClass=adjustedCssIndex />
where adjustedCssIndex is a CSS class that specifies the z-index property:
.adjustedCssIndex { z-index:100; }


Long story, it seems that the control assumes there is a default z-index value set by the browsers; Bertrand Le Roy from Microsoft says as much in his blog, and discloses a patch fix.

However, as you can see in that post's comments, there is also a very simple CSS fix to all of this, by specifying the z-index.

Recently I have been working on this Sharepoint project. I took it more out of curiosity as I didn't know anything about this piece of software. Now I know a lot more, like how hellish it is to code against it :) But it is also not a bad idea.

In case you don't know (as I didn't) Sharepoint is something like an ASP.Net site designed to work within a company, as an internal tool, allowing a lot of customizations and security from the web interface, with no code required. The desired end result is something looking like the IGoogle or Yahoo home pages, with web parts that can be configured, moved around, minimized, closed, made to interact one with another. Sharepoint Services is in itself a free software, but it only works on a Windows 2003 server or higher, so it sucks that way. Also, there is no real Sharepoint support for Visual Studio and most of the tutorials you find online are either too specific (blogs and such) or too vague (Microsoft style).

Also, there is a lot of confusion regarding the use of the interfaces in the Sharepoint dll, most of which have been obsoleted when the web part engine from .Net 2.0 was introduced.

Ok, short list of steps on how to start making a Sharepoint project in Visual Studio, assuming you code in Windows XP:
  1. Install Windows Server 2003 on another machine (virtual or not)
  2. Download and install Sharepoint Services 3.0 SP1 on it
  3. Get the Microsoft.Sharepoint.dll file and copy it on your XP machine somewhere
  4. Download and install the Sharepoint SmartTemplates for Visual Studio
  5. Update the WSPBuilder application and some batch files in the template files
  6. Start Visual Studio and create new project from installed templates
  7. Add a reference to the Microsoft.Sharepoint.dll library
  8. Code!
.

Now for the long list.
In order to install Sharepoint Services 3.0 SP1 you need to also install .Net 3.5 SP1. Actually it is a good idea to install this as well as the Visual Studio 2008 SP1 before you do anything (Sharepointy or not). Here is a link.

The Sharepoint SmartTemplates actually create a folder structure that is then used by the WSPBuilder utility to create the WSP file that installs a web part in Sharepoint. You can either import it in the site (upload) or use the setup that is provided with the templates. The problems I met when using it are linked primarily with the version of WSPBuilder that is included in the templates I've downloaded (version 0.2).
So first locate the installed template files: you can usually find them in My Documents/Visual Studio 2008/Templates/Project Templates/ as two zip files. First step is to download the latest WSPBuilder and replace it in the archives. The next step is to change the WSP/createwsp.bat file like this:
@ECHO OFF
DEL .\$safeprojectname$.wsp
ECHO Copying DLL ...
XCOPY /Y ..\BIN\$safeprojectname$.dll .\80\BIN\
ECHO Copying ASCX files ...
XCOPY /Y ..\*.ascx .\12\TEMPLATE\CONTROLTEMPLATES\$safeprojectname$\
ECHO Building WSP ...
..\WSPBuilder\WSPBuilder.exe -WSPName $safeprojectname$.wsp -BuildCAS false -SolutionID $guid2$ -DLLReferencePath "[the folder path where you copied Microsoft.Sharepoint.dll]" -TraceLevel Verbose
ECHO Copying WSP file ...
XCOPY /Y .\$safeprojectname$.wsp ..\SETUP\

The bold parts you must add to the file. The delete because otherwise you might be able to compile the project using the old WSP file if the WSPBuilder run fails. The others is in order to be able to compile the WSP using the sharepoint library and see any errors that might occur.
Alternatively, you can change the WSPBuilder/WSPBuilder.exe.config file with the DLLReferencePath and TraceLevel options.
Ok, now repack the folders into the archives and copy them back.

Now, after you build the project, you will have a Setup folder in the bin folder. That you must copy to the Windows 2003 computer and run. It will install the web part(s) in the project. In order to add more webparts to the project and make them compile in the setup project you need to alter the WSP\12\TEMPLATE\FEATURES\SmartPartTemplate\manifest.xml file and describe the files you add to the project.

After you run the setup project, you have to open the Sharepoint site and go to Site Settings -> Site collection features and activate the web part. Only then you can actually add it to a page.

Sounds complicated? Well, read more :)

Make sure that when you have finished with a web part you DO NOT DELETE THE SETUP PROJECT, but run it to remove the web part first! In order to remove an install web part from a Sharepoint site you must delve into the hell of command line utilities! Well, it's natural to me, but I am an old guy! ;)

Just supposing that you have done the undoable and you managed to delete a setup project with the part still installed, you must use the stsadm tool.
First find it on the Windows 2003 computer (with Find Files) then add the containing folder to the path. Then run cmd in the Start/Run menu and use the following commands:
stsadm -o enumsolutions
will enumerate the installed solutions. Remember the name of the solutions you want to remove.
stsadm -o retractsolution -name "[name of solution]" -immediate
will retract the web part project and allow you to delete it.
stsadm -o deletesolution -name "[name of solution]" -override
retracting doesn't always work, so the override option will force a delete.

Sometimes you manage to change the GUID of the project and you get an error like A solution with the same name "SomeName.wsp" or id "Some GUID" already exists in the solution store.. You delete it, but you still have this error. Try to install the solution with the setup project. Wait for the error, exit the setup project. Use stsadm -enumsolutions to see what the GUID of the project is, copy it, replace the SolutionId GUID in the setup.exe.config file with this one. The setup should then work.

This is about it. I've wasted a few hours to learn all of this. I know it's not terribly organized, but writing something is better than sharing nothing.