I have been working recently with Page.LoadTemplate and ITemplate.InstantiateIn to add content from user controls to pages or other controls. This thing solves the problem of having to declare abstract classes in App_Code, but poses another problem linked to the lack of object references to the user controls you instantiate. What that means, among other things, is that you lose the ability to use events in your code.

But there is a way to bubble events to the upper controls and catch them. The first thing you should look at is the OnBubbleEvent protected method of the Control object. It catches all the events raised by its controls. Override it and you can catch events and treat them. Now, this method returns a bool value. It tells the RaiseBubbleEvent method (I'll talk about it shortly) if the event was handled or not. If it was, then the event doesn't rise above that control.

Now, about the RaiseBubbleEvent method, also a protected method of the Control object. What it does is go up the object hierarchy and execute on each object the OnBubbleEvent. It also stops if the method returns true. It is so simple and perfect that it is not overridden in any of the ASP.NET 2.0 WebControls.

But there is a catch. Some objects, like DataLists, DataGrids, Gridviews, Repeaters, etc, choose to handle the events in their items no matter what. That's why if you click a button inside a DataList, the event won't bubble to the OnBubbleEvent method from the UserControl or Page the DataList is in. Instead, the event reaches the OnItemCommand event.

So, if you want to use this general bubbling method with WebControls that override OnBubbleEvent, you have two options.
One is use inherited objects that remove this issue altogether (like inheriting from a DataList, overriding OnBubbleEvent, executing base.OnBubbleEvent, then always return false), which might make things cumbersome since you would have to define a control library.
The second option is to always handle the OnItemCommand and other similar events with something like RaiseBubbleEvent(sender, args); . This very line will re bubble the event upwards.

Benefits: the benefits of using this general event bubbling technique is that you don't have to always specifically write code in the OnItemCommand or having to handle OnClick events and so on and so on. Just catch all events, check if their arguments are CommandEventArgs, then handle them depending on source, command name and command argument.

First of all there is no reason not to apply this method to any other templatable control like GridViews or DataGrids. The basic mechanism is the same.

The problem here is how to display different templates for different items (not just for different item types) like when databinding to a general collection of different objects.

Basically all you have to do is use the OnItemCreated event to first load a template (using Page.LoadTemplate) from any user control and then applying it to the DataListItem (using ITemplate.InstantiateIn). But there are a few catches. First of all, the original templates (the ones in the as?x file) are applied before the OnItemCreated event. So if some templates are defined, like ItemTemplate for example, you need to clear the controls in the item before you instantiate your template. Second of all, you cannot declare the OnItemCreated event in the Page_Load method, since it is executed after the OnItemCreated event. But you can declare it in the as?x file.

So let's combine all this into code. First the aspx:
<asp:DataList id="dlMain" runat="server" OnItemCreated="dlMain_ItemCreated" >
</asp:DataList>

nothing fancy. Then the cs code:
protected void dlMain_ItemDataBound(object sender, DataListItemEventArgs e)
{
ITemplate template1 = e.Item.ItemIndex % 2 == 0
? Page.LoadTemplate("~/ucTest1.ascx")
: Page.LoadTemplate("~/ucTest2.ascx");
e.Item.Controls.Clear();
template1.InstantiateIn(e.Item);
}


That's it! ucTest1 and ucTest2 are two arbitrary user controls I am loading alternatively. For this particular case an AlternatingItemTemplate could have been used, but you get the point.

I have this Web User Control that has a simple function of displaying a customised grid and fill it with data. Since I had to email the rendered HTML I've added a static method to the Web User Control that would render itself based on some parameters. However, in Net 2.0 one cannot dynamically use the types declared in the codebehind of a user control or page inside another control or page, only types declared in App_Code. In pages this gets solved as in the link above, but what do you do when you want to use the type inside a class in App_Code or, like I needed to, in a web service (where register directives are not allowed)?

In my case, there were two solutions. One is to create a page that loads the user control and nothing else, then read its html. That solves the problems of using the code, but adds security issues. I have to either add a security mechanism to the page or allow anyone to render the UserControl. The second solution, the one that I ended up implementing, is to use reflection.

Let's recap. I have the web user control, let's call it Wuc, and I have the static method Wuc.GetHtml(int i) that I must access from a Web Service. If I write
string s=Wuc.GetHtml(i); it doesn't get to compile, returning the error "The name 'Wuc' does not exist in the current context".

So I do something like this:
UserControl uc = new UserControl();
uc = (UserControl) uc.LoadControl("~/Wuc.ascx");

and I get the object I need to get the type of. Then I should get a reference to the method I want so I try:

MethodInfo mi = uc.GetType()
.GetMethod("GetHtml",BindingFlags.Static);


which should work, but it doesn't!

Why not? Because the type of the object is not Wuc is wuc_ascx and it's the dynamically generated ASP.NET type. I get all the methods of Wuc, but not the static ones! So, the (really ugly) solution is to make the method not static and use this code:

MethodInfo mi = uc.GetType()
.GetMethod("GetHtml");
string s = (string)mi.Invoke(uc, new object[] { i });


which finally works.

Update
Scott Gu was nice enough to respond to my request on how to do this. He has this blog entry that explains how to render a control in NET 2.0 within an ASP.NET Ajax environment, but what really connects with my blog entry is this archive and the ViewManager object. Scott uses here the Page.LoadControl method (here is why) to load the control and Server.Execute instead of RenderControl.

Update!! Read the Sift3 post. It is an even better algorithm.


A while ago I wrote a little algorithm that tried to cope with the large amount of time that the Levenshtein edit-distance algorithm took to compare two strings. It was a really funny algorithm, but it was fast enough to show me the similarity between strings that, after all, should have been either very similar or different.

Meanwhile I started thinking if I could improve on it. I was sure I could, because it wasn't very scientific, it was empirical. And finally I did it. This is the Sift2 algorithm, along with an SQL server function that can make one million string comparisons in 2.5 minutes. Compared with Levenshtein, Sift2 performs 10 to 25 times faster and it is four times faster than Sift.

The concept:
  • Starting from the beginning of both words, compare the letters on the same position.
  • If the same, move forward, else search the letter from the first word in the next maxOffset letters in the second word and viceversa.
  • Offset the words according to the closest found letter, add 1 to distance
  • Repeat until one of the words ends
  • Add to the calculated distance half of the length of string remained unparsed from the other word
That's it! Here is the code:


C# Code (double click to show/hide)




T-SQL code (double click to show/hide)



You can find a nice OOP Javascript implementation at IT BASE.

Performance:
The algorithm seems to be working fine for letter insertions, typos, letter inversions and such. It gives slightly different values than Levenshtein when big words are inverted. When a lot of letters are inverted, the difference from Levenshtein increases. Example: abcdefghijkl vs. badcfehgjilk (every two letters inverted) results in 0.42 similarity in Levenshtein and 0.08 in Sift2. But let's face it, the two words are really different.

Update:
I've optimised the algorithm a little and also changed the formula so that it matches the Levenshtein distance as close as possible. The basic idea remains the same, but now the average error from Levenshtein (calculated or real company name and address data) is only 3%.
Some people saw the goto line and immediately laughed. Well, I tried replacing it with a break and a subtraction and even removed the subtraction altogether (thus maiming the algorithm) and the goto implementation was still the fastest. So I will continue to use goto, as it is more efficient.

Request:
I have seen a lot of people actually searched on Google and got here. I would really really really like some comments, links to implementations or whatever... It's my baby after all. Thanks!

Check out this little link: You receive an "interface not registered" error message when you try to build a Setup project in Visual Studio .NET
Why this is happening in the first place, I do not know, but the fix worked wonderfully. I was trying to build a Net 1.1 setup vdproj with Visual Studio 2003 and I got the error: "Could not find the file '[file that was obviously there]' 'Interface not registered' ".

Sometimes, when you use ASP.Net 2.0 with MasterPages, UserControls and dynamic loading like LoadControl, you get a silly error: Unable to cast object of type 'X' to type 'X' where X=X. Of course, it is a versioning problem. Some of these errors appear in the VS2005 designer, when the designer uses an older version of a library, but also when trying to open the web page in a browser.

Microsoft has released a fix for this: http://support.microsoft.com/kb/915782 , but, to quote the same source: "This hotfix may receive additional testing. Therefore, if you are not severely affected by this problem, we recommend that you wait for the next Microsoft .NET Framework 2.0 service pack that contains this hotfix.". So you risk screwing things up.

The issue seems to be mostly a developer problem. That means that during programming, you get this error when you keep changing stuff in the project. A client might get this error if an update of the site created this problem. The iisreset utility won't work. Recompiling locally and reupdating the site usually solves the issue.

and has 0 comments
Long story short: the BackgroundWorker object. Available in .NET 2.0
This is a Microsoft tutorial on using BackgroundWorker:
How to: Run an Operation in the Background
This is an older and more Windows Forms basic tutorial on multithreading:
Safe, Simple Multithreading in Windows Forms, Part 1
Safe, Simple Multithreading in Windows Forms, Part 2

Details:
BackgroundWorker has the DoWork, ProgressChanged, RunWorkerCompleted, and Disposed events. You need to assign at least one method for DoWork and one for RunWorkerCompleted, then run
bw.RunWorkerAsync(obj);
The DoWork method should do something like
e.Result=BackgroundOperation(obj);
while the RunWorkerCompleted method should do anything related to the GUI. There is also a CancelAsync() method, to try to stop a background operation.

Also, here is an article about a possible bug in BackgroundWorker, but I haven't replicated it on my computer.

There are 726 articles on Google when you search "gridview thead". Most of them, and certainly all the first ones, talk about not being able to render thead, tbody and tfoot elements for NET 2.0 table based controls. But it's not so!

Each table row has a property called TableSection. If you set it to TableRowSection.TableHeader, TableBody or TableFooter, the specific tags will be created. Let me show a quick example of creating a THEAD element in a gridview:
gridView.HeaderRow.TableSection=TableRowSection.TableHeader;

And that's it. This kind of behaviour works for the Table WebControl and everything that derives from it or uses it to render itself.
However, the rendering of these elements inside the Table control is done simply with writer.RenderBeginTag(HtmlTextWriterTag.Thead), which gives no one the ability to change from .NET code the attributes of those sections. You can't have it all! You can use CSS, though. ex:
.tableClass thead {
position:relative;
}

Amirthalingam Prasanna's article about the transactional model in NET 2.0.

As far as I understand, the old declarative ADO.NET Begin/RollBack/CommitTransaction model has become obsolete and a new TransactionScope model is used in NET 2.0. You have to add the System.Transactions.dll file to your references.

Basically, the C# code is like this:

using (TransactionScope scope=new TransactionScope
(scopeOption,transactionOptions,interopOption)) {
// do database ops

// if everything is alright
scope.Complete();
}


scopeOption is an enum of type TransactionScopeOption, with the options Required (requires a transaction and uses if there is already on open), RequiresNew (always opens a new transaction), Suppress (don't use a transaction, even if one is open)

transactionOptions is of type TransactionOptions which has two interesting properties: IsolationLevel and Timeout.

interopOption is an enum of type EnterpriseServicesInteropOption and specifies how distributed transactions interact with COM+ transactions.

But what about the old NET1.1 framework? Doesn't it have something like that? Here comes Alexander Shirshov with help:
TransactionScope in .NET 1.1

and has 0 comments
Well, basically, you can't do it.
I am looking at the internal ParseSortString(string sortString) in the DataTable object of NET 1.1, where the first thing the method does is to split the string by commas, then check for square brackets. This insures that there is no way to sort datatables by columns with commas in their names. The funny thing is that the filtering expression is treated like royalty by an ExpressionParser object, and allows column names with commas inside.
Now let's check the code for NET 2.0. It's identical.

The solution is a little annoying code like this:
private DataRow[] SelectSafe(DataTable dt, string filter, string sort)
{
var columns = new string[dt.Columns.Count];
for (var c=0; c<dt.Columns.Count; c++)
{
columns[c] = dt.Columns[c].ColumnName;
if (dt.Columns[c].ColumnName.IndexOf(',')>-1)
{
dt.Columns[c].ColumnName = dt.Columns[c].ColumnName.Replace(',', ';');
// assume that the column name was bracketed correctly in the select
sort = sort.Replace(
"[" + columns[c] + "]",
"[" + dt.Columns[c].ColumnName + "]");
}
}
var dr = dt.Select(filter, sort);
for (int c=0; c<dt.Columns.Count; c++) {
dt.Columns[c].ColumnName = columns[c];
}
return dr;
}


I am sure there is more elegant code, but this seems to be the only solution so far except manually sorting a DataTable.

You may experience unexpected results when you open a Web page that is in an ASP.NET 2.0-based application in Mozilla Firefox and the DefaultButton property is assigned to a LinkButton control or an ImageButton control

Just a reminder of a bug I am likely to encounter. The obvious solution is to use ControlAdapters or inheritance to create LinkButtons and ImageButtons that are rendered as buttons.

and has 0 comments
I've accidentally stumbled upon FxCop, a Microsoft free tool that analyses the generated NET code (.exe or .dll) for bad design practices.
While many of the errors and warnings I got were related to casing, a lot of them were not and they had come with links, extended information and solutions. The rules that FxCop has help you to make members static if none of the instantiated object's properties or members are used in it, use case insensitive String.Compare instead of comparing two ToLower strings, or StringBuilder in loops, use NET 2.0 constructs instead of 1.1 ones, etc.
I find it at least interesting and I intend to use it in my future software projects.

ASP.NET 2.0 has this nice feature called Virtual Path Providers. What it
actually does is enable you to get your site files from anywhere using an
override of the VirtualPathProvider class.

Virtualizing Access to Content: Serving Your Web Site from a ZIP File
This is a very nice article where a Microsoft guy shows how to run a
complete ASP.NET site from a ZIP arhive. Just two lines of code in
global.asax , a standard web config file and a ZIP arhive.

This opens up a lot of possibilities, like reading the ASPX or CS files from
a class that creates them dynamically, or reading the files from multiple
sources at once. Yummy!

and has 0 comments
I vaguely remember reading of nullable types in the C# 2.0 "what's new" documentation, but somehow it slipped by me. Now I've stumbled over this useful new feature and I can explain it for a bit.
Here is the Microsoft explanation.

Basically you can declare any value type as nullable by using the syntax <type>?.
Example: int? x=null;
There is even a nice operator ?? that acts like the SQL isnull function.
Example: int y=x ?? 0;
The two above examples are the short for the following:
System.Nullable x=null;
int y=x==null?0:x.Value; int y=x.HasValue?x.Value:0; OR int y=x.GetValueOrDefault(0)

    The Nullable type has some nice methods:
  • GetValueOrDefault([value]) - gets the default value or the specified value when the nullable type is null

  • HasValue() - something like is not null



There is no IsNull method to the Nullable type. Also, x=null makes x==null true, as opposed to, let's say, the SqlInt32 type.

I was stunned today to see that a site that I was working on was not starting because of this idiotic error:
ASP.NET 2.0 Parser Error Message: Access to the path '[something.cs]' is denied.
And further down:
No relevant source lines

The only thing I remembered doing was close the project in Visual Studio and work on another. I tried starting the site with the URL, without loading it into Visual Studio and the error occured. If you search on the net this error, you will see that there are a lot of articles that talk about the ind*exing ser*vice, but I stopped it a long time ago. So what was going on?

  • The file was accessible

  • The file was not opened by another application

  • I could freely delete/remove/modify the file



In desperation I compared the Security settings for this file with other files in the directory. To my surprise, there was a major difference. The files that were accessible had a lot of users with access rights to them, the file that gave the error had around three.

I have no idea what caused this. I just copied the same rights from the other files to the problematic one and it worked. I am using Visual Studio 2005, Resharper and SourceSafe. Do you also hear the Twilight Zone soundtrack?