web 2.0

LINQ - How to Use Custom SQL Statements

I have a table where I stored encrypted passwords. In order to decrypt the passwords I wrote a UDF (user defined function) which utilizes SQL Server's DecryptByPassphrase function. By having the password encrypted in the table it prevents people from browsing the table and seeing the passwords in plain text.

When you need to retrieve a password you have to issue a sql statement like this:

select dbo.Decrypt(encryptedPassword) as Password from Password

I control the security on the UDF's so only a select few people can execute them. In any case, I have an application which used LINQ to SQL to access the passwords. The problem I ran into was that the SQL statements generated by LINQ have no idea to how to encrypt/decrypt my passwords. Therefore I had to build some custom procedures for LINQ to use.

The Insert Statement:

image

The two important things to notice here are:

  1. I call the UDF to encrypt the password when I insert the record
  2. The identity column is an output parameter. This way I can reference the primary key after the record is inserted.

In order to hook this stored procedure in with your LINQ Entity you need to do the following:

  1. Open your dbml file (LINQ Data Model).
  2. Make sure the methods pane is visible by right clicking on the design surface and choosing "Show Methods Pane"
  3. Open Server Explorer (View—>Server Explorer) and browse to the database where you created the procedure. Drag the procedure into the method pane.
  4. Open the LINQ entity that is going to use the SPROC and view the properties. Bring up the designer for the insert statement.
  5. When the designer appears, select the customize radio button. In the drop down list choose the stored procedure you dragged in the method pane.
  6. Make sure the arguments map correctly to the properties.

Repeat these steps for the Update and Delete statements if applicable.

Sorting Data in ASP.NET MVC

In the old days of WebForm development we took for granted all the little things that went on behind the scenes. For example, when you put a DataGridView on a WebForm you could set a few properties, and BOOM, you had sorting, paging and the works.

MVC has kind of brought web development back to its roots. This means that you have to do a little more work to get features like paging and sorting implemented. In order to simplify the sorting problem I made my own extension method using the HtmlHelper class to render the column headers. My code creates the links for the column headers and draws the sort indicators (without using any images!). The method utilizes two hard-coded variable names which are sidx and sord. The sidx variable is the name of the column to be sorted and the sord variable is the sort order (ascending or descending).

public static string SortableColumn(this HtmlHelper htmlHelper, string linkText, string columnName, object routeValues) {
//automatically determine the current action
System.Web.Routing.RouteData data = htmlHelper.ViewContext.Controller.ControllerContext.RouteData;
string actionName = data.GetRequiredString("action");

StringBuilder sb = new StringBuilder();
var vals = new RouteValueDictionary(routeValues);

string sidx = String.Empty;
if (System.Web.HttpContext.Current.Request["sidx"] != null) {
sidx = System.Web.HttpContext.Current.Request["sidx"].ToString();
}

//modify the sidx
if (vals.ContainsKey("sidx") == false) {
vals.Add("sidx", columnName);
}
else {
vals["sidx"] = columnName;
}

//get the sort order from the request variable if it exists
string sord = String.Empty;
if (System.Web.HttpContext.Current.Request["sord"] != null) {
sord = System.Web.HttpContext.Current.Request["sord"].ToString();
}

//add the sord key if needed
if (vals.ContainsKey("sord") == false) {
vals.Add("sord", String.Empty );
}

//if column matches
if (sidx.Equals(columnName, StringComparison.CurrentCultureIgnoreCase) == true) {
if (sord.Equals("asc", StringComparison.CurrentCultureIgnoreCase) == true) {
//draw the ascending sort indicator using the wingdings font.
sb.Append(" <font face='Wingdings 3'>&#112;</font>");
vals["sord"] = "desc";
}
else {
sb.Append(" <font face='Wingdings 3'>&#113;</font>");
vals["sord"] = "asc";
}
}
else {
//if the column does not match then force the next sort to ascending order
vals["sord"] = "asc";
}

//Use the ActionLink to build the link and insert it into the string
sb.Insert(0,System.Web.Mvc.Html.LinkExtensions.ActionLink(htmlHelper, linkText, actionName, vals));
return sb.ToString();
}

Next we need to utilize the method in the markup. The "helper" method really cleans up the code and is very simple to understand and use. Once the header is rendered, and you mouse over the link you should see a href that looks something like this:

/Instance/Assignments?dbaid=109&sidx=SecondaryDBA&sord=desc

<% object routeValues = new { dbaid = Request["dbaid"] }; %>

...

