Entity Framework 6 Weirdness

I used NuGet to install Entity Framework for a new project. To my surprise Entity Framework 6 was installed and version 5 is no longer available. The configuration file is certainly more complicated than it was in version 5. You are now required to have the entityFramework section in the application configuration file even if you are working with code-first.

So I was seeing the following error when running a test that inserted an entity into my database:

Unable to create instance of class PingYourPackage.Data.Tests.Repositories.And_Working_With_Roles. Error: System.InvalidOperationException: The Entity Framework provider type ‘System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer’ registered in the application config file for the ADO.NET provider with invariant name ‘System.Data.SqlClient’ could not be loaded. Make sure that the assembly-qualified name is used and that the assembly is available to the running application. See http://go.microsoft.com/fwlink/?LinkId=260882 for more information..

I went to the link in the error message and verified the configuration file was properly written during the NuGet package installation. I also saw that a reference had been added to EntityFramework.SqlServer.dll. I opened the assembly in Object Browser and verified that System.Data.Entity.SqlServer.SqlProviderServices was indeed present.

The stack trace was pretty deep, but it started in my DbContext derived class’s constructor:

at System.Data.Entity.DbContext..ctor(String nameOrConnectionString)
at MyAssembly.Data.MyDbContext..ctor()

I figured I try load the type myself so I put in this code in my DbContext derived class’s static constructor:

// Without this line, EF6 will break.
var type = typeof(System.Data.Entity.SqlServer.SqlProviderServices);

Problem solved.

My configuration file is shown below for reference. Note than with Entity Framework 5, I only needed the connection string section when working with code-first.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
  <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --></configSections>
  <connectionStrings>
    <add name="MyDatabase" connectionString="Data Source =.;Initial Catalog=MyDatabase;Integrated Security=True" providerName="System.Data.SqlClient"  />
  </connectionStrings>
  <entityFramework>
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>
</configuration>
Advertisements

The serviceSecurityAudit Service Behavior

The serviceSecurityAudit service behavior helped me figure out an exception I was receiving from my WCF service. As shown below, the exception was not very helpful:

System.ServiceModel.Security.MessageSecurityException occurred
  HResult=-2146233087
  Message=An unsecured or incorrectly secured fault was received from the other party. See the inner FaultException for the fault code and detail.
  Source=mscorlib
  StackTrace:
    Server stack trace:
       at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.ProcessReply(Message reply, SecurityProtocolCorrelationState correlationState, TimeSpan timeout)
       at System.ServiceModel.Channels.SecurityChannelFactory`1.SecurityRequestChannel.Request(Message message, TimeSpan timeout)
       at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.DoOperation(SecuritySessionOperation operation, EndpointAddress target, Uri via, SecurityToken currentToken, TimeSpan timeout)
       at System.ServiceModel.Security.SecuritySessionSecurityTokenProvider.GetTokenCore(TimeSpan timeout)
       at System.IdentityModel.Selectors.SecurityTokenProvider.GetToken(TimeSpan timeout)
       at System.ServiceModel.Security.SecuritySessionClientSettings`1.ClientSecuritySessionChannel.OnOpen(TimeSpan timeout)
       at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
       at System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
       at System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
    Exception rethrown at [0]:
       at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
       at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
       at System.ServiceModel.ICommunicationObject.Open(TimeSpan timeout)
       at System.ServiceModel.ClientBase`1.System.ServiceModel.ICommunicationObject.Open(TimeSpan timeout)
       at System.ServiceModel.ClientBase`1.Open()
       at ProductsClient2.Program.Main(String[] args) in c:\Users\farooqm\Documents\Visual Studio 2012\Projects\WCF 4 Step By Step\Chapter 5\ProductsClient2\Program.cs:line 32
  InnerException: System.ServiceModel.FaultException
       HResult=-2146233087
       Message=An error occurred when verifying security for the message.
       InnerException:

Enter serviceSecurityAudit to the rescue. You can configure this to write security related service events to the Windows Event Log. Simply add the code in Listing 1.

  
<servicebehaviors>
     <behavior name="MyService_serviceSecurityAuditBehavior">
          <servicesecurityaudit 
               auditloglocation="Application" 
               serviceauthorizationauditlevel="SuccessOrFailure" 
               messageauthenticationauditlevel="SuccessOrFailure" />
     </behavior>
</servicebehaviors> 

Listing 1

Now when the service fails, take a look at the errors in the Windows Application Event Log. Listing 2 shows the messages seen in a PowerShell session.

 

PS C:\windows\system32> get-eventlog -logname application -entrytype error -newest 10 | fl message

Message : Message authentication failed.          
          Service: https://farooqmelite3/InternetProductsService/ProductService.svc
          Action: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/SCT
          ClientIdentity: 
          ActivityId: <null>
          SqlException: An attempt to attach an auto-named database for file C:\Users\farooqm\Documents\Visual Studio 
          2012\Projects\WCF 4 Step By Step\Chapter 5\ProductsService\App_Data\aspnetdb.mdf failed. A database with the 
          same name exists, or specified file cannot be opened, or it is located on UNC share.

