.NET Performance Blog

July 1, 2009

ASP.NET MVC Grid – Part 3 – Sorting

Filed under: ASP.NET MVC — Eric P @ 11:57 am

For this part I implemented server side sorting.

screenshot

click image to see full screenshot

You can see demo here:
http://samples.entechsolutions.com/MvcGridSample/Part3

Code is available here:
http://samples.entechsolutions.com/Downloads/MvcGridSample/MvcGridSample_Part3.zip

Implementation

1. Started by adding sort links for ID column

	<th>
	     ID
	     <a href="#" onclick="sort('id', 'asc');">asc</a>
	     <a href="#" onclick="sort('id', 'desc');">desc</a>
	</th>

2. Added javascript and hidden fields to pass sorting information to controller

	<script type="text/javascript">
 	 	...

		function sort(sortField, sortDirection) {
			$("#gridAction").val("Sorted");
			
			$("#sortField").val(sortField);
			$("#sortDirection").val(sortDirection);

			submitForm();
		}    
				
		function submitForm() {
			var form = $("#grid").parents("form:first");
			form.submit();
		}            
	</script> 
 	
...

<%= Html.Hidden("sortField") %>
<%= Html.Hidden("sortDirection") %>

3. Modified CustomerController to handle sorting

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult List(int currentPage, int pageSize, string sortField, string sortDirection, string gridAction)
{
	if (gridAction == "PageSizeChanged" || gridAction == "Sorted")  //Resetting currentPage on Sorted action
		currentPage = 1;

	IQueryable<Customer> query = _customerService.GetQueryable();
	int totalRows = query.Count();
	if (totalRows==0)
		return View(new List<Customer>());

	//Update query with order by clause
	if (!String.IsNullOrEmpty(sortField))
		query = AddQuerySorting(query, sortField, sortDirection);

	int totalPages = (int)Math.Ceiling((double)totalRows / (double)pageSize);
	if (totalPages != 1)
		query = AddQueryPaging(query, pageSize, currentPage);
    
	//Update ViewData with new sort params
	UpdateSorterViewData(sortField, sortDirection);
	UpdatePagerViewData(totalPages, totalRows, currentPage, pageSize);
	
	List<Customer> customers = query.ToList();
	return View(customers);
}


private IQueryable<Customer> AddQuerySorting(IQueryable<Customer> query, string sortField, string sortDirection)
{
	//Used approach from http://www.singingeels.com/Articles/Self_Sorting_GridView_with_LINQ_Expression_Trees.aspx
	//instead of a long switch statement 
	var param = Expression.Parameter(typeof(Customer), "customer");
	var sortExpression = Expression.Lambda<Func<Customer, object>>
							(Expression.Convert(Expression.Property(param, sortField), typeof(object)), param);

	if (sortDirection == "Asc")
		query = query.OrderBy(sortExpression);
	else
		query = query.OrderByDescending(sortExpression);

	return query;
}


private void UpdateSorterViewData(string sortField, string sortDirection)
{
	ViewData["sortField"] = sortField;
	ViewData["sortDirection"] = sortDirection;
}

4. Changed UI to only display asc/desc image next to column being sorted. Also changed column heading labels to links. Used the following CSS to display ASC or DESC image next to link that was sorted.

#grid #data .asc{
	background: transparent url('../Content/Images/asc.png') center right no-repeat ;
}

#grid #data .desc{
	background: transparent url('../Content/Images/desc.png') center right no-repeat;
}

5. Made all columns sortable. Moved some of the sorting display logic to controller to prevent too much duplication.

Html was simplified to look like this:

<th>
	<a href="#" class="<%= CustomerController.GetGridThClass(ViewData, "FirstName") %>" 
				onclick="<%= CustomerController.GetGridThOnClick(ViewData, "FirstName")%>">
		First Name</a>
</th>

The new methods in CustomerController are:

public static string GetGridThClass(ViewDataDictionary<IEnumerable<Customer>> viewData, string sortField)
{
	if ((string)viewData["SortField"] != sortField)
		return "";

	if ((string)viewData["SortDirection"] == "Asc")
		return "asc";
	
	return "desc";
}


