Notify Database changes to ASP.NET pages

In the old times there were two ways of getting notifications from the database into the ASP.NET pages.

  1. writing to a file (simply create or delete an empty file) in a specific location where a CacheDependency can listen to and callBack a method on change.
  2. implement an HttpHandler that gets the notification with a parameter of what is changed, and let the database send an http request to the IIS server on a trigger.
I am sure there could be worse methods but even these two have a lot of complications in a secured architecture with high performance requirements, like we have these days.

Fortunately, since SQL-Servet 2000, there is a new component implemented into SQL-server called Service Broker that act on changes in tables that are marked to be notified on change. Internally they write to a specific table mentioning about the change.
In order to configure a database for Service Broker you can call a statement like this:
Use Northwind
ALTER DATABASE Northwind SET ENABLE_BROKER
For more information about Service Broker see the MSDN.
Next, you need to set the ASP.NET to recieve the notification via dependencies. To do so , you need to add the command object to the dependency:
// Create the dependency.
SqlCacheDependency empDependency = new SqlCacheDependency(cmd);
// Add a cache item that will be invalidated if one of its records changes
// (or a new record is added in the same range).

Cache.Insert("Employees", ds, empDependency);
To start the notification on application service you need to add the following to the Global.ascx.cs in Application_Start
SqlDependency.Start(connectionString);
It is a good practice to stop the notifications on Application_End
SqlDependency.Stop(connectionString);
Once this is implemented, you can get the notifications through the OnChange event of the SqlDependency class.

Implementing custom FileCacheProvider

This is a summerized version of what you can find in the APress book Chapter 11.

If you want to cach some pages or all, you need to first tell the ASP.NET to do so. As the caching starts before rendering the page, you can not specifiy this in the page markup, rather it will be mentioned in the Global.asax.cs
        public override string GetOutputCacheProviderName(HttpContext context)
        {
            // Get the page.
            string pageAndQuery = System.IO.Path.GetFileName(context.Request.Path);
            if (pageAndQuery.StartsWith(“OutputCaching.aspx”))
                return “FileCache”;
            else
                return base.GetOutputCacheProviderName(context);
        }
This tells to ASP.NET to use FileCache mechanics for cachin OutputCaching.aspx page. The rest will just follow the default.
Next step is to specify where to find the implementation of FileCache. This is mentioned in the web.config as follows:
    <system.web>
      <caching>
      <outputCache defaultProvider=”FileCache”>
        <providers>
          <add name=”FileCache” type=”MyCompany.MyProject.Caching.FileCacheProvider” 
               cachePath=”~/Cache” />
        </providers>
      </outputCache>
    </caching>
  </system.web>
Notice that the cachePath is not a recognized attribute but we may introduce it to get the parameters. In this case it refers to an existing folder on the root of the website.
Next step is to implement the provider. This involves to implement a class that inherits from OutputCacheProvider and overrides the methods as follows:
    public class FileCacheProvider : OutputCacheProvider
    {
        // The location where cached files will be placed.
        public string CachePath
        { get; set; }
        public override void Initialize(string name, System.Collections.Specialized.NameValueCollection attributes)
        {
            base.Initialize(name, attributes);
            // Retrieve the web.config settings.
            CachePath = HttpContext.Current.Server.MapPath(attributes[“cachePath”]);
        }
        public override object Add(string key, object entry, System.DateTime utcExpiry)
        {
            // Transform the key to a unique filename.
            string path = ConvertKeyToPath(key);
            // Set it only if it is not already cached.
            if (!File.Exists(path))
            {
                Set(key, entry, utcExpiry);
            }
            return entry;
        }
        public override object Get(string key)
        {
            string path = ConvertKeyToPath(key);
            if (!File.Exists(path)) return null;
            CacheItem item = null;
            using (FileStream file = File.OpenRead(path))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                item = (CacheItem)formatter.Deserialize(file);
            }
            // Remove expired items.
            if (item.ExpiryDate <= DateTime.Now.ToUniversalTime())
            {
                Remove(key);
                return null;
            }
            return item.Item;
        }
        public override void Set(string key, object entry, System.DateTime utcExpiry)
        {
            CacheItem item = new CacheItem(entry, utcExpiry);
            string path = ConvertKeyToPath(key);
            // Overwrite it, even if it already exists.
            using (FileStream file = File.OpenWrite(path))
            {
                BinaryFormatter formatter = new BinaryFormatter();
                formatter.Serialize(file, item);
            }
        }
        public override void Remove(string key)
        {
            string path = ConvertKeyToPath(key);
            if (File.Exists(path)) File.Delete(path);
        }
        private string ConvertKeyToPath(string key)
        {
            // Flatten it to a single file name, with no path information.
            string file = key.Replace(‘/’, ‘-‘);
            // Add .txt extension so it’s not confused with a real ASP.NET file.
            file += “.txt”;
            return Path.Combine(CachePath, file);
        }
    }