Listing 2

Turns out the application pool’s identity did not have permissions to create the ASP.NET membership provider database. Changing the identity to a different account resolved the issue as shown by the event log entries in Listing 3.

 

PS C:\windows\system32> get-eventlog -logname application -entrytype information -source "ServiceModel Audit 4.0.0.0" -newest 10 | fl message
Message : Impersonation succeeded.
          MethodName: GetProductNumbers
          ClientIdentity: bubba
          ActivityId: <null>
		  
Message : Service authorization succeeded.
          Service: https://farooqmelite3/InternetProductsService/ProductService.svc
          Action: http://tempuri.org/IProductService/GetProductNumbers
          ClientIdentity: bubba
          AuthorizationContext: uuid-2db2091a-8226-4e3d-a422-1720388491a0-1
          ActivityId: <null>
          ServiceAuthorizationManager: <default>

Message : Message authentication succeeded.
          Service: https://farooqmelite3/InternetProductsService/ProductService.svc
          Action: http://tempuri.org/IProductService/GetProductNumbers
          ClientIdentity: bubba
          ActivityId: <null>

Message : Message authentication succeeded.
          Service: https://farooqmelite3/InternetProductsService/ProductService.svc
          Action: http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/SCT
          ClientIdentity: bubba
          ActivityId: <null>

Listing 3

Hopefully, you will find the serviceSecurityAudit saves you time troubleshooting security related issues with your WCF service.

MVC Pattern

Introduction

Recently, I was at Half-Price Books where Pro ASP.NET 4 in C# 2010  by Matthew McDonald, et al was sitting (at more than half-off the retail price, by the way). I started to thumb through the book and in Chapter 12, we learn how to build a simple file browser web application. The code was simple enough and I started thinking about the MVC pattern and how I could adapt this example to use MVC. I conceptually understand the MVC pattern and why it helps. However, I do have questions and concerns about it, mostly around the model. Isn’t it just the business logic layer or a data layer? In other words, to me it didn’t seem like it was directly tied into the presentation. Why does it specifically need to be part of this pattern? It seems to me that the view and controller should be sufficient and the model seemed extraneous. Second, the controller is just a forwarder for the view. Why couldn’t the controller do more? These questions puzzled me the most about the MVC pattern. I put the book back and continued browsing the shelves.

Must have been my lucky day because also on the shelf was Microsoft .NET: Architecting Applications for the Enterprise by Dino Esposito et al. I had borrowed it from the corporate library several times for reference while doing design work. I never looked at Chapter 7 in detail which talks about the presentation layer although I knew it mentioned the MVC pattern. I found a chair and started reading. I never realized that this pattern had such an interesting history. I was also gratified that my MVC questions were answered.

The Original MVC Paradigm

Esposito takes the reader through a history of MVC starting with the original MVC paradigm mentioned in a MVC 1979 paper. Esposito places emphasis on the term “paradigm” as it implies a construct that is amenable to modification and extension as opposed to a pattern which is more firmly rooted. This is probably the reason why there are so many variations of MVC. Figure 1 shows the original MVC pattern as discussed in the paper. The paper refers to the model, view, and controller as the “MVC triad.”

image

         

Figure 1

         

The green lines show the typical sequence of operations with an optional operation in purple. Esposito mentions that the main issue with the original MVC is that the model can communicate with both the controller and the view. In a layered design, lower levels should only communicate with the layer directly above it. In the original MVC, this is not the case. A second issue is that the controller is dependent on a concrete implementation of the view. This makes it difficult for an application to support multiple views or change the view entirely (say from an ASP.NET form to a Windows form). The same holds true for the dependency on the controller on a concrete model implementation.

The Model View Presenter Pattern

The coupling issues inherent in the original formulation of MVC, led to the formation of the Model View Presenter (MVP) pattern. This pattern is first mentioned in this paper. This pattern is a descendant of MVC but gives the controller more power, thus eliminating the coupling of the model to the view. The controller becomes the central figure in the pattern. The view becomes “dumber” because it does not have to interact with the model. The upshot of all this is that the solution becomes more testable. Now that the UI contains code that simply operates on visual elements, the need for automated testing in the view is reduced. The automated testing can now be focused solely on the controller. A second benefit is that the view can be changed (say from a ASP.NET form to a Windows Form) without changing the controller code. Or the same application can provide multiple views based on the same controller. This is possible because the controller is not dependent on the concrete view but on an interface the view exposes. From this, you can see another testing benefit – the view can be mocked. The same holds true for the dependency on the controller to an interface exposed by the model. Figure 2 shows the MVP pattern in action. Yes, the controller becomes more complex but the tradeoff being simpler testing and more flexibility to application changes makes up for it.

