PDB files are sometimes added to Source Safe when doing asp.net 2.0 projects

This is a very annoying VS2005 bug: PDB files residing in bin folder are sometimes added to source safe when you are doing an asp.net 2.0 project. This causes problems with source safe operations (i.e. Get Latest Version) and compile process as those files are marked read-only when they are under source control. The problem is described in details in this thread and this blog post. There is also a known KB article 915110.

One of the solutions is to download this hotfix which is rather tedious as you have to contact PSS to get it. Fortunately there is another way. You get this hotfix by downloading (public free download) "Microsoft Visual Studio 2005 - Update to Support Web Application Projects" which is some sort of addition to VS2005 (it doesn't forces you to how to do asp.net 2.0 projects in any way). I just installed it and it seems OK so far.

Using page fragment caching and AJAX thing

I am building a project powered by Ajax (telerik implementation, excellent stuff, highly recommended) these days. Soon I got an interesting challenge. How to enable UserControl (or page fragment) caching based on some parameters with Ajax (I won't discuss the importance of caching here nor its internals, just note that cache is your good friend). It is not strictly an Ajax issue but it stems from the way Ajax forces you to code - no postbacks, a callback has to be implemented as a server event. No postback means that one can't use VaryByParam caching attribute because you can't pass parameters in such way when doing Ajax. VaryByControl doesn't help either, as it is useful only in declarative way.

So, only attribute remaining is VaryByCustom. And this one I've used. Here is my control's ascx code:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="WebUserControl.ascx.cs" Inherits="WebUserControl" %> <%@ OutputCache Duration="15" Shared="true" VaryByParam="None" VaryByCustom="tubo" %> <asp:Label ID="ASPxLabel1" runat="server" Text="<%# DateTime.Now.ToString() %>" /> - <asp:Label ID="tubek" runat="server" Text="ASPxLabel" />

Nothing dramatic here. A couple of labels - one that shows the date and the other that will show parameter passed. There is <%@ OutputCache %> directive that instructs asp.net runtime to cache the control for 15s based on VaryByCustom value and the cache output is shared among different pages.

Here is code behind:

public partial class WebUserControl : System.Web.UI.UserControl { protected void Page_Load(object sender, EventArgs e) { DataBind(); } public string Tublo { set { tubek.Text = value; } } }

Again, nothing spectacular - there is a property Tublo that sets the second label's text to show the parameter passed. My goal is to cache this usercontrol based on value passed to Tublo. Here steps in VaryByCustom attribute. It lets you define a custom string that later is used to determine the caching key. If the key matches an output already present in cache then no instance is generated and output is reused. The code that emits proper value defined by VaryByCustom has to be put in global.asax or better, it has to override HttpApplication.GetVaryByCustomString method as shown here (excerpt from global.asax file):

public override string GetVaryByCustomString(HttpContext context, string custom) { if (custom == "tubo") { string tublo = (string)context.Items["tublo"]; System.Diagnostics.Debug.WriteLine(DateTime.Now + ": tublo is " + tublo); return tublo; } else return base.GetVaryByCustomString(context, custom); }

In the custom argument you get text defined in VaryByCustom to make a decision which value to return (the return value is actually caching key for particular control). This part puzzled me the most. How can I let know which Tublo value to return (remember, my goal is to cache based on Tublo property which in turn is the number of button pressed). After some investigation I've found out that I could use HttpContext's request cache aka HttpContext.Items property - values put here are cached for the request lifetime. Once request is served the cached values are lost. No better place to communicate with GetVaryByCustomString as it gets HttpContext as an argument. I just get the value out of context.Items and return it.

Here is how is the host test page built:

Very simple. It has two buttons and beneath you see the ouput of WebUserControl defined above.

And here is matching aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %> <%@ Register Src="WebUserControl.ascx" TagName="WebUserControl" TagPrefix="uc1" %> <%@ Register Assembly="RadAjax.Net2" Namespace="Telerik.WebControls" TagPrefix="radA" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <radA:RadAjaxPanel ID="RadAjaxPanel1" runat="server" > <asp:Button ID="buttonOne" runat="server" OnClick="Button1_Click" Text=" 1 " /> <asp:Button ID="buttonTwo" runat="server" OnClick="Button2_Click" Text=" 2 " /> &nbsp;<asp:Panel id="Panel1" runat="server" style="font: normal 12px Arial, Verdana, Sans-serif; color: #a6a896;"></asp:Panel> </radA:RadAjaxPanel> </div> </form> </body> </html>

Note that I didn't put WebUserControl on the page at design time (however, if you want to access WebUserControl you have to register it with <%@ Register directive %>). Yes, that's right - you need to create WebUserControl at runtime to use asp.net's built it caching mechanism. All controls are embedded in RadAjaxPanel that handles Ajax mechanism for you - no need to do anything else, simple as that. Each button has its own Click event defined that does set WebUserControl's Tublo property. And here is code behind:

public partial class _Default : System.Web.UI.Page { private void CreateDynamicControl(string s) { Context.Items.Add("tublo", s); Control c = LoadControl("~/WebUserControl.ascx"); Panel1.Controls.Add(c); WebUserControl wc = c as WebUserControl; if (wc == null) { PartialCachingControl pcc = c as PartialCachingControl; if (pcc != null) { wc = pcc.CachedControl as WebUserControl; if (wc == null) Debug.WriteLine("Control is cached"); } } if (wc != null) wc.Tublo = s; } protected void Button1_Click(object sender, EventArgs e) { CreateDynamicControl("1"); } protected void Button2_Click(object sender, EventArgs e) { CreateDynamicControl("2"); } }

CreateDynamicControl method does create a new instance of WebUserControl and if it is not cached yet it sets its Tublo property according to the clicked button. A portion of its code that does creation is borrowed from MSDN Magazine's article Keep Sites Running Smoothly By Avoiding These 10 Common ASP.NET Pitfalls. The important sentence in this method is first one - it stores Tublo argument to HttpContext.Items - this value is later used in GetVaryByCustomString as a return value and thus acts the role of caching key. The value is removed when request life ends.

That's it. Run the demo and click to both buttons. You'll note that each control's version will have a different time and time will change after at least 15s which means the output was rebuilt. Which in turn means that your IIS server will be able to server more requests per second not to mention that Ajax speeds up applications considerably.

Here is the source code for this article.

Extending LLBLGenPro's ResultsetFields to work like List

These days I had a need to use ResultsetFields for fetching dynamic list. As you know, ResultsetFields derives from EntityFields2 (I am working with LLBLGenPro 2.0 .net 2) which is basically an array. There is nothing wrong with that, it is just you have to set its size beforehand (ok, you can explicitly expand or contract it later on) and you have to use indexes. But why would one need to deal with indexes and sizes? Hence, here is my solution...read my article and get source code here.

Dejan started writing for Simple-Talk

Dejan Sarka, a fellow Slovene MVP (SqlServer), has started writing for Simple-Talk online technical journal for Sql Server. Knowing Dejan I am sure that articles are/will be worth reading if you deal with Sql Server in any way. You can find his first article here (there is a link at the end of blog post).

Developer Express releases new major version (6.2) of their .net stuff

It contains new ASP.NET controls; ASPxMenu, ASPxNavBar, ASPxTabControl, ASPxSiteMapcontrol and of course, full support for AJAX. Then there is a RibbonControl, XtraCharts has new graphs (3D ones among them), VisualStudio type docking, XtraGrid got an advanced filter, new WinForms controls (MarqueeProgressBar, TrackBarControl, LabelControl, XtraScrollableControl), XtraForm supports skinning of entire outlook plus other improvements and fixes. If you are a subscriber, go to client area and download them. If you aren't, go to [DevEx] site and look for trial download - worth checking out.

Taking LLBLGenPro and other CHM help files everywhere with PocketPC

If you have a PocketPC and you want to read CHM files (compiled HTML Help Format - previous MS' help format) on it then here is the solution. Pete's free CHMReader does the job very well and the result is actually very readable. I read every issue of MSDN Magazine (free CHM downloads) on PocketPC while I wait somewhere (don't you hate waiting at i.e. doctor's doing nothing?). Plus I have a copy of LLBLGenPro's help file on PocketPC, too. Very useful at the start since it is not just a help file, but also a guide to OR mappers in general.

Almost forgot - this is my first blog entry with Windows Live Writer.

Are new passports safe?

There is an ongoing frenzy to implement new passports with biometric data and RFID capability. I won't even start discussing why this sucks big time. Recently there was a news in Slovenia that we are going manufacturing such passports, too. Hura for us. And involved ministers assured that such passwords can't be problematic even when dealing with hackers. Really? How can they be that sure?