public static string GetGridThOnClick(ViewDataDictionary<IEnumerable<Customer>> viewData, string sortField)
{
	if ((string)viewData["SortField"] == sortField && (string)viewData["SortDirection"] == "Asc")
		return "sort('" + sortField + "', 'Desc');";

	return "sort('" + sortField + "', 'Asc');";
}

Observations

  • Discovered a nice way to post code in WordPress using ‘sourcecode’ tag here: http://support.wordpress.com/code/
  • ViewData is starting to remind me of a ViewState. With all the hidden variables it is basically the same thing. Of course without being bloated and encoded and not usable from JS.

Coming up…

At this point we have a grid with server side paging and server side sorting.

For next part I will create a Grid class/data structure with all the Pager and Sorter properties and pass it as a View model instead of using the non-strong typed ViewData[…].
I will also add keyword search with auto-complete.

June 29, 2009

ASP.NET MVC Grid – Part 2 – Paging

Filed under: ASP.NET MVC — Eric P @ 9:08 am

For Part 2 – I implemented server side paging.Mvc_Grid_WithPaging

You can see demo here:
http://samples.entechsolutions.com/MvcGridSample/Part2

Code is available here:
http://samples.entechsolutions.com/Downloads/MvcGridSample/MvcGridSample_Part2.zip

Implementation

To add server side paging to grid I made the following changes:

1. Add page navigational controls to the View. For this I used a simple “<< >>” approach. The HTML for this was pretty straight forward.

2. Add page size control. For this task I used a drop down populated using a function on CustomerController:

html was:

<%= Html.DropDownList("pageSize", CustomerController.PageSizeSelectList(), new { onchange = "onPageSizeChange()" })%> rows per page                  

and function on CustomerController

public static SelectList PageSizeSelectList()
{
	var pageSizes = new List {"1", "2", "5", "10", "100"};
	return new SelectList(pageSizes, "Value");
}

3. Add JS code to make paging navigation and page size operational

//Set hidden variable to go to next/prev/last/first page and submit the form
function goToPage(pageIndex) {
	$("#currentPage").val(pageIndex);
	$("#gridAction").val("CurrentPageChanged");

	submitForm();
}

//Set action performed in hidden variable. When PageSize changes - PageIndex needs to be
//reset to 1. This logic will go on the server side.
function onPageSizeChange(pageIndex) {
	$("#gridAction").val("PageSizeChanged");
	submitForm();
}                   

function submitForm() {
	var form = $("#grid").parents("form:first");
	form.submit();
}    

4. Update CustomerController to perform paging using LINQ.


[AcceptVerbs(HttpVerbs.Post)]
public ActionResult List(int currentPage, int pageSize, string gridAction)
{
        //Do logic depending on what action was performed
	if (gridAction == "PageSizeChanged")
		currentPage = 1;

        //Check if there are no results.  In this case return empty list.
	IQueryable query = _customerService.GetQueryable();
	int totalRows = query.Count();
	if (totalRows==0)
		return View(new List());

	int totalPages = (int)Math.Ceiling((double)totalRows / (double)pageSize);
	if (totalPages != 1)
	{
		//use LINQ to perform paging
		query = query.Skip((currentPage - 1) * pageSize)
						.Take(pageSize);
	}

        //Update ViewData collection to display pager stats and pager controls
	UpdatePagerViewData(totalPages, totalRows, currentPage, pageSize);

	List customers = query.ToList();
	return View(customers);
}

5. Cleanup CSS and table structure. This part took majority of the time. At first I was thinking of just using CSS and Divs for pager, but after having some issues with getting navigational control positioned in the middle, I decided to go with a table approach. In the end I ended up using a combination of Divs and CSS.

Observations

  • Using ViewData to pass information from Controller to View is getting heavy. I am currently passing 5-10 variables just for the pager. I think it makes sense to create data structure GridModel/Grid to hold all the variables. This approach has the following advantages:
    1. Strong typing using “if (gridModel.IsFirstPage) then ” instead of “if (bool)ViewState(“IsFirstPage”)
    2. Can keep call CustomerController.List(…) clean by using “UpdateModel(gridModel);” instead of passing more and more arguments to CustomerController.List(…);
    3. Will be able to compartmentalize Pager and Sorter using object hierarchy. For ex. GridModel.Pager.PageIndex, GridModel.Sorter.SortField, etc…
  • Noticed something weird in CSS. Using CSS class like:

    #grid #pager #navButtons table tr td .disabled {
    			color: #C0C0C0;
    			text-align: center;
    		}
    

    does not work. But if I change it to:

    #grid #pager #navButtons  .disabled {
    			color: #C0C0C0;
    			text-align: center;
    		}
    

    it will work. I wonder if CSS selectors don’t allow for matching “id tag class”.