image

         

Figure 2

         

Notice the controller is now called the presenter presumably due to its expanded responsibilities. It is also dependent on interfaces exposed by the view and model rather than concrete implementations. Esposito coins the term “presenter-first development” for this characteristic. This makes the view and model amenable to mocking, facilitating automated testing.

So What of the Model?

By this time, my questions concerning the model have been answered. Yes, the model in enterprise applications is the business logic layer (or a data layer for simpler applications). It is not directly related to presentation. MVP also addresses my other concern about the controller playing a larger role and eliminating the dependency between the view and model. Indeed by abstracting the model through an interface, who cares what the model really does now right? The same holds true for the view.

The View and Data Binding

ASP.NET, WPF, and Windows Forms offers a great data binding infrastructure that makes it easy for the presenter to update the view. The question is should the view contain the data binding code at all? The benefit of MVP is a “dumb” view. Does data binding code make it smarter and does that impact testability. In my opinion, this is a judgment call. Data binding certainly reduces complexity. If you are comfortable with not testing the data binding infrastructure then put the data binding code in the view. However, if you feel the need to put data binding logic in the presenter, then put the code in the presenter. Fowler calls these MVP variations Supervising Controller and Passive View respectively. In the case where you need to have complex logic that data binding doesn’t provide, then my opinion is to put that code in the controller where it can be tested.

Presentation Model

Presentation Model is a variant of MVP. It is used in WPF and Silverlight applications. The model in this pattern plays a key role. The model is not the business logic or data layer as it is in MVP. Rather, it contains the state of the view. It is through the model that the view is updated. The view in Presentation Model is “dumb.” It only contains logic to render the controls. The controls’ properties are bound to properties on the model. Figure 3 shows Presentation Model in action. Note that the view and model data binding is bidirectional which WPF supports.

image

         

Figure 3

         

Conclusion

Esposito and Fowler really clarified MVC for me. The driver for the original MVC pattern was separation of concerns. As applications became more complex, MVP was devised to address testability concerns. Presentation Model is a further refinement that incorporates bidirectional data binding which facilitates testing and reduces some of the complexity of implementing a supervising controller. My key takeaway is that as long as the solution you’ve come up with meets the customer’s requirements and is testable, what patterns you use or don’t use is not important.

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 3

Introduction

Part 1 outlined the load testing process and setup the database and application to load test. Part 2 described how to create Web performance tests. Part 3 will explain how to create the load tests. The load tests simply run the Web performance tests created in Part 2.

Create the Load Tests

There will be one load test for each Web performance test for a total of five load tests that are added to the test project. As you will see, there are a lot of knobs you can potentially turn in a load test. However, to keep things simple, we will accept defaults for most of the choices. To create a load test, begin by right-clicking the test project and selecting Add Load Test. This launches a wizard. Click Next on the Welcome screen. Enter a name for the load test scenario as shown in Figure 1 and click Next .

Figure 1

Figure 1

In the next screen, you configure the load test pattern. The load test pattern represents the number of users to simulate and whether a constant load or step load is desired. In this case, we will choose a gradually increasing step load as shown in Figure 2.
This configuration makes the load test start with 20 simulated users. Every 60 seconds, 20 more users will be added until 100 users are reached.

Figure 2

Figure 2

Click Next twice and you’re brought to the Add tests screen. This is where you add the Web performance tests created in Part 2. Click Add and select one web performance test and click OK. Remember we are adding only one Web performance test per load test. Once the Web performance test has been added, click Next three times to get to the performance monitor screen. Click Add Computer, enter the name of the machine to monitor and hit Enter. Performance counter categories will be populated under the machine name. For this example, only select the ASP.NET and IIS categories as shown in Figure 3. While the load test runs, performance counter samples will be taken and written to a local SQL Server database.

Figure 3

Figure 3

Click Next and you are on the load test run settings screen. This is where you set the load test duration as well as the performance counter sampling frequency. Configure the load test run duration to six minutes as shown in Figure 4.

Figure 4

Figure 4

Click Finish and the load test is added to the test project. Repeat these steps for each of the five Web performance tests. The end result is that you should have a Web performance test and load test for each of the five scenarios we’re testing as shown in Figure 5. The load test files were renamed after creation.

Figure 5

Figure 5

Run the Load Tests

To run a load test, open a load test by double clicking it in Solution Explorer. Then right-click the test name and select Run load test. At this point you will see four graphs similar to Figure 6. At this point you can add and remove counters. You can change the number of grids displayed by clicking the grid icon in the toolbar.

Figure 6

Figure 6

When the load test finishes, a summary report opens displaying useful data such as average page time and pages per second.

Run the remaining load tests. Once all the load tests are run, we can analyze and compare the results.

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 4

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 2

Introduction