<table id="grid">
<tr>
<th><%=Html.SortableColumn("Instance", "InstanceName", routeValues )%></th>
<th><%=Html.SortableColumn("Primary DBA", "PrimaryDBA", routeValues )%></th>
<th><%=Html.SortableColumn("Secondary DBA", "SecondaryDBA", routeValues)%></th>
<th><%=Html.SortableColumn("Version", "Version", routeValues)%></th>
<th><%=Html.SortableColumn("RDBMS", "RDBMSTypeCD", routeValues)%></th>
<th><%=Html.SortableColumn("Bus. Group", "BusinessGroupCD", routeValues)%></th>
</tr>
<% foreach (var item in Model) { %>
<tr>
<td><%= Html.Encode(item.InstanceName) %></td>
<td><%= Html.Encode(item.PrimaryDBA) %></td>
<td><%= Html.Encode(item.SecondaryDBA) %></td>
<td><%= Html.Encode(item.Version) %></td>
<td><%= Html.Encode(item.RDBMSTypeCD) %></td>
<td><%= Html.Encode(item.BusinessGroupCD) %></td>
</tr>
<% } %>
</table>

Most importantly, the method in your controller that populates the grid must utilize the variables sidx (column to be sorted) and sord (sort order). Without this, you will not get any sorting...

public ActionResult Assignments( int? page, int? dbaid, string sidx, string sord ) {
try {
var query = InstanceRepository.GetAssignments(dbaid);

//sort the data
string sortExpression = (sidx ?? "InstanceName") + " " + (sord ?? "asc");
query = query.OrderBy(sortExpression);

//page the data
return View(query.ToPagedList(page ?? 1, MySession.PageSize));
}
catch {
return View("Error");
}
}

The data is sorted with the help of the Dynamic Linq library. I originally discovered this library after reading one of Scott Gu's posts. I also utilized the famous PagedList class to add pagination to the grid. Finally, here is the result:

Using JqGrid with ASP.NET MVC

UPDATE: 1/20/2009 - Implementing the jqGrid can be quite painful when you get into advanced configurations. My initial impression of jqGrid was based on the overall look and feel of the control. In the eyes of the end user, this control is amazing. However, for those who write the code to feed the grid, it can be a nightmare.

When I discovered the jQuery Grid I had very high expectations. So I thought I would put it through some tests to see if it could handle my requirements. The requirements are: paging, sorting, inline controls and filtering.

