LINQ Data Table Extensions

Legacy applications which is to be migrated to a new platform (WPF, Silverlight etc.,) requires leveraging the underlying business layer too. We have IQueryable interface implemented for DataTable in System.Data.DataSetExtensions. There are couple of extension providers present,

  • DataTableExtensions
  • EnumerableRowCollectionExtensions

Data Table Extensions

This provides a list of functions to query with the DataTable. Most of them are casting functions,

  • AsDataView<T>
    • Accepts a EnumerableRowCollection and returns a DataView.
  • AsDataView
    • Accepts a DataTable and returns a DataView.
  • AsEnumerable
    • Accepts a DataTable and returns a EnumerableRowCollection, which is used for querying with DataRow collection.

Enumerable Row Collection Extensions

The LINQ provider is implemented for the DataRowCollection that is present in the DataTable.Rows property. The following are the LINQ extensions you can work with,

  • Select
  • OrderBy
  • OrderByDescending
  • ThenBy
  • ThenByDescending
  • Where
  • Cast

Select

Use the Select extension to get the query the required fields from the DataTable.

private static void SelectDataTable()
        {
            var dt = GetOrdersDataTable();
            var orders = dt.AsEnumerable().Select(o =>
                new
                {
                    OrderID = o.Field<int>("OrderID"),
                    CustomerID = o.Field<string>("CustomerID"),
                    EmployeeID = o.Field<int>("EmployeeID"),
                    OrderDate = o.Field<DateTime>("OrderDate"),
                    ShipCountry = o.Field<string>("ShipCountry")
                });
            foreach (var order in orders)
            {
                Console.WriteLine(string.Format("OrderID : {0} / CustomerID : {1} / EmployeeID : {2} 
/ OrderDate : {3} / ShipCountry : {4}", order.OrderID, order.CustomerID, 
order.EmployeeID, order.OrderDate, order.ShipCountry));
            }
        }

The Field<T> returns a strongly typed value from the underlying DataTable. You can also use SetField<T> 
to set the field value thru a strongly typed object.

OrderBy / OrderByDescending / ThenBy / ThenByDescending

Sort operations can be performed by using the above mentioned functions. Check out the code below,

 

private static void SortDataTable()
{
    var dt = GetOrdersDataTable();
    var orders = dt.AsEnumerable().OrderBy(r => r.Field<string>("ShipCountry"));
    var result = orders.ThenBy(r => r.Field<string>("CustomerID")).Select(o =>
        new
        {
            OrderID = o.Field<int>("OrderID"),
            CustomerID = o.Field<string>("CustomerID"),
            EmployeeID = o.Field<int>("EmployeeID"),
            OrderDate = o.Field<DateTime>("OrderDate"),
            ShipCountry = o.Field<string>("ShipCountry")
        });
    foreach (var order in result)
    {
        Console.WriteLine(string.Format("OrderID : {0} / CustomerID : {1} / EmployeeID : {2} 
/ OrderDate : {3} / ShipCountry : {4}", order.OrderID, order.CustomerID, order.EmployeeID, 
order.OrderDate, order.ShipCountry));
    }
}

Where

Filter operations require a predicate match to be passed. Check out the code below,
private static void WhereOperation()
{
    var dt = GetOrdersDataTable();
    var filteredOrders = dt.AsEnumerable().Where(o => o.Field<string>("ShipCountry") == "Brazil")
.Select(o =>
        new
        {
            OrderID = o.Field<int>("OrderID"),
            CustomerID = o.Field<string>("CustomerID"),
            EmployeeID = o.Field<int>("EmployeeID"),
            OrderDate = o.Field<DateTime>("OrderDate"),
            ShipCountry = o.Field<string>("ShipCountry")
        });
    foreach (var order in filteredOrders)
    {
        Console.WriteLine(string.Format("OrderID : {0} / CustomerID : {1} / EmployeeID : {2} 
/ OrderDate : {3} / ShipCountry : {4}", order.OrderID, order.CustomerID, 
order.EmployeeID, order.OrderDate, order.ShipCountry));
    }
}
With these functions we can easily translate our code to more typed collection and work 
with the legacy DataTable objects.
Note: The API documentation suggests that these API’s are used internally in the .NET FW and 
not intended to be used in our code directly :).
Hope this helps.
-Fahad 