Part 1 outlined the load testing process and setup the database and application to load test. Part 2 will describe how to create Web performance tests. A Web performance test simply records the browsing of a website for replay later. Once the Web Performance tests are created, they can be run by a Visual Studio load lest.

Create the Web Performance Tests

There will be one Web performance test for each of the five scenarios listed in Part 1. Each test simply browses to a single web page and displays the customer sales data in a GridView. The details of the request are saved by the web performance test for subsequent replay by the load test. Before creating a Web performance test, make sure the Microsoft Web Test Recorder 10.0 & Microsoft Web Test Recorder Helper add-ons are enabled in Internet Explorer. Once this is done, right-click an ASPX page in the Web project and select View in Browser. Copy the URL. Now right-click the test project and select Add > Web Performance Test. This opens up Internet Explorer with the Web Test Recorder console. Paste the URL you copied earlier and hit enter. Once the GridView is rendered, click Stop in the Web Test Recorder console to stop the recording. This brings you back to Visual Studio and the Web performance test is opened – the document with the .webtest extension. At this point you can close the document and notice it has been added to the test project. Repeat this step for each of the five scenarios, that is, enter the five URL’s in five different Web Test Recorder sessions. The end result is that you should have five web tests as shown in Figure 1. Don’t worry about the files with the .loadtest extension. Those will be created later. Also, the web test files were renamed after creation.

Figure1

Figure 1

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 3

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 1

Introduction

Visual Studio 2012 Ultimate lets you load test you web application (or any code for that matter) within Visual Studio, see the results as the test runs, and export to Excel for further reporting and analysis. Since it is so easy, there shouldn’t be any excuse for load testing your web apps. As we shall see, the load tests are highly configurable. One can configure a load test to use a mix of browsers, network types, among other things. However, we won’t be doing anything that fancy in this series. To get an introduction to load testing, I will demonstrate the responsiveness of an ASP.NET web application that access data using the following methods:

  1. Scenario 1: Synchronous page using synchronous ADO.NET methods
  2. Scenario 2: Synchronous page using the thread pool that uses asynchronous ADO.NET methods
  3. Scenario 3: Synchronous page using the thread pool that uses synchronous ADO.NET methods
  4. Scenario 4: Synchronous page using asynchronous ADO.NET methods
  5. Scenario 5: Asynchronous page using asynchronous ADO.NET methods

You probably already know that the last method is the one that scales best but it is neat to see it for yourself with a load test. It’s just as eye-opening to see how bad the first three methods are.

The Test Environment

The test environment consists of the following applications:

  1. Windows 8 Enterprise 64-bit
  2. Visual Studio 2012 Ultimate
  3. ASP.NET 4.5
  4. SQL Server 2012 Service Pack 1 64-bit

The above software is installed on my laptop which is also where the load tests will be run. The machine specs are as follows:

  1. Processor: Intel(R) Core(TM) i7-3740QM CPU, 2.70GHz, 4 Core(s), 8 Logical Processors
  2. Memory: 16GB
  3. Hard disk: 256GB SanDisk Extreme solid state drive

I’d like to stress that Visual Studio, the ASP.NET website, and SQL Server are all running on my laptop.

The Process

Creating a load test that allows us to test the five scenarios entails the following process:

  1. Create the database.
  2. Create the data access component which will be a C# Class Library project.
  3. Create the ASP.NET web application. There will be a page for each scenario listed above. Each page contains a single GridView control that is bound to the data returned by the data access component.
  4. Create a unit test project.
  5. Create a Web performance test. Since I will have a separate web page for each scenario, I will eventually create five Web performance tests.
  6. Create a load test.
  7. Configure the load test. Since I have five scenarios to test, I will create five load tests with each load test running one of the web performance tests. This is not a requirement because you can add as many web performance tests as you want. However, to keep things simple, I will add only one web performance test per load test.
  8. Run the load test

You can watch a two-minute video demonstrating the load testing feature of Visual Studio 2012 Ultimate. I will be demonstrating the same thing in this series with respect to the four data access scenarios shown above. Additionally, I will delve into the analysis of the load tests which the video does not cover.

The Database

I used the DBGen utility which you can download from The Transaction Processing Performance Council (TPC). This utility writes test data to text files which can be imported into SQL Server using bcp or SSIS. The T-SQL script to create the database and an SSIS package that can be used to import the file data can be found here. Alternatively you can download a SQL Server 2012 backup of the database used in this series here.

The Data Access Component

Listing 1a shows the code for the simple data access component used in this series. Add this class to a C# Library project.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
using System.Threading;

namespace LoadTestDemo
{
	public sealed class SimpleDataAccessComponent
	{
		private readonly string connectionString;
		