So, If you want to use jqGrid in your ASP.NET MVC app then just follow these steps:

  1. Download the jQuery Grid Plugin from trirand.com. The download is customizable. For the purposes of this demo you will only need the Grid base component.
  2. In the <HEAD> section of your HTML page put in the following js includes:
    <script type="text/javascript" src="/Scripts/i18n/grid.locale-en.js"></script>
    <script type="text/javascript" src="/Scripts/jquery.jqGrid.min.js"></script>    
  3. Optionally, you may want to include additional css references if you are using a jQuery theme. For example if you are using the overcast theme then you would also include these lines in the <HEAD> section of your HTML:
    <link rel="stylesheet" type="text/css" href="/Scripts/themes/overcast/ui.jqgrid.css"/>        
    <link rel="stylesheet" type="text/css" href="/Scripts/themes/overcast/ui.all.css"/>
  4. In the <BODY> of your HTML page you need to include this jqGrid initialization code:
        <script type="text/javascript">
            $(document).ready(function() {
                $("#list").jqGrid({
                    url: '/Instance/AssignmentsJson',
                    datatype: "json",
                    mtype: 'GET',
                    colNames: ['Instance', 'Version', 'Primary DBA', 'Secondary DBA'],
                    colModel: [
                                   { name: 'InstanceName', index: 'InstanceName', width: 300, formatter: 'showlink',
                                       formatoptions: { baseLinkUrl: '/Instance/Details', idName: 'name'}
                                   },
                                   { name: 'Version', index: 'Version', width: 80 },
                                   { name: 'PrimaryDBA', index: 'PrimaryDBA', width: 200 },
                                   { name: 'SecondaryDBA', index: 'SecondaryDBA', width: 200 }
                               ],
                    jsonReader: {
                        repeatitems: false,
                        id: "0"
                    },
                    rowNum: 50,
                    rowList: [10, 20, 30, 50],
                    pager: jQuery('#pager'),
                    viewrecords: true,
                    sortname: '0',
                    sortorder: "asc",
                    width: 800,
                    height: 500
                });
            });
      </script>
    So what exactly does this code do? I know, it can be a little overwhelming the first time you look at it. So I will break down the important parameters for you:
    • url - The url where the grid data is coming from. I will talk more about this in the upcoming steps.
    • datatype - I am using Json, which is Javascript object notation. However, the JqGrid also supports other formats such as XML.
    • mtype - Post of Get, since we are populating the grid we are going to use GET.
    • colNames - The user friendly column names.
    • colModel - This parameter is used to format each column and also to specify additional options, such as putting a drop down, date picker or other components in each cell. There should be a 1 to 1 mapping between colNames and colModel.
    • jsonReader - When using jqGrid with ASP.NET you will probably need to override the default jsonReader settings. Specifically, you will need to set the repeatitems parameter to false. Also in my example, I have a primary key which is a string. Therefore I tell the JqGrid that the first column returned in each row is the primary key. I could either use the column name or the column index. In my example I used "0" which is the index of the column.
  5. Also, in the <BODY> of your HTML page you should include the following two lines:
    <table id="list" cellpadding="0" cellspacing="0"></table> 
    <div id="pager"></div> 
    Note: The id's of the table and div correspond to the parameters in the javascript code above
  6. Ok, so now we have all the HTML and Javascript wired up. Now we just need to implement an Action inside our controller to return the Json data to populate the grid. The jqGrid normally expects data in this format:
    { 
      total: "xxx", 
      page: "yyy", 
      records: "zzz",
      rows : [
        {id:"1", cell:["cell11", "cell12", "cell13"]},
        {id:"2", cell:["cell21", "cell22", "cell23"]},
          ...
      ]
    }
    In the Json string above, there is header data, such as the total, page and records followed by an array of row data. In order to adhere to this format we will need to do some work when we return our data from the controller:
    public JsonResult AssignmentsJson( int? page, int? rows, string sidx, string sord ) {              
                  var query = from x in db.Instances
                                  where
                                      x.RemovedFromServiceDate == null
                                      && (x.PrimaryDBA != null || x.SecondaryDBA != null)                              
                                  select new
                                  {
                                      InstanceName = x.InstanceName,
                                      Version = x.DBVersion,
                                      PrimaryDBA = x.Contact.FullName,
                                      SecondaryDBA = x.Contact1.FullName
                                  };
                                
                  //sort the data
                  string sortExpression = (sidx ?? "InstanceName" ) + " " + (sord ?? "asc" );                  
                  query = query.OrderBy(sortExpression);
    
                  //page the data
                  var data = query.ToPagedList( page ?? 0, rows ?? MySession.PageSize);
    
                  //return it in a format acceptable to the JqGrid
                  var ret = new
                  {
                      total = data.PageCount-1, //number of pages
                      page = data.PageIndex,  //current page
                      records = data.TotalItemCount, //total items                        
                      rows = data
                  };
    
                  //put the data in the JSON format
                  return Json(ret);
              }
    Note: I am using the PagedList class from Rob Conery in my code. This allows me to easily implement paging with Linq. Also notice that the parameters are named sidx, sord, page and rows respectively. These parameter names are the default names expected by the JqGrid component. If the parameter names do no match, then your grid will not sort or page properly.

    The important things to note are the return type (JsonResult) and the structure created by the ret variable. We generated an anonymous class that included the header elements and the row data as an array. If you view this URL in your browser it should return the following:
    {"total":8,"page":0,"records":208,
    "rows":[{"InstanceName":"instance1",
    "Version":"10.2.0.4.0",
    "PrimaryDBA":"Smith, Jim",
    "SecondaryDBA":"Brown, Michael"}...]}
  7. If you followed all the steps correctly you should end up with a grid that looks something like this (sorry, had to blur some of the data for security reasons):

The JqGrid gives you a rich user experience but it is painful to customize and integrate into your application. The initial "cool factor" behind the look and feel of the grid made me want to use it in all of my applications. However, a few days later I ended up pulling it out in favor of standard HTML tables because I wanted to do some advanced things that were just way too painful to implement with jqGrid. Don't get me wrong, jqGrid is cool and the user experience is great but the steps to implement it made me cringe which eventually led me to pulling the plug on using the control all together.

Additional Resources:

System.IO Improvements in the .NET 4.0 Framework

I got a new MSDN article in the mail last week and I finally got around to reading it. One of the articles was titled "What's New in the .NET Framework 4 Base Class Library" by Justin Van Patten. This article is required reading for any .Net Developer, because whenever a new version of the framework is released it is important for developers to fully understand what has changed. There may be methods and functions that you have avoided over the years due to performance reasons. However, a newer release of the BCL may have addressed that issue and it may be time for you to revisit your code.