For Part 3

In upcoming part 3, I will implement server side sorting.

June 25, 2009

ASP.NET MVC Grid – Part 1

Filed under: ASP.NET MVC — Eric P @ 8:29 am

I have been looking for a grid control for ASP.NET MVC. In the olden days of ASP.NET Web forms – I have been using a customized GridView which had the following features:

  1. Paging (server side)
  2. Sorting (server side)
  3. AJAX – using update panel around grid
  4. Page size
  5. External Filters
  6. Remembering the state of the Grid (page, sorting, etc…) so if user goes to page 2, clicks on “Edit” to modify one of the items and then goes back to grid – it will still be on Page 2

It looks like this:
Mvc_Grid_Old_Grid

U can see a demo of it here:
http://demos.entechsolutions.com/XWebSiteTemplate/Admin
Login: demo/demo

There are several options available for ASP.NET MVC:

1. MvcContrib Grid http://www.codeplex.com/MVCContrib/Wiki/View.aspx?title=Grid.
I really like fluent interface, but there are some issues with this control:

  • Only supports paging out of the box. If you want to add AJAX or sorting – have to do it yourself
  • Can end up with a mess of code mixed with HTML. I noticed that even with simple HTML. I think MVC should expose as much HTML as possible and only use inline code when needed. Otherwise – it would be a lot like Web Forms.
  • It doesn’t seem like the control has been updated for a while.

2. Using one of the client side grids and writing an AJAX layer for server-side paging, sorting, etc..
I have looked and jqGrid, extJs grid, flexiGrid and several others.

Each one has pluses and minuses, but one issue that I found in most, is that you are pretty much stuck with the UI they provide. There are themes and custom styles available for most, but it is extremely difficult to do any of the following

  • move the pager to a different position
  • replace the pager look from ‘<>’ to ‘1 2 3 …’
  • change the way sorting works (use up down errors instead of links or use a drop down)
  • modify how inline editing works

In most cases you will be stuck with whatever look the Grid has out of the box. In many of my projects – customer has very specific requirements about how they want the grid to look and feel, so picking one of the grids above would make it difficult to use in many circumstances.

3. Roll my own grid. This is the most flexible solution, but will probably take the most time. I am planning to use JQuery for javascript as well as any JQuery plugins that simplify client side development without restricting UI. I would like to expose as much HTML as possible to allow front end developers free reign on look and feel.

I plan to start with 6 features that I had in my ASP.NET web forms grid. I would also like to add the following features depending on how much time I have available:

  • check boxes for batch actions (like delete)
  • multi column sorting
  • hide/show columns
  • move columns around
  • provide a drop down menu in the column header (kinda like ExtJs)
  • inline row editing
  • expand row to display more information

Many of these features will be handled as separate samples (or add-ons) instead of being built-in into generic grid control.

As a first step I created a simple MVC web site and used MVC templates to create “List” and “Edit” pages.Mvc_Grid_SimpleGrid
For data I used an List of objects which will be re-created for any new user session. I plan to use LinqToObjects to perform various filtering/paging/sorting operations.

You can see the site here:
http://samples.entechsolutions.com/MvcGridSample/Part1

The code is available here:
http://samples.entechsolutions.com/Downloads/MvcGridSample/MvcGridSample_Part1.zip

The next step will be adding server side paging. Here it is in Part 2.

May 14, 2009

Web Sites vs Web Applications – build times

Filed under: General — Eric P @ 10:01 am

The enterprise-level application I am currently working on has several web projects built using “ASP.NET Web Site” model.
For a while now, I have been thinking of converting one of them to “Web Application” and see if it improves my compilation/build times. I took one of the smaller projects consisting of about 500 web pages and converted it to Web Application.