		private readonly string customerSalesQuery = @"SELECT TOP 25 c.CUSTKEY AS CustomerKey,
													   c.NAME AS CustomerName,
													   SUM(o.TOTALPRICE) AS TotalSales
												FROM dbo.CUSTOMER AS c
												INNER JOIN dbo.ORDERS AS o
												ON c.CUSTKEY = o.CUSTKEY
												INNER JOIN dbo.NATION AS n
												ON c.NATIONKEY = n.NATIONKEY
												WHERE n.NAME = N'UNITED STATES'
												GROUP BY c.CUSTKEY, c.NAME
												ORDER BY SUM(o.TOTALPRICE) DESC OPTION (MAXDOP 1);";

		private List<CustomerSales> customerSalesList = new List<CustomerSales>();
		private readonly Action<SqlDataReader> dataReaderAction;

		public SimpleDataAccessComponent(
			string connectionString
			)
		{
			if (string.IsNullOrEmpty(connectionString) != false)
			{
				throw new ArgumentNullException(
					"connectionString",
					"Parameter cannot be null or empty."
					);
			}

			this.connectionString = connectionString;

			this.dataReaderAction = new Action<SqlDataReader>(
			_reader =>
				{
					while (_reader.Read() != false)
					{
						CustomerSales customerSales = new CustomerSales(
							(int)_reader["CustomerKey"],
							(string)_reader["CustomerName"],
							(decimal)_reader["TotalSales"]
							);

						this.customerSalesList.Add(
							customerSales
							);
					}
				}
			);

		}

		public IList<CustomerSales> GetCustomerSalesSync()
		{
			this.ExecuteReaderSync(
				this.customerSalesQuery,
				this.dataReaderAction
				);

			return customerSalesList;
		}

		public IList<CustomerSales> GetCustomerSalesAsync()
		{
			this.ExecuteReaderAsync(
				this.customerSalesQuery,
				this.dataReaderAction
				);

			return customerSalesList;
		}


		public IList<CustomerSales> GetCustomerSalesThreadPool(
			bool asyncDataRetrieval
			)
		{
			if (asyncDataRetrieval == false)
			{
				this.ExecuteReaderThreadPool(
					this.customerSalesQuery,
					this.dataReaderAction
					);
			}
			else
			{
				this.ExecuteReaderThreadPool(
					this.customerSalesQuery,
					this.dataReaderAction,
					true
					);
			}

			return customerSalesList;
		}

		#region Private helper data access methods

		private void ExecuteReaderSync(
			string query,
			Action<SqlDataReader> action
			)
		{
			Debug.Assert(
				string.IsNullOrEmpty(query) == false
				);

			Debug.Assert(
				action != null
				);

			SqlConnection connection = null;
			SqlCommand command = null;

			try
			{
				connection = new SqlConnection(
					this.connectionString
					);

				command = new SqlCommand(
					query,
					connection
					);

				connection.Open();
				SqlDataReader reader = command.ExecuteReader();

				action(
					reader
					);
			}
			finally
			{
				if (command != null)
				{
					command.Dispose();
				}

				if (connection != null)
				{
					connection.Close();
				}
			}
		}

		private void ExecuteReaderAsync(
			string query,
			Action<SqlDataReader> action
			)
		{
			Debug.Assert(
				string.IsNullOrEmpty(query) == false
				);

			Debug.Assert(
				action != null
				);

			SqlConnection connection = null;
			SqlCommand command = null;

			try
			{
				connection = new SqlConnection(
					this.connectionString
					);

				command = new SqlCommand(
					query,
					connection
					);

				connection.Open();

				//This event is signaled when the dataReaderAction delegate returns.
				ManualResetEvent queryProcessedEvent = null;

				try
				{
					queryProcessedEvent = new ManualResetEvent(
						false
						);

					command.BeginExecuteReader(
							_ar =>
							{
								SqlDataReader _reader = command.EndExecuteReader(_ar);

								action(
									_reader
									);

								//Signal the event indicating the dataReaderAction delegate has completed.
								queryProcessedEvent.Set();

							},
						command,
						CommandBehavior.SequentialAccess
						);

					//Wait for the dataReaderAction delegate to complete.
					queryProcessedEvent.WaitOne();
				}
				finally
				{
					if (queryProcessedEvent != null)
					{
						queryProcessedEvent.Close();
					}
				}
			}
			finally
			{
				if (command != null)
				{
					command.Dispose();
				}

				if (connection != null)
				{
					connection.Close();
				}
			}
		}

	   private void ExecuteReaderThreadPool(
			string query,
			Action<SqlDataReader> action
		   )
		{
			Debug.Assert(
				 string.IsNullOrEmpty(query) == false
				 );

			Debug.Assert(
				action != null
				);

			this.ExecuteReaderThreadPool(
				query,
				action,
				false
				);
		}