Let the ASP.NET ScriptManager render jQuery

using ASP.NET client library + jQuery is not much of a fun, it makes use of lesser jQuery core functionalities. But we sure want to use the ASP.NET to create our server-side HTML code and use jQuery to give the UI behavior.

I have a small class that abstracts the behavior and makes the ScriptManager to render out JavaScript code for jQuery. This really helps out in keeping jQuery code be jQuery itself,

   1: using System;
   2: using System.Collections.Generic;
   3: using System.Text;
   4: using System.Web.UI;
   5: using System.Web.Script.Serialization;
   6: 
   7: namespace jQuery.Plugins {
   8:     public class jQueryComponentDescriptor : ScriptDescriptor {
   9: 
  10:         private string _type;
  11:         private string _elementID;
  12:         private SortedList<string, object> _properties;
  13:         internal const string NullStringException = "Cannot have null string";
  14:         private JavaScriptSerializer _serializer;
  15: 
  16:         public jQueryComponentDescriptor(string type) {
  17:             this._type = type;
  18:             this._properties = new SortedList<string, object>();
  19:             this._serializer = new JavaScriptSerializer();
  20:         }
  21: 
  22:         public jQueryComponentDescriptor(string type, string elementID)
  23:             : this(type) {
  24:             this._elementID = elementID;
  25:         }
  26: 
  27:         public string ElementID {
  28:             get {
  29:                 return this._elementID;
  30:             }
  31:         }
  32: 
  33:         public void AddProperty(string propertyName, object value) {
  34:             if (string.IsNullOrEmpty(propertyName))
  35:                 throw new InvalidOperationException(NullStringException);
  36:             this._properties[propertyName] = value;
  37:         }
  38: 
  39:         protected override string GetScript() {
  40:             //return the jQuery script here
  41:             if (this._properties.Count > 0) {
  42:                 StringBuilder builder = new StringBuilder();
  43:                 builder.Append("$('#" + this.ElementID + "')");
  44:                 builder.Append("." + this._type);
  45:                 builder.Append("({");
  46:                 int i = 0;
  47:                 foreach (KeyValuePair<string, object> pair in this._properties) {
  48:                     i++;
  49:                     builder.Append(pair.Key);
  50:                     builder.Append(":");
  51:                     builder.Append(this._serializer.Serialize(pair.Value));
  52:                     if (i != this._properties.Count)
  53:                         builder.Append(",");
  54:                 }
  55:                 builder.Append("});");
  56:                 return builder.ToString();
  57:             }
  58:             return string.Empty;
  59:         }
  60: 
  61:     }
  62: }

 

Now use this code instead of the ScriptControlDescriptor / ScriptComponentDescriptor that we normally use with the IScriptControl implementation in our server-sided code,

   1: IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors() {
   2:     jQueryComponentDescriptor jDesc = new 
jQueryComponentDescriptor("somejQueryPlugin", this.ClientID);
   3:     jDesc.AddProperty("positiveTextColor"
this.PositiveTextColor);
   4:     jDesc.AddProperty("negativeTextColor"
this.NegativeTextColor);
   5:     yield return jDesc;
   6: }

 

That was pretty simple. Once you have this done, the ASP.NET ScriptManager would automatically create the load up script code as,

   1: Sys.Application.add_init(function() {
   2:     $('#something').somePlugin({negativeTextColor:"Red"
,positiveTextColor:"Blue"});
   3: });

 

I just started working on this and so there might be issues with the jQueryComponentDescriptor. Do let me know if you face any issues with different scenarios. In the next post I will make out a clear sample that uses both this functionality.

Hope this helps!!

-Fahad

Detect Google Chrome in ASP.NET AJAX

Google launched a new fast browser recently (currently in beta) – Chrome. Getting in short, with ASP.NET we do have some functionality for detecting browsers using the Sys.Browser class.

