Tuesday, December 21, 2010

Dynamic LINQ on DataTable

 

I’ve seen lots of examples of dynamic LINQ on the web. But all of them were using either LINQ to SQL or LINQ to Entity. I did not see any good example on net for using Dynamic LINQ on Data table.

My application was written in C# 2.0 with heavy use of data tables. Now since i’ve migrated my code to C# 4.0, i want to leverage LINQ and other cool features by not breaking my existing code base.

My Problem: In my data table, i’ve a property name “ARRIVE_TIME”; user has the option to filter the arrival time by selecting check box: Morning (up to 12 PM) , Afternoon (after 12 PM to 4 PM)  and Evening (after 4 PM). Based on their selection i would need to filter my data table which by default fetch all the times from the database. User has the option to select either one or all of the options. Initially i thought of using the Row Filter property of data table by dynamically creating the condition, but its an old school method. I wanted to use LINQ power to filter the data. Having said that, Microsoft did not make it any simple for using Dynamic LINQ on data tables. I even checked the System.Linq.Dynamic.DynamicQueryable class and it was useless for data tables.

So i had to write my own implementation for using Dynamic LINQ on data tables or data sets.

Solution: First we export data table as List<DataRow>. And then we define an expression of function datarow and boolean.

var data = (from t in datatable1.AsEnumerable().AsQueryable<DataRow>()
select t).ToList<DataRow>();

Expression<Func<DataRow, bool>> condition = null;



Now we add the conditions to expression based on the check box checked;


if (chkMorning.Checked)
{
condition = (p => p.Field<DateTime>("ARRIVE_TIME") <= Convert.toDateTime("12:00 PM"));
}
if (chkAfternoon.Checked)
{
condition = condition.Or(p => p.Field<DateTime>("ARRIVE_TIME") > Convert.toDateTime("12:00 PM"));
condition = condition.And(p => p.Field<DateTime>("ARRIVE_TIME") <= Convert.toDateTime("04:00 PM"));
}
if (chkEvening.Checked)
{
condition = condition.Or(p => p.Field<DateTime>("ARRIVE_TIME") > Convert.toDateTime("04:00 PM"));
}


You may need to tweak the above logic a bit based on your condition as what if the Morning check box is not checked then condition.Or in the next line will throw an error. So based on your requirements you need to set the first expression with out using Or/And.


I’ve written the Or and And extension methods to make this expression more readable.


public static Expression<Func<DataRow, bool>> And(this Expression<Func<DataRow, bool>> _leftside, Expression<Func<DataRow, bool>> _rightside)
{
ParameterExpression param = Expression.Parameter(typeof(DataRow));
return Expression.Lambda<Func<DataRow, bool>>
(Expression.AndAlso(Expression.Invoke(_leftside, param),Expression.Invoke(_rightside, param)), param);
}

public static Expression<Func<DataRow, bool>> Or(this Expression<Func<DataRow, bool>> _leftside, Expression<Func<DataRow, bool>> _rightside)
{
ParameterExpression param = Expression.Parameter(typeof(DataRow));
return Expression.Lambda<Func<DataRow, bool>>
(Expression.OrElse(Expression.Invoke(_leftside, param), Expression.Invoke(_rightside, param)), param);
}


Finally, you use the expression in you list. List.Where method will only accept the predicate of type FUNC<DataRow, bool>. so we just need to compile the expression.


data = data.Where(condition.Compile()).ToList<DataRow>();


You can use my Linq to data table method in order to get the data table back with filtered data.

Monday, November 1, 2010

Using async CTP in Silverlight with generated WCF Proxy

 

I was pretty excited about the async CTP announcement. I was eager to use async in my projects and wanted to get rid off most of the delegates which make all the more unreadable and maintenance nightmare for a new resource. We as developers always want to see the code in debug mode and check the flow of the code. With the async implementation, the code looks more cleaner.

So long story short, i wanted to use async CTP in my silverlight project. So i took the reference of AsyncCtpLibrary_Silverlight and i assume that now all my WCF proxy client will have the [Methodname]TaskAsync method where i can use await keyword. To my surprise, it was not there. I thought i might need to “Update Service Reference” so that the code can regenerated and i will get access to TaskAsync methods. But it didn’t work either. Then i started doing some research and i realized that Async CTP does not support generated WCF proxy class, that was pretty disappointing hmm….