The CachePath will be set by configurationManager. The private method ConvertKeyToPath helps to find a unique filename based on the url. This example uses binary formatter and a wrapper class that adds an expiration property to any object that needs to be cached. So, the following is the implementation of the wrapper class:
    [Serializable]
    public class CacheItem
    {
        public DateTime ExpiryDate;
        public object Item;
        public CacheItem(object item, DateTime expiryDate)
        {
            ExpiryDate = expiryDate;
            Item = item;
        }
    }
That’s all. When you run this you will notice that you will get an error if the Cache folder does not exist in the root.
To test the caching try to put the next code in the Default.aspx
    <%@ OutputCache Duration=”10″ VaryByParam=”None” %>

MVC Tips

You can use the standard ASP.NET features in your MVC views. In this case, you call the String.Format method to display the UnitPrice field in a suitable form for a monetary amount. You just pass in the Model.UnitPrice value as the argument to the method call.
<%= String.Format(“{0:F2}”, Model.UnitPrice) %>

String class can also be used as a formatter in thextbox:

Unit Price:
<%: Html.TextBoxFor(model => model.UnitPrice, new {Value = String.Format(“{0:F2}”, Model.UnitPrice)})%>

Localizing ASP.NET Tips

There are two kind of localizations:

  • Local resources are specific to a page.
  • Global resources are shared throughout the site

If your site contains many folders, you might have an App_LocalResources subfolder in each folder of your site.

<asp:Button ID="ButtonFind" runat="server" Text="Find" CssClass="submitButton" meta:resourcekey="ButtonFindResource1" />

<asp:Localize ID="LabelTitle" runat="server" Text="Customer Lookup" meta:resourcekey="LabelTitleResource1"></asp:Localize>

The Text property of the Button control is to aid the developer at design time.

ASP.NET will use the key to find and match on any property that might be set inside the resource file as meta:resourcekey.<PropertyName> or ButtonFindResoure1.Text:

<data name="ButtonFindResource1.Text" xml:space="preserve">

     <value>Find</value>

</data>

<data name="ButtonFindResource1.Tooltip" xml:space="preserve">

     <value>Click this to start the search action</value>

</data>

Accessing a Local resource in C# could be done as follows:

Textbox1.Text = GetLocalResourceObject(“Textbox1.Text”).ToString();

Accessing a shared global resource in C# could be done in one of the two followings:

Textbox1.Text = Resources.ResourceFileName.Textbox1Text;

Textbox1.Text = GetGlobalResourceObject(“ResourceFileName”, “Textbox1Text”) as string;

The methods GetGlobalResourceObject  and GetLocalResourceObject can come handy when the resources does not exist at compile time and might be provided as a separate dll at runtime.

Show an object instance as an xnl on your page

This sample code demonstrates how to show an instance of an object in XML format on a page. It encodes the xml serialized string and dumps it as a code into a placeholder.
    public void ShowXmlObject<T>( T instance)
    {
        var ms = new MemoryStream();
        System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(ms, Encoding.Unicode);
        var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
        serializer.Serialize(writer, instance);
        writer.Flush();
        ms.Position = 0;
        var reader = new StreamReader(ms);
        LogCode(HttpUtility.HtmlEncode(IndentXml(reader.ReadToEnd())));
    }
    public string IndentXml(string xml)
    {
        var p = xml.LastIndexOf(“?>”);
        if (p > 0)
            xml = xml.Substring(p + 2);
        var doc = new System.Xml.XmlDocument();
        doc.LoadXml(xml);
        var settings = new System.Xml.XmlWriterSettings();
        settings.Indent = true;
        settings.IndentChars = ”  “;
        settings.NewLineChars = “rn”;
        settings.NewLineHandling = System.Xml.NewLineHandling.None;
        var  sbOutput = new StringBuilder();
        var writer = System.Xml.XmlWriter.Create(sbOutput, settings);
        doc.Save(writer);
        writer.Close();
        return sbOutput.ToString();
    } 
    public void LogCode(string message)
    {
        placeResult.Controls.Add(new Literal() { Text = "<pre><code>" + message + "</code></pre>" });
    }

