Exclude Source Files From StyleCop Analysis

StyleCop is a useful tool that helps development teams establish coding standards per Microsoft best practices. Unfortunately, you will likely be inundated with hundreds of warnings if you run it on an existing codebase. I recently ran it on a solution which I inherited and Visual Studio displayed 1000 warnings. There are likely more and 1000 is the Visual Studio limit.

Here is a nice post on how to exclude files from being analyzed by StyleCop. By implementing this process, you can have StyleCop analyze only new files, which will hopefully lead to faster adoption since you won’t be confronted with hundreds of warnings at the outset.

Advertisements

Sorting With the ObjectDataSource Control

Introduction

When sorting with the ObjectDataSource control and the method used to retrieve the collection (specified in the ObjectDataSource’s SelectMethod propety) does not return a DataSet or DataTable, the method must implement a string parameter representing the sort expression. The parameter name is specified in the ObjectDataSource’s SortParameterName property.

Listing 1 shows an ObjectDataSource that gets a collection of Employee objects by calling a GetEmployees method. The method has a single parameter – sortExpression specifying how the collection should be sorted. The method returns an IEnumerable<Employee>.

<asp:ObjectDataSource ID="dataSourceEmployeeInformation" 
			runat="server" 
			TypeName="ObjectDataSourceExample.EmployeeDb" 
			SelectMethod="GetEmployees" 
			SortParameterName="sortExpression"/>

Listing 1

An easy way to sort this collection is to convert the collection into a DataView instance so that the type’s built-in sorting capabilities can be leveraged. Then convert the DataView back into an IEnumerable<Employee> which is returned to ASP.NET via the ObjectDataSource ready to be bound to controls on the page.

Since these conversions would likely be done by different classes in an application, they should be generalized. Listing 2 shows the signature of a method that converts an IEnumerable<T> into a DataView. Listing 3 shows the signature of a method that converts an DataView into a IEnumerable<T>. Notice that these two methods are implemented as extension methods.

public static IEnumerable<T> ToEnumerable<T>(
            this DataView view,
            Func<DataRowView, T> createObjectFunction
            )

Listing 2

public static IEnumerable<T> ToEnumerable<T>(
            this DataView view,
            Func<DataRowView, T> createObjectFunction
            )

Listing 3

The DataView.FromEnumerable Extension Method

Let us go through the DataView.FromEnumerable method introduced in Listing 2. The first parameter is the DataView instance the method operates on. The second parameter is the IEnumerable<T> to be converted. The third parameter is an IDictionary<string, Type> instance that will contain the column definitions for the DataView. The dictionary’s keys are the columns’ names and the values are the columns’ data types. The fourth parameter is a delegate representing a method accepting a DataRow and a collection item of type T that returns a DataRowView. Essentially the caller is responsible for the code that assigns the row values based on the values of the collection item instance. The method returns a DataView. Listing 4 shows the complete code for the method.