Since i wanted to use async anyways, i wrote an extension method. This probably is not the best way but it worked for me. I was able to use await keyword at the method call and go rid off the delegates.

Here’s the example of the extension method i wrote:

public static Task<List<Customers>> GetCustomerInformationTaskAsync(this IService webClient, int aCustomerID)
{
var TaskCompSource = new TaskCompletionSource<List<Customers>>();
webClient.BeginGetCustomerInformation(aCustomerID, o =>
{
try
{
TaskCompSource.TrySetResult(webClient.BeginGetCustomerInformation(o));
}
catch (Exception e)
{
TaskCompSource.TrySetException(e);
}
}
, null);
return TaskCompSource.Task;



This extension method is ready to use in your client.


List<Customers> CustomerList = await objService.GetCustomerInformationTaskAsync(_customerId);


Happy coding!!!

Sunday, October 31, 2010

Linq to DataTable

 

I’ve been working on my old code which was just migrated from VS2005 to VS2010. In my version i could not leverage the LINQ and i was using lots of DataSets and DataTable by querying my stored procedures.

Now that my code has been upgraded to .Net 4 and VS2010 i wanted to leverage the LINQ instead of FOR Loops to make my code look cleaner, at the same time; i also did not want to break my existing functionalities So my Business layer can use LINQ to filter/sort/group data from DataSet and can still return DataSet to my presentation layer in order to maintain the integrity. There’s no straight way to use LINQ on DataSet and return DataSet, So i made a small extension method.

public static DataTable ToDataTable<T>(this IList<DataRow> data)
{
DataTable table = new DataTable();
if (data.Count > 0)
{
table = ((DataRow)data[0]).Table.Clone();
foreach (DataRow drData in data)
{
table.Rows.Add(drData.ItemArray);
}
}
return table;
}



Here’s how we use the ToDataTable extension:



private DataTable FilterCustomersByName(DataSet dts, string CustomerNames)
{
var Data = (from t in dts.Tables[0].AsEnumerable()
where CustomerNames.Contains(t.Field<string>("CUSTOMER_NAME").ToString())
select t).ToList().ToDataTable<DataRow>();
return Data;
}



enjoy!!

Friday, October 1, 2010

Call WCF service from JQuery

When i developed a WCF service in VS2010, i was really struggling modifying the web.config file. One of the feature of VS 2010 is the clean web.config or app.config. But in general we don’t pay too much attention to the code that is being generated by the visual studio.
So in VS 2008, it would be pretty simple to update the config file as we can see the existing service entries and use that code as a reference for our new entry. In order to call WCF service from JQuery, we need to make certain changes to web.config file and i could not find any example of updating the clean web.config file of VS2010.
So when i finally figured out how to update the clean CONFIG file, i thought it would be good idea to share for someone who are new to JQUERY and WCF.
Service Set up
1. First create a new WCF Service website
2. Since my service will return data in JSON format, we need to make following changes in your contract.
   1: [ServiceContract]
   2: public interface IService
   3: {
   4:  
   5:     [OperationContract]
   6:     [WebInvoke(Method = "POST", 
   7:         BodyStyle = WebMessageBodyStyle.Wrapped, 
   8:         RequestFormat = WebMessageFormat.Json, 
   9:         ResponseFormat = WebMessageFormat.Json)]
  10:     string GetData(string input);
  11:  
  12:  
  13:     // TODO: Add your service operations here
  14: }
3. Next we need to add the AspNetCompatibilityRequired attribute at class level. This class is a part of System.ServiceModel.Activation namespace.

   1: [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
   2: public class Service : IService
   3: {
   4:     public string GetData(string input)
   5:     {
   6:         return string.Format("You entered: {0}", input);
   7:     }
   8:  
   9:     
  10: }

4. When we create the WCF service in VS 2010, visual studio generates a clean config file. We need to update the web.config file. We need to add a new endpoint in order to allow JQuery communication. endpoint MUST be exposed using WebHttpBinding as this is the only type of binding that supports the transfer of JSON to and from JQuery. We also need to add the </webHttp> behavior on the endpoint.

our new web.config will resemble the following:

   1: <?xml version="1.0"?>
   2: <configuration>
   3:  
   4:   <system.web>
   5:     <compilation debug="false" targetFramework="4.0" />
   6:   </system.web>
   7:   <system.serviceModel>
   8:     <services>
   9:       <service behaviorConfiguration="JSonServiceBehavior" name="Service">
  10:         <endpoint address="" binding="webHttpBinding" behaviorConfiguration="JsonBehavior" contract="IService">
  11:           <identity>
  12:             <dns value="localhost"/>
  13:           </identity>
  14:         </endpoint>
  15:       </service>
  16:       
  17:     </services>
  18:     <behaviors>
  19:       <serviceBehaviors>
  20:         <behavior>
  21:           <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
  22:           <serviceMetadata httpGetEnabled="true"/>
  23:           <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
  24:           <serviceDebug includeExceptionDetailInFaults="false"/>
  25:         </behavior>
  26:         
  27:         <behavior name="JSonServiceBehavior">
  28:           <serviceMetadata httpGetEnabled="true"/>
  29:           <serviceDebug includeExceptionDetailInFaults="false"/>
  30:         </behavior>
  31:         
  32:       </serviceBehaviors>
  33:       <endpointBehaviors>
  34:         <behavior name="JsonBehavior">
  35:           <webHttp/>
  36:         </behavior>
  37:       </endpointBehaviors>
  38:     </behaviors>
  39:     <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  40:   </system.serviceModel>
  41:   <system.webServer>
  42:     <modules runAllManagedModulesForAllRequests="true"/>
  43:   </system.webServer>
  44:   
  45: </configuration>

 Client Set up

1. Add a new ASP.Net web site in the same Service solution, we’ll name it as WebSite. (new ASP.Net project template is very cool and it creates Master page and the general layout of the web site. Its a pretty cool even for making a sample application)

2. Just a button (either server side or plain HTML button) on the default.aspx page and add a Javascript function to make an AJAX call to our service that we’ve just created.

   1: <script language="javascript" type="text/javascript">
   2:  
   3:         function GetDataFromService() {
   4:  
   5:             var Url = "http://localhost/DataService/Service.svc/GetData";
   6:             var Parameter = '{"input" :"My Jquery Test"}';
   7:             $.ajax({
   8:                 type: "POST",
   9:                 contentType: "application/json; charset=utf-8",
  10:                 url: Url,
  11:                 data: Parameter,
  12:                 dataType: "json",
  13:                 success: function (response) {
  14:                     
  15:                     alert(response.GetDataResult);
  16:                 },
  17:                 error: function (message) {
  18:                     alert(message);
  19:                 }
  20:             });
  21:             return false;
  22:         }
  23:     </script>

3. We can invoke the Service methods by passing the method name in parameter.
4. Input parameter will also be passed as JSON string.
5. The result will be returned as <methodname>Result from WCF call.

Tuesday, September 21, 2010

Find number of lines Of Code (LOC) with LINQ

 

There are number of tools and projects available online to get the number of lines of code from your project. So what am i doing new? Well, actually there’s nothing new and I did not even cover all the scenarios. However, i’ve used the power of LINQ to achieve the results and doesn’t it look neat?

private static int CountNoOfLinesInApplication()
{
var CurrDirectory = @"C:\\ApplicationDirectory";
int lintCount = 0;
lintCount = (from t in Directory.GetFiles(CurrDirectory, "*.cs", SearchOption.AllDirectories)
where !t.EndsWith("AssemblyInfo.cs")
from line in File.ReadAllLines(t)
where line.Trim().Length > 1
&& (!line.StartsWith("//") || !line.StartsWith("///"))
select line).Count();
return lintCount;
}


I’ve written this program for my windows application and hence i wanted to avoid counting AssemblyInfo,cs file which is generated by visual studio, and i’ve also removed all blank lines and commented lines. This program only counts for .cs file, If you want to use this utility for ASP.net application and want to include .aspx files too then add an extra extension and you’re good to go :-)