Results are as follows (using VS2008, cleaned solution before each build)

Web Site: 1 minute 20 seconds
Web Application: 2 secs

That’s a 60 times improvement. AMAZING.

There are definitely some drawbacks to switching to Web Application:
1. Not sure how to deal with namespaces. By default when you convert to “Web Application” – the code behind classes and classes in App_Code stay the same as before – no namespaces are added. But any new classes will have the namespaces. This type of inconsistency can be a bit confusing.
2. Namespaces introduce some naming conflicts, since some of my directory names match class name. For ex.
\UserControls\Order\UCViewOrder.ascx
The namespace will be “…UserControls.Order.UCViewOrder” which will conflict with my domain’s “Order” class.
Need to come up with some convention for this one.

These issues seem pretty small compared to SIXTY TIMES speed up in compilation time.

January 29, 2009

OOP vs Structured/Procedural programming (or DDD vs ADM)

Filed under: DDD,General — Eric P @ 12:26 pm

I think I may have succeeded in creating a headline with most Jargon evar… It is almost as bad as the name of my blog.

I have been having this dilemma. I have an enterprise level application written using OOP and ActiveRecord. It utilizes many OOP concepts such as Inheritance and Polymorphism. Recently I have been looking into making the system more friendly for Unit Testing. I talked about it to some developers working on the system and I had an interesting revelation: most of the developers prefer Structured/Procedural programming over OOP.

Here is the general overview of Procedural programming and OOP.
From http://www.umsl.edu/~subramaniana/concepts1.html

Procedural/Structured programming

  • Procedural Approach Data Structures can be represented as a network of associated structures, referring to one another.
  • Procedures can be represented as a network of routines which call one another, i.e., “call tree”

OOP

  • Object Oriented Approach Collection of discrete objects that incorporate data structures and behavior.
  • Each data structure has, combined with it, the procedures which apply to that data structure.
  • Contrasts with conventional programming in which data structures and behavior are only loosely connected
  • These entities, called objects, can be associated to one another in one network, rather than two.

DDD is based on OOP, while Anemic Domain Model is all about procedural programming.

Back to Dilemma. As much as Anemic Domain Model is an anti-pattern – it has one really nice thing going for it – it is simple and it makes sense to most developers and non-developers. How can Order ship itself, how can cake bake itself? Instead order and cake are just data and you have some OrderService and CakeService operating on them. With SOA even many business people can easily think in procedural terms.

My current system is written using OOP – objects have both data and actions. So I was hoping that switching to DDD would make OOP even more central to future development. The problem is that separating Active Record Entities into Repositories, Domain Entities and Application Services layer is confusing other developers on my team. Many of them come from procedural programming (aka Java EJB), so as soon as they see Entities and Services – then all logic goes into Services while Entities are just data structures.

Here is an example of what I have in my system:


Order
{
     OrderStatus _status;  (InProgress, Paid, Shipped)
     List _orderLines;
     
     Customer _customer;
     OrderBilling _billing; //Includes ShippingAddress and payment info
     OrderShipping _shipping;  
      
     DateCreated _dateCreated;
    
     AddOrderLine(product, quantity)
     RemoveOrderLine(orderLine)

     CalculateTotal();

     TakePayment();
     Ship();
}

Here is the same code written using ADM/Procedural:


Order
{
     OrderStatus _status;

     List _orderLines;
     Customer _customer;
     OrderBilling _billing;
     OrderShipping _shipping;  //Includes ShippingAddress and payment info
     DateCreated _dateCreated;
}


OrderService
{
     AddOrderLine(order, product, quantity)
     RemoveOrderLine(order, orderLine)
     
     CalculateTotal(order);

     TakePayment(order);
     Ship(order);
}

So what are the benefits of OOP vs ADM:
1. In OOP all the methods that operate on Entity are part of entity (or delegated to appropriate command/domain services by entity), while in Procedural – the code can be dispersed through many different services.

2. OOP is better for code re-use. Will need some examples for this one.

3. When refactoring, can use OOP Design Patterns like State Pattern for switching Order status.

But saying all this is not enough. There is only one way to make a convincing argument in Software Development:

SHOW ME THE CODE