Show Items structure in Sitecore

The following example demonstrates how to get the information about a node on the back side of a node by giving the item.ID. You also could do it easier by having the full path instead of creating an ID.
It is important to do all this inside a SecurityDisabler. You might have some nodes that are not accessible to anonymous user, if the code is running for without proper security.
    protected void StartToAnalyse(object sender, EventArgs e)    {
        Sitecore.Data.Database master =
            Sitecore.Configuration.Factory.GetDatabase(“master”);
        using (new Sitecore.SecurityModel.SecurityDisabler())
        {
             ProcessItem(master.GetItem(new Sitecore.Data.ID(textboxRoot.Text)));
        }
    }
    private void ShowTechnicalDetails(Sitecore.Data.Items.Item item)
    {
        string pageName = item.DisplayName;
        
        var template = item.Template;
        //LogLine(” Template : ” + item.TemplateName);
        // LogLine(” Uri : ” + item.Uri.Path);
        // string rend = Sitecore.Context.Item.Fields[“Renderings”].Value;
        Sitecore.Data.Items.DeviceItem defDevice = Sitecore.Data.Items.DeviceItem.ResolveDevice(Sitecore.Configuration.Factory.GetDatabase(“master”));
        var layout = item.Visualization.GetLayout(defDevice);
        if (layout != null)
        {
            LogLine(” Layout : <u> [“ + layout.DisplayName + “]</u>” );
        //   //  LogLine(” File : ” + layout.FilePath);
        }
        var renderings = item.Visualization.GetRenderings(defDevice, false);
        //LogLine(“Renderings:<ul>”);
        foreach(var rend in renderings)
        {
            //LogLine(” Layout : ” + rend.RenderingItem.DisplayName);
            LogItem(pageName + “;” + rend.RenderingItem.InnerItem[“Path”]);
        }
    }
    private void ProcessItem(Sitecore.Data.Items.Item item)
    {
        if (item == null)
        {
            LogLine(“Item not found.”);
            return;
        }
        
        ShowTechnicalDetails(item);
        foreach (Sitecore.Data.Items.Item child in item.Children)
        {
            ProcessItem(child);
        }
    }
    

jQuery.Ajax versus Server-side event handler

This sample demonstrates two ways of getting address from the server: using server-side event handler versus calling jQuery.Ajax

The following is the markup that provides two fields with javascript call on the change event. It also provides a button that is wired to a server side methode:

     <div>

         <h3> Address Test</h3>

         tabbing from the textboxes will verify if calling the webservice is required.

         <table  width="100%"><tr><td><table><tr>

                             <td> Huisnummer *</td>

                             <td><div class="FieldContainer">

                                     <asp:TextBox  runat="server"  ID="textboxHousenumber"  ClientIDMode="Static"

                                         CssClass="TextField TextField02" onchange="VerifyAddress();"

                                         ValidationGroup="KlantAddress" />

                                 </div>

                             </td></tr><tr>

                             <td> Postcode *</td>

                             <td><div  class="FieldContainer">

                                     <asp:TextBox  runat="server"  ID="textboxPostcode"      ClientIDMode="Static"

                                                 CssClass="TextField TextField02"  

                                                 MaxLength="7"  onchange="VerifyAddress();"

                                                 ValidationGroup="KlantAddress" 

                                                 />

                                 </div>

                             </td></tr>

                     </table>

                   Server side call:<br  />

                     <asp:Button  ID="Button1"  runat="server"  OnClick="ShowAddress"  Text="Get Adres"  ToolTip="CustomerDataController"  />

                     <asp:Label  runat="server"  ID="lblAddress"  />

                   

 