		private void ExecuteReaderThreadPool(
			string query,
			Action<SqlDataReader> action,
			bool asyncDataOperation
			)
		{
			Debug.Assert(
				string.IsNullOrEmpty(query) == false
				);

			Debug.Assert(
				action != null
				);

			SqlConnection connection = null;
			SqlCommand command = null;

			try
			{
				connection = new SqlConnection(
					this.connectionString
					);

				command = new SqlCommand(
					query,
					connection
					);

				connection.Open();

				//This event is signaled when the dataReaderAction delegate returns.
				ManualResetEvent queryProcessedEvent = null;

				try
				{
					queryProcessedEvent = new ManualResetEvent(
						false
						);

					WaitCallback waitCallback = new WaitCallback(
						_object =>
						{
							Action<SqlDataReader> _action = (Action<SqlDataReader>)_object;

							if (asyncDataOperation != false)
							{
								this.ExecuteReaderAsync(
									query,
									_action
									);
							}
							else
							{
								this.ExecuteReaderSync(
									query,
									_action
									);
							}

							//Signal the event indicating the dataReaderAction delegate has completed.
							queryProcessedEvent.Set();
						}
					  );

					ThreadPool.QueueUserWorkItem(
						waitCallback,
						action
						);

					//Wait for the dataReaderAction delegate to complete.
					queryProcessedEvent.WaitOne();
				}
				finally
				{
					if (queryProcessedEvent != null)
					{
						queryProcessedEvent.Close();
					}
				}
			}
			finally
			{
				if (command != null)
				{
					command.Dispose();
				}

				if (connection != null)
				{
					connection.Close();
				}
			}
		}
		#endregion
	}
}

Listing 1a

Listing 1b shows the code for the business object used in this series. Collections of the CutomerSales type are returned by the data access components.


using System;

namespace LoadTestDemo
{
    [Serializable]
    public sealed class CustomerSales
    {
        private int customerKey;
        private string customerName;
        private decimal totalSales;

        public int CustomerKey
        {
            get
            {
                return this.customerKey;
            }
        }

        public string CustomerName
        {
            get
            {
                return this.customerName;
            }
        }

        public decimal TotalSales
        {
            get
            {
                return this.totalSales;
            }
        }

        public CustomerSales(
            int customerKey,
            string customerName,
            decimal totalSales
            )
        {
            if (customerKey < 1)
            {
                throw new ArgumentOutOfRangeException(
                    "customerKey",
                    customerKey,
                    "Value must be a positive integer."
                    );
            }

            if (string.IsNullOrEmpty(customerName) != false)
            {
                throw new ArgumentNullException(
                    "customerName",
                    "Parameter cannot be null or empty."
                    );
            }

            if (totalSales < 0)
            {
                throw new ArgumentOutOfRangeException(
                    "totalSales",
                    totalSales,
                    "Value must be zero or greater."
                    );
            }

            this.customerKey = customerKey;
            this.customerName = customerName;
            this.totalSales = totalSales;
        }
    }
}

Listing 1b

The ASP.NET Web Application

A single ASP.NET Web application will house the five ASP.NET pages corresponding to each data access scenario. Add five web forms to an ASP.NET Empty Web project. Name them Scenario1.aspx, Scenario2.aspx, and so forth. Simply add a single GridView control to each Web form as shown in Listing 2.

<asp:GridView ID="gridResults" runat="server" />

Listing 2

Also add a two connection strings to the web.config file as shown in Listing 3. One connection string is used for asynchronous data access and the other for synchronous data access. Do not change the names of the connection strings as they are referenced in code using these names.

<configuration>
    <system.web>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
    </system.web>
  <connectionStrings>
    <add name="CompanyDbAsync" connectionString="Data Source=.;Initial Catalog=Company;Integrated Security=True;Asynchronous Processing=true"/>
    <add name="CompanyDbSync" connectionString="Data Source=.;Initial Catalog=Company;Integrated Security=True"/>
  </connectionStrings>
</configuration>

Listing 3

The Code Behind

The code for each form is simple – query the database and bind the data to the GridView control. All the code is placed in the Page’s Load method. Listings 4-8 show the code behind for the forms corresponding to scenarios 1-5 respectively.

Code for Scenario 1: Synchronous page using synchronous ADO.NET methods

Listing 4 shows the code that synchronously executes the query and binds the result to the GridView.

using System;
using System.Web.Configuration;

namespace LoadTestDemo
{
	public partial class SyncPageSyncDataAccess : System.Web.UI.Page
	{
		protected void Page_Load(object sender, EventArgs e)
		{
			string connectionString = WebConfigurationManager.ConnectionStrings["CompanyDbSync"].ConnectionString;

			SimpleDataAccessComponent c = new SimpleDataAccessComponent(
				connectionString
				);

			this.gridResults.DataSource = c.GetCustomerSalesSync();
			this.gridResults.DataBind();
		}
	}
}

Listing 4

Scenario 2: Synchronous Page Using the Thread Pool That Uses Asynchronous ADO.NET Methods