public static DataView FromEnumerable<T>(
            this DataView dv,
            IEnumerable<T> collection,
            IDictionary<string, Type> columnDefinitions,
            Func<DataRow, T, DataRow> addRowFunction
            )
        {
            if (collection == null)
            {
                throw new ArgumentNullException("collection", "Parameter cannot be null.");
            }

            if (collection.Any() == false)
            {
                return null;
            }

            if (columnDefinitions == null)
            {
                throw new ArgumentNullException("columnDefinitions", "Parameter cannot be null.");
            }

            if (columnDefinitions.Any() == false)
            {
                throw new InvalidOperationException("No column definitions were specified.");
            }

            if (addRowFunction == null)
            {
                throw new ArgumentNullException("addRowFunction", "Parameter cannot be null.");
            }

            DataTable dt = new DataTable();

            foreach (KeyValuePair<string, Type> keyValuePair in columnDefinitions)
            {
                dt.Columns.Add(keyValuePair.Key, keyValuePair.Value);
            }

            foreach (T item in collection)
            {
                DataRow row = dt.NewRow();
                row = addRowFunction(row, item);
                dt.Rows.Add(row);
            }

            return dt.DefaultView;

Listing 4

Lines 33-38 constructs a DataTable instance that is the basis for the DataView using the information provided in the dictionary. Lines 40-47 do the following for each item in the collection:

  1. Create a new DataRow instance.
  2. Calls the delegate, passing in the DataRow and collection item.
  3. The modified row is returned and added to the DataTable.
  4. The DataView represented by the DataTable’s DefaultView property is returned to the caller.

The DataView.ToEnumerable Extension Method

Let us go through the DataView.ToEnumerable method introduced in Listing 3. The first parameter is the DataView instance the method operates on. The second parameter specifies a delegate that takes a DataRowView and returns an item of type T. Essentially the caller is responsible for assigning the collection item’s properties based on the row values. The method returns an IEnumerable<T>. Listing 5 shows the complete code for the method.

public static IEnumerable<T> ToEnumerable<T>(
            this DataView view,
            Func<DataRowView, T> createObjectFunction
            )
        {
            if (view == null)
            {
                throw new ArgumentNullException("view", "Parameter cannot be null.");
            }

            if (createObjectFunction == null)
            {
                throw new ArgumentNullException("createObjectFunction", "Parameter cannot be null.");
            }

            IList<T> collection = new List<T>();

            foreach (DataRowView row in view)
            {
                T item = createObjectFunction(row);
                collection.Add(item);
            }

            return collection;
        }

Listing 5

Line 16 creates a new collection holding items of type T. Lines 18-22 do the following for each row in the view:

  1. Passes the row to the delegate, getting an item of type T in return.
  2. The row is added to the collection.

The collection is returned to the caller on Line 24.

Implementing the GetEmployees Method

Now a GetEmployees method that can be used for sorting by the ObjectDataSource can be written. Listing 6 shows the simple Employee class used in the method.

public class Employee
{
	public int EmployeeId { get; set; }
	public string FirstName { get; set; }
	public string LastName { get; set; }
	
	public Employee(
		int employeeId,
		string firstName,
		string lastName
		)
	{
		this.Id = employeeId;
		this.FirstName = firstName;
		this.LastName = lastName;
	}

	public Employee() : this(int.MinValue, null, null) { }
}

Listing 6

Personally I like to avoid classes with publicly settable properties. However, the ObjectDataSource requires this as well as a parameterless constructor. Listing 7 shows the complete GetEmployees implementation. The method retrieves a collection of Employees from the database and sorts them according to the value of the sortExpression parameter passed to the method.


public IEnumerable<Employee> GetEmployees(
	string sortExpression
	)
{
	//Simulate retrieving a collection from the database.

	IEnumerable<Employee> employees = new List<Employee>()
	{
		new Employee(1, "Farooq", "Mahmud"),
		new Employee(2, "Anny", "Mahmud"),
		new Employee(3, "Noor", "Mahmud"),
		new Employee(4, "Yasin", "Mahmud"),
	};

	Dictionary<string, Type> columnTypeMapping = new Dictionary<string, Type>()
	{
		{ "Id", typeof(int)},
		{"FirstName", typeof(string)},
		{"LastName", typeof(string)}
	};

	DataView dv = new DataView();

	dv = dv.FromEnumerable<Employee>(
		employees,
		columnTypeMapping,
		(row, emp) =>
		{
			row["Id"] = emp.Id;
			row["FirstName"] = emp.FirstName;
			row["LastName"] = emp.LastName;
			return row;
		}
	);

	dv.Sort = sortExpression;

	IEnumerable<Employee> sortedEmployees = dv.ToEnumerable<Employee>(
		row =>
		{
			return new Employee(
				(int)row["Id"],
				(string)row["FirstName"],
				(string)row["LastName"]
				);
		}
	);

	return sortedEmployees;
}

Listing 7

Lines 7-12 simulate retrieving a collection of employees from a database. Lines 15-20 specify the view’s structure. Lines 24-33 demonstrate calling DataView.FromEnumerable. Notice the lambda expression setting the view’s row values based on the Employee instance’s property values. The completed DataView is returned to the caller. On line 36, the view is sorted based on the value of the sortExpression parameter. In this case, assume the parameter is set to “LastName”. Now that the DataView has been sorted, a new collection must be created and the employees inserted in sorted order. Lines 38-47 accomplish that. Observer the lambda expression creating an Employee instance based on the DataView’s row values. Finally, on line 49, the sorted collection is returned to the caller.

Alternative Solutions

The IEnumerable<T> type includes the OrderBy extension method that can sort our employees. However, because the ObjectDataSource forces us to specify a string sort expression, there would be some parsing involved in order to create a method to pass to the OrderBy method.