Assume we have a we DBLLayer that provides an address or throws an exception.
The event handler would be something like this:

 

     /// <summary>Server side event handler</summary>

     public  void  ShowAddress(object  sender, EventArgs  e)

     {

         try

         {

             var  adres = DBLayer.GetAddress(textboxPostcode.Text, textboxHousenumber.Text);

             ShowAdres(adres);

         }

         catch  (Exception  ex)

         {

             LogError("Error :- "  + ex.Message);

         }

     }

 

And the Javascript will look like this:

 

     function  VerifyAddress() {

         // This method is calling the ShowAddress only if both parameters are filled in.  

         $("#<%=lblAddress.ClientID %>" ).text("" );

         var  postcode = $("#<%=textboxPostcode.ClientID %>" ).val();

         var  huisnummer = $("#<%=textboxHousenumber.ClientID %>" ).val();

         if  (postcode && huisnummer && parseInt(huisnummer) > 0) {

             $("#<%=lblAddress.ClientID %>" ).text("calling the server" );

             var  data = "{ postcode:’"  + postcode + <span’ , huisnummer: "  + huisnummer + " }" ;

             jQuery.ajax({

                 type: <span’ ,

                 contentType: <span’application/json;’ ,

                 data: data,

                 dataType: <span’ ,

                 url: <span’ ,

                 success: OnGetAddressComplete,

                 error: OnErrorReceived

             });

         }

     }

     function  OnErrorReceived(xhr, ajaxOptions, thrownError) {

         var  message = jQuery.parseJSON(xhr.responseText);

         $("#<%=lblAddress.ClientID %>" ).text(

             "ERROR ("  + xhr.status + ") – "  + message.Message);

     }

     function  OnGetAddressComplete(result) {

         // display the result

         var  adres = result.d;

         $("#<%=lblAddress.ClientID %>" ).text(

             adres.Straat + <span”  +

             adres.Huisnummer + <span’,’  +

             adres.Postcode + <span”  + adres.Plaats);

     }

And finally the webservice will be like:

 

     [System.Web.Services.WebMethod ()]

     public  static  Adres GetAddress(string  postcode, string  huisnummer)

     {

         if  (!IsPostcode(postcode))

             throw  new  Exception ("Invalid Postcode." );

         int  hNr = 0;

         if  (!Int32 .TryParse(huisnummer, out  hNr))

             throw  new  Exception ("Invalid house number." );

         var  result = DBLayer .GetAddress(postcode, huisnummer);

         if  (result == null )

             throw  new  Exception (" Unknown address." );

         return  result;

     }

    

     public static bool IsPostcode(string  zipcode)

     {

         var  ZipcodeRegex = @"^[1-9][0-9]{3}[a-zA-Z]{2}[\s]*$" ;

         Regex  r = new  Regex (ZipcodeRegex, RegexOptions .IgnoreCase);

         Match  m = r.Match(zipcode);

         return  m.Success;

     }

    

Convert XElements to Json

You need to capture the data type in a class that is serializable.
In this example I use Employee to do so. The first action will be to construct an IEnumerable of Employee:

 XElement empXml = GetEmployees();
var empJson = from emp in empXml.Descendants("Employee")
select new Employee
{
ID = emp.Element("ID").Value,
FirstName = emp.Element("FirstName").Value,
Department = emp.Element("Department").Value,
City = emp.Element("City").Value
};

The second step is to serialize the enumeration into the memory stream.

  var ser = new  DataContractJsonSerializer(typeof(IEnumerable));
var ms = new MemoryStream();
ser.WriteObject(ms, empJson);

And at last, we can take the generated stream as a string just before closing the stream.

string json = Encoding.Default.GetString(ms.ToArray());
ms.Close();

What is jQuery? Introduction

This is a very short description of jQuery coming from the book MCTS Self-Pased Training Kit (Exam 70-515):

jQuery is an open source library that simplifies the way JavaScript is written. It works across all modern browsers and is lightweight. You can use it for a variety of client-side programming tasks, such as selecting items inside your page, manipulating those items, changing styles, doing animations and effects, handling user events on the client side, and calling web services by using AJAX. There are also several plug-ins available for jQuery that provide rich controls that execute
inside a browser window.