Listing 5 shows the code that uses a thread pool thread to execute an asynchronous ADO.NET method and binds the result to the GridView.

using System;
using System.Web.Configuration;

namespace LoadTestDemo
{
    public partial class ThreadPoolAsyncDataAccess : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string connectionString = WebConfigurationManager.ConnectionStrings["CompanyDbAsync"].ConnectionString;

            SimpleDataAccessComponent c = new SimpleDataAccessComponent(
                connectionString
                );

            this.gridResults.DataSource = c.GetCustomerSalesThreadPool(
                true
                );

            this.gridResults.DataBind();
        }
    }
}

Listing 5

Scenario 3: Synchronous Page Using the Thread Pool That Uses Synchronous ADO.NET methods

Listing 6 shows the code that uses a thread pool thread to execute a synchronous ADO.NET method and binds the result to the GridView.

using System;
using System.Web.Configuration;

namespace LoadTestDemo
{
	public partial class ThreadPoolSyncDataAccess : System.Web.UI.Page
	{
		protected void Page_Load(object sender, EventArgs e)
		{
			string connectionString = WebConfigurationManager.ConnectionStrings["CompanyDbSync"].ConnectionString;

			SimpleDataAccessComponent c = new SimpleDataAccessComponent(
				connectionString
				);

			this.gridResults.DataSource = c.GetCustomerSalesThreadPool(
				false
				);

			this.gridResults.DataBind();
		}
	}
}

Listing 6

Scenario 4: Synchronous Page Using Asynchronous ADO.NET Methods

Listing 7 shows the code that uses an asynchronous ADO.NET method and binds the result to the GridView.

using System;
using System.Web.Configuration;

namespace LoadTestDemo
{
	public partial class SyncPageAsyncDataAccess : System.Web.UI.Page
	{
		protected void Page_Load(
			object sender, 
			EventArgs e
			)
		{
			string connectionString = WebConfigurationManager.ConnectionStrings["CompanyDbAsync"].ConnectionString;

			SimpleDataAccessComponent c = new SimpleDataAccessComponent(
				connectionString
				);

			this.gridResults.DataSource = c.GetCustomerSalesAsync();
			this.gridResults.DataBind();
		}
	}
}

Listing 7

Scenario 5: Asynchronous Page Using Asynchronous ADO.NET Methods

Listing 8 shows the code that uses an asynchronous ADO.NET method and binds the result to the GridView.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web;
using System.Web.Configuration;

namespace LoadTestDemo
{
	public partial class AsyncPage : System.Web.UI.Page
	{
		List<CustomerSales> customerSalesList;

		protected void Page_Load(object sender, EventArgs e)
		{
			SimpleDataAccessComponent c = new SimpleDataAccessComponent(
				WebConfigurationManager.ConnectionStrings["CompanyDbAsync"].ConnectionString
				);

			BeginEventHandler beginHandler = new BeginEventHandler(
				 (_sender, _eventArgs, _callback, _extraData) =>
				 {
					 Task<IList<CustomerSales>> task = null;

					 try
					 {
						 task = new Task<IList<CustomerSales>>(
										() =>
										{
											return c.GetCustomerSalesAsync();
										}
										);

						 task.Start();
						 _callback(task as IAsyncResult);
						 return task as IAsyncResult;
					 }
					 finally
					 {
						 if (task != null)
						 {
							 if (task.Status == TaskStatus.RanToCompletion ||
									 task.Status == TaskStatus.Faulted ||
									 task.Status == TaskStatus.Canceled
								 )
							 {
								 task.Dispose();
							 }
						 }
					 }
				 }
				);

			EndEventHandler endHandler = new EndEventHandler(
				(_asyncResult) =>
					{
						Task<IList<CustomerSales>> task = null;

						try
						{
							task = (Task<IList<CustomerSales>>)_asyncResult;
							task.Wait();
							this.customerSalesList = task.Result as List<CustomerSales>;
						}
						finally
						{
							if (task != null)
							{
								if (task.Status == TaskStatus.RanToCompletion || 
										task.Status == TaskStatus.Faulted || 
										task.Status == TaskStatus.Canceled
									)
								{
									task.Dispose();
								}
							}
						}

					}
				);

		   this.Page.AddOnPreRenderCompleteAsync(
			   beginHandler,
			   endHandler
			   );
		}

		protected override void OnPreRenderComplete(
			EventArgs e
			)
		{

			this.gridResults.DataSource = this.customerSalesList;
			this.gridResults.DataBind();
			base.OnPreRenderComplete(e);
		}
	}
}

Listing 8

The Test Project

Add a Test project which will contain the web performance and load tests.

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 2

Load Testing Web Apps With Visual Studio 2012 Ultimate – Part 4

Introduction

Part 1 outlined the load testing process and setup the database and application to load test. Part 2 described how to create Web performance tests. Part 3 explained how to create the load tests. In Part 4, we will analyze the five load test reports to determine which data access method is best.