For example in the 4.0 release, a lot of System.IO libraries have been revamped. One shining example is the File.ReadAllLines method. In versions prior to .NET 4.0, I would have avoided using this method because when you are dealing with large text files you would have to wait indefinitely for all the lines in the file to be read into memory.

string[] lines = File.ReadAllLines("app.log");
foreach( string line in lines ){
   Console.WriteLine( line );
}

As an alternative, I normally use a TextReader to open the file and then read each line of the file into memory. This was generally more efficient and my default practice for dealing with any kind of file parsing.

using( TextReader reader = new StreamReader( "app.log" ) {
   string line;
   while(( line = reader.ReadLine()) != null ) {
      Console.WriteLine( line );
   }
}

Well fortunately, this problem has been addressed in the 4.0 libraries. They have overloaded the File.ReadAllLines method so we now have a method call that returns an IEnumerable<string>. Here is an example

IEnumerable<string> lines = File.ReadAllLines("app.log");
foreach( var line in lines ){
   Console.WriteLine( line );
}

The .NET 4.0 BCL library has also made optimizations for reading directories and files. Microsoft has done this by introducing new methods which return enumerable types. They also reduced the memory footprint by taking advantage of the underlying OS to read file metadata. Again, by using the enumerable type you no longer will block subsequent operations until all the files are retrieved. This should yield (no pun intended) a great improvement in performance.  Here is a list of the new methods

System.IO.File

  • public static IEnumerable<string>ReadLines(string path)
  • public static void WriteAllLines(string path, IEnumerable<string> contents)
  • public static void AppendAllLines(string path, IEnumerable<string> contents)

System.IO.Directory

  • public static Enumerable<string> EnumerateDirectories(string path)
  • public static IEnumerable<string> EnumerateFiles(string path)
  • public static IEnumerable<string> EnumerateFileSystemEntries(string path)

System.IO.DirectoryInfo

  • public IEnumerable<DirectoryInfo> EnumerateDirectories()
  • public IEnumerable<FileInfo> EnumerateFiles()
  • public IEnumerable<FileSystemInfo> EnumerateFileSystemInfos()

In addition to the System.IO improvements we also have support for tuples, parallel extensions and code contracts. All of these items are very important additions to the BCL that you should know about.

Additional Resources:

Simple Way to Process Command Line Arguments

For some reason I have been finding myself writing more console apps lately. Mostly to overcome unique problems with antiquated systems that rely heavily on batch file processing. Anyway, the most common problem people have when writing console apps is parsing all the arguments that get passed into the program. Since I have already written the code, I thought I would share...

static void ProcessArguments(string[] args) {
    string argString = String.Empty;
    //do a little work to remove unecessary spaces between the option and value
    foreach (string s in args) {
        if (s.StartsWith("-") && argString.Length > 0)
            argString += ",";

        argString += s;
    }

    string[] fixedArgs = argString.Split(new string[] { "," }, StringSplitOptions.RemoveEmptyEntries);

    string pattern = @"-(?<argument>[a-zA-Z])(?<value>.+)#";
    foreach (string argument in fixedArgs) {
        Match match = Regex.Match(argument, pattern, RegexOptions.IgnorePatternWhitespace);
        if (match != null) {
            string option = match.Groups["argument"].Value.ToUpper();
            string value = match.Groups["value"].Value;

            //String.Format( "{0}: {1}", option, value ).WriteDebug();
            if (option == "R") {
                int num;
                if (int.TryParse(value, out num) == true)
                    _retention = num;
            }

            if (option == "P") {
                _filePath = value;
            }
            else if (option == "S") {
                _searchPattern = value;
            }
        }
    }
}

First the code takes all the arguments and puts them to into a format that I can use to apply a regular expression against. For example, the command:

TraceArchiver.exe -p D:\DBA\profiler -s Daily_Thu* -r 7

Would produce an argString value of

-pD:\DBA\profiler,-sDaily_Thu*,-r7

Next, I split this formatted string into an array by using the Split function with the comma as the separator. Then, for each item in the string array I can apply my regular expression pattern against it: For example, if the first item in the string array is "–pD:\DBA\profiler", after the regex pattern (@"-(?<argument>[a-zA-Z])(?<value>.+)#") is applied to it there are two captures created. One titled "argument" and the other called "value".  Now that the string is "tokenized" we are only left with the simple task of checking which argument you are processing and assigning it to a variable. I hope this snippet of code is useful to someone out there. Happy coding :-)