In the upcoming blog entries, I will try to provide a real world coding example for each one of the points above…

January 28, 2009

One class per file or multiple classes in one file

Filed under: ASP.NET,General — Eric P @ 9:10 am

I browsed the internet for an answer to this question and the best I could find was:

“The primary benefit of a class per file is for source control and concurrent access: Why deal with the inevitable human error of code merges if each developer is really dealing with the separate classes.”

In my case there are several really small classes that seem like they can go into one file or be separated. As a personal style it seems best to put each class into separate file. This way I can easily see/find all the classes through solution explorer.

On the other hand it seems more like a stylistic argument, since I couldn’t find any evidence that it actually improves performance. I could also use VS diagramming tool to create a nice diagram for all the classes in a module.

So some possible guidelines for development team that can come out of this are:

  1. Allow including several classes in file only if each class is max of 10 lines of code.
  2. Classes in the same file must belong to the same Module (DDD Module)
  3. Enums should go in .cs file that uses them. If there are several classes that use enum – pick one.

Found another good reason for keeping classes in separate files:

“Also you’ll find many errors/diagnostics are reported via file name (“Error in Myclass.cpp, line 22″) and it helps if there’s a one-to-one correspondence between files and classes. ”
From: http://stackoverflow.com/questions/28160/multiple-classes-in-a-header-file-vs-a-single-header-file-per-class

August 9, 2006

ENTechSolutions.com launched, XLib is available for download

Filed under: .NET,General,XLib Framework — Eric P @ 1:51 pm

I finally launched a web site for my consulting company:

http://www.entechsolutions.com

At the same time I packaged BETA versions of XLib and XWebSiteTemplate.  You can find these products as well as AutoSuggestBox control in the ‘Developer Corner’ section of the web site.

July 18, 2006

AJAX Modal Dialog using UpdatePanel

Filed under: .NET,XLib Framework — Eric P @ 5:57 pm

Please see complete post here:

http://www.entechsolutions.com/Blog/ViewPost.aspx?PostID=6

May 17, 2006

.NET Web Service For Email Labs

Filed under: .NET,General — Eric P @ 10:53 am

Recently, one of the clients of my consulting business asked for an integrated email solution. I did some research and found that EmailLabs would fit client needs. They are one of the few companies that provide an API to their email marketing solution. The only issue is that their API is very basic — it works by sending and receiving XML messages through HTTP.

To simplify things I wrote .NET web service that wraps around HTTP messages. It allows .NET developers to quickly tap in into list management, message building and sending functionality provided by EmailLabs. The web service is available at the following location:

http://samples.entechsolutions.com/EmailLabsWebService/Service.asmx

This web service encapsulates about 80% of functionality of EmailLabs API. For this release I concentrated on most useful functions. I didn’t implement functions used for managing Filters and adding/editing Demographics.

To demo the API you can contact EmailLabs to setup a demo account. For testing they let you send e-mails with up to 50 recipients. Or you can send me an e-mail I will give you access to my demo account.

Security Considerations

For API integration EmailLabs provides IP security. For every mail list you can specify a list of IP Addresses that can contact EmailLabs API. To test .NET web service you can provide security the following 2 ways:

A. Disable IP Security for the list

  1. Edit mailing list in EmailLabs admin
  2. Uncheck the ‘Limit API access to these addresses:’ check box
  3. Save

For this approach you may want to create a new test list, so security for other lists stays the same.
B. Add IP Address ‘66.129.79.80’ to secure IP addresses list

  1. Edit mailing list in EmailLabs admin
  2. Check the ‘Limit API access to these addresses:’ check box.
    Add IP addresses ‘66.129.79.80’ to comma delimited list of allowed IP addresses.
  3. Save

This IP address is dynamic, so it is possible that it may change. Let me know if you get authentication error using this approach.

FYI: If you create a new mailing list using Web Service API – it will automatically add appropriate IP address to the list of allowed IP addresses.

April 28, 2006

Editable GridView with Add New/Insert button

Filed under: .NET,General — Eric P @ 6:05 pm

Please see the full post here:

http://www.entechsolutions.com/Blog/ViewPost.aspx?PostID=5 

« Previous PageNext Page »

Create a free website or blog at WordPress.com.