To open a load test’s result, first double-click the load test file in Solution Explorer. Then click the Open and Manage Results icon in the toolbar (Figure 1). Select the test result and click Open (Figure 2).

Figure 1

Figure 1

Figure 2

Figure 2

We will analyze and compare the following counters for each load test,

  1. User Load
  2. Pages/sec
  3. Avg. Page Time
  4. % Processor Time

For easier viewing, switch to one graph by clicking the Four panels grid icon in the toolbar and selecting One panel (Figure 3). Then select Key Indicators in the drop down list above the graph (Figure 4). Finally, add the above counters if not already added.

Figure 3

Figure 3

Figure 4

Figure 4

Scenario 1: Synchronous page using synchronous ADO.NET methods

Figure 5 shows the load test graph for the first scenario. The scenario under test was browsing to a synchronous page that accesses data using synchronous ADO.NET methods.

Figure 5

Figure 5

Notice the trend in pages/sec matches the user load. This makes sense because the I/O and CPU load are more or less growing in proportion to the number of users since the same query is being executed and a single cached plan is being reused. The pages per second served up are very consistent between 10.8 and 12 pages per second. The CPU’s remain pegged at or close to 100% for the duration of the test. The query coupled with the load has exposed a CPU bottleneck on my laptop.

Scenario 2: Synchronous page using the thread pool that uses asynchronous ADO.NET methods

Figure 6 shows the load test graph for the second scenario. The scenario under test was browsing to a synchronous page that accesses data using a thread pool thread that runs asynchronous ADO.NET methods.

Figure 6

Figure 6

As in the first scenario, average page time increases with user load. However, the times are much more erratic. The number of pages serves are higher than the first scenario – an average of about 10 pages per second with a max of 18.8 pages per second. There is more variance in this counter as well. Processor utilization is lower than the first scenario.

Scenario 3: Synchronous page using the thread pool that uses synchronous ADO.NET methods

Figure 7 shows the load test graph for the third scenario. The scenario under test was browsing to a synchronous page that accesses data using a thread pool thread that runs synchronous ADO.NET methods.

Figure 7

Figure 7

The first thing to notice here is that the average page time increases much more per additional user as compared to the first scenario. The pages per second served are lower as compared to the first scenario and more variable. This makes sense because these threads are competing with IIS threads for CPU time. This is in sync with the guidance that the thread pool should not be used from within ASP.NET pages. Also notice the processor utilization is a lot lower than the first scenario.

Scenario 4: Synchronous page using asynchronous ADO.NET methods

Figure 8 shows the load test graph for the fourth scenario. The scenario under test was browsing to a synchronous page that accesses data using asynchronous ADO.NET methods.

Figure 8

Figure 8

Like the first scenario, the page time increases in almost lock step with the user load. The number of pages served up per second is more variable than the first scenario but the range is higher – an average of 11.4 pages per second with a maximum of 19.2 pages per second. The processor are fully utilized for the duration of the test.

Scenario 5: Asynchronous page using asynchronous ADO.NET methods

Figure 9 shows the load test graph for the fifth scenario. The scenario under test was browsing to a asynchronous page that accesses data using asynchronous ADO.NET methods.

Figure 9

Figure 9

Like the first scenario, the page time increases in almost lock step with the user load although there is more variance when there are 100 users. The number of pages served up per second is more variable than the first scenario but the range is higher – an average of 11.2 pages per second with a maximum of 19.6 pages per second. This range is similar to the range in the fourth scenario. In fact the performance as a whole is similar to the fourth scenario.

Box Plots

A box plot can help us see more clearly the performance of each of the scenarios. Figures 10 and 11 show box plots for the pages per second and average page time counters with 100 users. Notice the variance in the asynchronous scenarios (excluding the one using the thread pool) in the first, second, and last boxes. However notice that the upper limit for the async scenarios is also higher. There is little variance in the synchronous scenarios (third and fourth box) however the upper limit is a lot less. The thread pool using synchronous ADO.NET is definitely the worst when it comes to pages per second.

Figure 10

Figure 10

Figure 11

Figure 11

Regarding page time, the asynchronous methods have the lowest values, but they are also highly variable. There is very little variance with the synchronous method that doesn’t use the thread pool but the minimum time is noticeably higher than the asynchronous methods. The thread pool using synchronous ADO.NET is definitely the worst when it comes to page time.

Conclusion

Visual Studio 2012 Ultimate gives us an easy way to load test web sites. The testing done in this series provide empirical evidence for choosing asynchronous data access methods over synchronous data access methods. There is also support for avoiding the explicit use of the thread pool. The use of asynchronous pages over synchronous pages is also supported but the performance difference is a lot closer than one might think, at least this is what my testing showed. As always with performance testing, your mileage may vary :).