Extend the prototype as follows,

//Google chrome check
Sys.Browser.Chrome = {};
if (navigator.userAgent.indexOf(' Chrome/') > -1) {
    Sys.Browser.agent = Sys.Browser.Chrome;
    Sys.Browser.version = parseFloat(navigator.userAgent.match(/ Chrome\/(\d+\.\d+)/)[1]);
    Sys.Browser.name = 'Chrome';
    Sys.Browser.hasDebuggerStatement = true;
}
Once you have this included in your script file and loaded inside the page, you can check it out as follows,
if(Sys.Browser.agent == Sys.Browser.Chrome){
//Write code for Chrome specific browser
}
Hope this helps!!
-Fahad

Localizing a custom web control in ASP.NET

Localization in custom web controls are needed when we would want to change default text according to some localized language. This allows the developers to create resource satellite assemblies and deploy as a multi-lingual website. In this post, we would look into creating one such localized button whose text is determined based on the language selected.

Create a resource manager –

  • We need a resource manager to read from embedded resource. I have named my resources in the FControls project as “SR”, and so
    • My resource class would be sr.cs
    • My resource text file would be sr.txt
    • My resources generated file would be sr.resources
  • Code snippet for the sr class,
   1: public class SR
   2: {
   3:     private ResourceManager resources;
   4:
   5:     public SR( ) {
   6:         this.resources = new ResourceManager( this.GetType( ) );
   7:     }
   8:
   9:     private static SR _managerDefault = null;
  10:     /// <summary>
  11:     /// Gets the default SR static instance.
  12:     /// </summary>
  13:     /// <value>The default.</value>
  14:     public static SR Default {
  15:         get {
  16:             if ( _managerDefault == null )
  17:                 _managerDefault = new SR( );
  18:             return _managerDefault;
  19:         }
  20:     }
  21:
  22:     /// <summary>
  23:     /// Gets the string from the resource manager.
  24:     /// </summary>
  25:     /// <param name="culture">The culture.</param>
  26:     /// <param name="name">The name.</param>
  27:     /// <param name="args">The args.</param>
  28:     /// <returns></returns>
  29:     public string GetString( CultureInfo culture, string name, params object[] args ) {
  30:         string value = this.resources.GetString( name, culture );
  31:         return string.Format( value, args );
  32:     }
  33:
  34:     public string GetString( string name ) {
  35:         return this.GetString( null, name );
  36:     }
  37:
  38:     public string GetString( string name, params object[] args ) {
  39:         return this.GetString( null, name, args );
  40:     }
  41:
  42: }

How to use the resource manager –

  • Define your constants in a sr.txt file. In our example, we are going to have a button whose text is localized.
  • Create a sr.txt file and add it to the project,

sr.txt

  • Then add the text values that you would expose for localizing. In our FButton, I have kept the localizing string as “ButtonText”. Enter that string in the sr.txt file as,
    • ButtonText = Click Me!!

Generate the resources file using resgen –

  • We need to create a resources file that would enable our resource manager to read the localized strings,
  • Enter the following command in your VS2005/VS2008 command prompt,
    • resgen sr.txt sr.resources.resources
  • This would create a resources file. Include that in your project.

Use the resource value in your control –

  • We would be adding a button control whose text is a localized string. Check out the following code snippet,
   1: protected override void CreateChildControls( ) {
   2:            this.Controls.Clear( );
   3:            Button btn = new Button( );
   4:            btn.Text = SR.Default.GetString( FLocButtonConstants.ButtonCaptionText );
   5:            if ( !this.Width.IsEmpty )
   6:                btn.Width = this.Width;
   7:            else
   8:                btn.Width = new Unit( 100 );
   9:            if ( !this.Height.IsEmpty )
  10:                btn.Height = this.Height;
  11:            this.Controls.Add( btn );
  12:        }
We now have a button control that is localized. Now lets create a website project and demo our localization in different languages.
  • Create a default website project.
  • Point your output directory of the library project to the website’s bin directory. This would make your website project refresh whenever you make a change in the control library ( just a quick way to check out ).