Visual Studio 2010 and ASP.NET 4 now fully support jQuery for client-side development. The jQuery library is installed by default when you create a new ASP.NET website.

jQuery is simply a file of JavaScript code that allows you to more easily write JavaScript code that runs in many different browsers. This code can do many things; it can work with UI styles, handle user events, animate parts of your page, call back to the server via AJAX, and more.

The jQuery library has a core set of features on which you can build. In fact, there are many extensions and plug-ins available for jQuery that help with menus, UI controls, page layout, navigation, and much more. The following list outlines the essential functionality that jQuery provides.

  • Core The core of the jQuery library allows you to identify code that can execute only after a document has fully loaded, create DOM elements dynamically, iterate selected
    elements, create extensions to jQuery itself, and more.
  • Selecting jQuery’s power is in its ability to quickly select items in the DOM. You can easily return a single item from your page’s DOM or many items that match a pattern without having to write much code. You use the jQuery selectors to find specific HTML tags or to find form elements by ID, cascading style sheet class name, attribute or attribute value, and more.
  • Filtering and Traversing You can create filters to select only those DOM elements that meet your filter criteria. You can also traverse through your selection and act upon the selected items (by changing their style or adding an event, for example). Some important filter and traverse functions are first, last, odd, visible, match, selected, contains, enabled, find, next, prev, parent, and siblings.
  • Manipulation After you have selected an item (or multiple items), you can also use jQuery to manipulate the item. This might be as simple as evaluating the HTML contents or setting the text contents of the selected item. You can also use functions such as append, insert, replaceWith, wrap, and remove (among others) to add, modify, or remove content from the selected DOM item.
  • Cascading style sheets jQuery also provides functions for working with cascading style sheets. This includes finding and setting styles, positioning items, setting height and width, and more.
  • Events The jQuery library allows you to attach client code to user events in the browser. This decouples your event code from the actual markup. You can handle almost any user input event, including hover, toggle, click, dblclick, keydown, keyup, focus, mousedown, mouseenter, mouseleave, scroll, resize, and more.
  • Animation and Effects jQuery provides functions for adding effects to and animating the items on your page. Functions include show, hide, fadeIn, fadeOut, fadeTo, slideDown, slideUp, animate, and more.
  • AJAX The jQuery library supports AJAX calls from the browser to the server. It allows you to call a web service or client script on the server and return the results to the page without refreshing the entire page
  • Utilities There are several utility functions inside the jQuery language for working with browser compatibility, arrays, strings, and more.

The jQuery language is contained in a single file, jquery-.min.js, in
which version is the current version (1.4.1 at the time of this writing).

The jquery-1.4.1-vsdoc.js file is used by Visual Studio to provide IntelliSense in the text editor for jQuery code. Visual Studio simply looks for this file based on the naming convention and will provide the appropriate IntelliSense. The jquery-1.4.1.js file is the debug version of jQuery. This is a version of the code that is readable. You will want to reference this file in your code when you are debugging your client scripts. The jquery-1.4.1.min.js file is the “minified” version of the jQuery language. You use this file for production applications because it is a smaller client download and executes faster.

The jQuery language files are actually hosted by several content delivery networks (or CDNs). This ensures faster downloads and caching of the jQuery language. Microsoft provides a CDN host of jQuery at http://ajax.microsoft.com/ajax/jquery/jquery-1.4.2.min.js.
You can use this URL to reference the jQuery language in your production applications.

Where to go from here?

  • Official web site
  • Online documentation
  • Wikipedia
  • jQuery UI provides abstractions for low-level interaction and animation, advanced effects and high-level, themeable widgets, built on top of the jQuery JavaScript Library, that you can use to build highly interactive web applications.

Linq: Group by and sort

The following LINQ statement was the first one I wrote:


var hsQ = from hspt in hospitals
orderby hspt.County, hspt.City
group hspt by hspt.County;

It obviously groups by country and then sorts by city.

However, I found the following even better as it groups first by country, sorts by country and then sorts within the group by city:


var hsQ = from hspt in hospitals
orderby hspt.City
group hspt by hspt.County into hsptGroup
orderby hsptGroup.First().County
select hsptGroup;