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/

and has 0 comments
A Romanian blogger made a very information link laden post about the new features in .Net 4.0. Check it out: Learning resources for .NET 4.0 new features.

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.

Update: two more days of work and a huge text file of regular expressions and I know a lot more about the syntax of .Net Regex than even MSDN :)
The third (Apr11) release of the library has a huge load of bug fixes and new features and it is now... [Tadaaaaa]... a stable version. At least I think of it that way :) Go download it.!

I've been working for two days on an idea. What can I do to make those long regular expressions that I always leave in my code more readable and easy to understand without having to compile automatons in your head?

I have first researched on Google regular expression converters. Nothing was even close to what I wanted. Also, on the more scientific side, people were talking a lot about BNFs, as a superset of regular expression syntax. I looked at BNF. Yes, it describes anything in a human readable form, it is used in RFCs but I hate it even more than XML! So XML it is. Most of the inspiration for the code came from this link: Regular expressions and regular grammars

I give you, RegexConverter. It is a library+demo that transforms a Regex into an XML and then back again. The demo application demonstrates (duh!) this by having two panes, one in which to write regex and the other in which to write XML. Changing one, also changes the other. It warns you of errors in both Regex, RegexConverter and then checks if what it got can be safely converted into your changed string!

Please tell me what you think. I believe it can be a real help in understanding regular expressions, some specific ones or regular expression syntax in general, whether one is a pro or a complete noob.

I've worked hard to design the library source in a way that is understandable, I also added comments everywhere. I tried to implement all the specifications of .NET regular expressions from the MSDN site so if you have a regex that is valid but can't be turned into XML or the conversion is not perfect, let me know.

The link is: RegexConverter on Github.

I will update this post with more science and links to my places of inspiration for this, so stay tuned.

Update: Ok, so I haven't updated this post much. Shame on me. I was reminded of this project when I got an email from the FamousWhy site which said RegexConverter "has been granted the Famous Software Award". I know it's probably an automatically generated message and went to many or all of the Codeplex people, but still: automated attention is still attention :)

and has 0 comments
Just a small mention of a thing I've learned today: what is the FullName of a Type of a class that is nested into another?

Usually, you would use it inside Visual Studio as ParentClass.ChildClass, but if you ever want to use the full name of the ChildClass Type (as when declaring it in web.config) you have to separate them with the + (plus) sign.

So let's assume you have this MyHandler class in the MyNamespace namespace which has a nested class Configuration in it. In the code you do a
var conf = new MyNamespace.MyHandler.Configuration();
while when using the handler type name to declare it in web.config you do it like this:
type="MyNamespace.MyHandler+Configuration"
.

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!

I've gathered the strength to defeat my laziness and put another of my projects on Github. I am talking about the Sift3 algorithm, described here.

The URL for the project is https://github.com/Siderite/Sift3/ where you can download the library and sources in .Net 3.5 C#. A class that also implements Levenstein and Length string distance algorithms is provided.

Please let me know if you are interested in the project, have any suggestions or are even using the algorithm in your projects.

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.

and has 4 comments
Ok, you first must know that Microsoft added a specific namespace for working with ActiveDirectory in .NET 3.5. It is called System.DirectoryServices.AccountManagement. The principal objects in the Account Management API include computer, group and user objects and it provides a means for applications to extend the object model to include custom schema object types.

Now that this is out of the way, I want to take my simple Authenticate, ListUser and ReadUser methods (working fine with the old DirectoryEntry method) and translate them into this new way of doing things.

I did some code and I got this error message: "80075000". That is the actual error Message property! Even more remarkable, a google for 80075000 resulted in only 246 results!! none of them explaining what I did wrong. Apparently, I had sent a string in the format "LDAP://ComputerName" as the computer name. Maybe it helps someone.

But this didn't solve it. I changed it with just the computer name, with or without a "\\" prefix, and I got a more clear text, but just as vague UnauthorizedAccessException: "General access denied error".

I am still working on it, but damn, how can a programmer not think about the error message he passes to other programmers?!

Ok, made it work, here is the code for the user authentication in an Active Directory domain.
Classic DirectoryEntry:

bool authentic = false;
try
{
var entry = new DirectoryEntry("LDAP://ComputerName",
"Domain\\username", "password");
object nativeObject = entry.NativeObject;
authentic = true;
}
catch (DirectoryServicesCOMException ex){}
return authentic;
As you can see, not the most elegant approach.

The .NET 3.5 way:

using (var context = new PrincipalContext(ContextType.Domain,"ComputerName"))
{
return context.ValidateCredentials("username","password");
}
Much better, isn't it? Pay attention that in the first case you need the domain in the username and in the second you need it not to be part of the username!

There is a third way (System.DirectoryServices.Protocols.LdapConnection), but seems too complicated to address right now.

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.

This is a message I got from the UpdatePanel Shrinker in a site we built:
Shrinkage: from 70000 to 10 = 0.014%.


Almost a year ago I thought of a way of compressing the UpdatePanel asynchronous output based on the previously sent information and created the UpdatePanel Shrinker. I waited all this time to test it and also I've used it in some small projects.

From today, the project is on Github, with an MIT licence, that means do whatever you want with it, but I would appreciate some words from you.

As for the details: it uses a sort of fast and dirty home made diff algorithm to compare the previously sent output for an UpdatePanel with the current one. The problem is that the effect can only be seen from the second async postback on, but when used, it yields fantastic compression rates.

You can use it for sites that are accessed from Internet challenged locations, for sites that have complex Ajax interactions and for sites that you "Ajaxify". And before I get angry comments from purists, yes, I know it is more efficient to use Ajax in a smart way to solve each problem in the best possible way, but if you just want the quick and dirty solution, like a MasterPage with a ScriptManager, an UpdatePanel and the page content in it, the Shrinker is the thing for you.

Take care to look in the Debug Output window. The shrinker will output the compression rate and any warnings it might have.

I have this cool thing I made that needs a HttpHandler to process some commands. Therefore, in the code, I am trying to change the web.config whenever possible. I do it in the usual way:
WebConfigurationManager.OpenWebConfiguration("~");
... .Save();
. That should work fine, unless you don't have writing rights on the web.config file. But you don't need only that! I gave rights to the web.config file, but I got this silly error: "changing web.config An error occurred loading a configuration file: Access to the path 'bla...bla...bla...bla.tmp' is denied.".

In other words, in order to write to the web.config you also need rights to add files to the web folder in order to create temporary files. Hmm, I thought the temporary files folder was used for that... :-|