sshot-2

  • Once everything is set, we can use our FLocButton in our webpage,
   1: <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
   2:
   3: <%@ Register Assembly="FControls" Namespace="FControls" TagPrefix="FControls" %>
   4: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
   5: <html xmlns="http://www.w3.org/1999/xhtml">
   6: <head runat="server">
   7:     <title>Localization demo on Custom web controls</title>
   8: </head>
   9: <body>
  10:     <form id="form1" runat="server">
  11:     <div>
  12:         <FControls:FLocButton Width="100px" Height="50px" ID="Btn" runat="server" />
  13:     </div>
  14:     </form>
  15: </body>
  16: </html>
  • Running this sample, would turn up a page with a button and a text saying “Click Me!!”. Since we are rather interested in getting the localized string into the button. We would directly see how to create one such.
  • Add a couple of resource files named in any directory as you would wish to,

sshot-3

  • We have a “de-DE” and “fr-FR” named resources added up. Inside the resource file just name the resource string id and its corresponding value that you would want to show up when the UICulture is set. Shown below is a resource string set for “German / de-DE” culture.

sshot-4

Code to localize –

  • To set the UICulture use the following code,
   1: /// <Summary>
   2: /// Sets the current UICulture and CurrentCulture based on
   3: /// the arguments
   4: /// </Summary>
   5: /// <PARAM name="name"></PARAM>
   6: /// <PARAM name="locale"></PARAM>
   7: protected void SetCulture( string name, string locale ) {
   8:     Thread.CurrentThread.CurrentUICulture = new CultureInfo( name );
   9:     Thread.CurrentThread.CurrentCulture = new CultureInfo( locale );
  10: }
  • We need to override the InitializeCulture() function in the Page to set the UICulture for the page. In our application, it has a DropDownList, through which we would want the UICulture to set on each postback,
   1: protected override void InitializeCulture( ) {
   2:     if ( Request["__EVENTTARGET"] != null ) {
   3:         string controlID = Request["__EVENTTARGET"];
   4:         if ( controlID != string.Empty ) {
   5:             string selectedValue =
   6:                    Request.Form[Request["__EVENTTARGET"]].ToString( );
   7:
   8:             switch ( selectedValue ) {
   9:                 case "0": SetCulture( "de-DE", "de-DE" );
  10:                     break;
  11:                 case "1": SetCulture( "fr-FR", "fr-FR" );
  12:                     break;
  13:                 default: break;
  14:             }
  15:         }
  16:     }
  17:     base.InitializeCulture( );
  18: }
  • If you execute the page, the results would be as follows,

sshot-5

  • The zipped version of the sample can be found here.

That’s it!!, we have the strings localized.

Flinq – How to?

F# has given a new way for programmers to think, with its fundamentals based on functional programming, it gives a new higher order level the way we used to solve our daily programming problems. I was always fascinated about LINQ  which has it base on fundamental programming. When I looked up at F#, I just had thought it was just another language. But after checking it out, it was very different, different than we normally used to program in our daily lives. It lends me to think in rather unconventional way than OO based languages.

In this part of the post I will not try to explain the basics of F#, but rather a more specific part of C# – “LINQ”.

First get the latest version of the F# setup from the F# website. Once you install it, you would need to browse through the flinq directories sample “C:\Program Files\FSharp-<version number>\samples\fsharp\FLinq”.

  • Open up the FLinq project.
  • Build the “FLinq” project to generate the FLINQ assembly.

flinq

  • Once you generate this assembly, you could easily run any of the samples that is present in the next project.
  • On the other way, if you would want to use the FLinq assembly in your own project. All you have to do is refer the “fsharp.linq.dllassembly in your project,
   1: #I "C:\Program Files\FSharp-1.9.4.17\samples\fsharp\FLinq (Path to your fsharp assembly)";;
   2: #r "fsharp.linq.dll";;

That’s it!! You would be starting off with your Flinq projects. In coming posts we would check out more in detail about using Flinq, F# with applications, controls and other stuff.