You are on page 1of 11

Background threads in ASP.

net
November 24, 2014– the concept application
When debugging memory dumps from customers, I have come to see, quite often, a pattern that
you should not use in your application if you don't want to run into trouble. This pattern can be
resumed in a simple rule: thou shall not create thy own threads in thy application! To show
you what I mean, through a series of three blog articles I will create a simple application and show
you what happens when we transgress this rule.
Let's build a simple stock quote lookup application. I am basing my sample on a sample I found
earlier and bookmarked withwww.linqto.me under this url: http://linqto.me/StockAPI . Since the API
in question is now defunct, and I wanted to provide a working app, I have performed some major
changes, including using the Yahoo API instead of the Google one. You can download the
completed solution from my OneDrive here:
Background Threading Sample Applications
When you start the solution, you should see a page that allows you to input a stock symbol and get
a quote. Here is the page loaded in Internet Explorer and showing the price for the MSFT stock
symbol:

So how does this work? The page has a textbox called txtSymbol and a button which, when
pressed, will submit the page and run some code behind to lookup the symbol in the Yahoo API.
The code behind has a click event associated to the button, which looks like this:

protected void cmdSubmit_Click(object sender, EventArgs e)


{
//check if there is a symbol in the textbox
if (!String.IsNullOrWhiteSpace(txtSymbol.Text.Trim()))
{
//get a quote from Yahoo:
FetchQuote(txtSymbol.Text.Trim());
//show the panel and set the labels
pnlResults.Visible = true;
lblCompany.Text = company;
lblPrice.Text = price.ToString();
lblSymbol.Text = symbolName;
lblVolume.Text = volume.ToString();
}
}

If the textbox is not empty (I am not doing fancy error checking to keep this simple), the code will
call a method called FetchQuote(System.String) to which it will pass the value of the textbox. Here
is the code for this second method:

private void FetchQuote(string symbol)


{
string url = "http://finance.yahoo.com/webservice/v1/symbols/" + Server.UrlEncode(symbol)
+"/quote";
//load the xml document
XDocument doc = XDocument.Load(url);
//extract the data
company = GetData(doc, "name");
price = Convert.ToDouble(GetData(doc, "price"));
symbolName = GetData(doc, "symbol");
volume = Convert.ToInt32(GetData(doc, "volume"));
}

The method will compose the Yahoo Stock API url with the stock symbol we want to look up. It will
down the XML document containing the quote data from Yahoo. Such a document will look
something like this for the MSFT (Microsoft) stock symbol

<list version="1.0">
<meta>
<type>resource-list</type>
</meta>
<resources start="0" count="1">
<resource classname="Quote">
<field name="name">Microsoft Corporation</field>
<field name="price">47.980000</field>
<field name="symbol">MSFT</field>
<field name="ts">1416603605</field>
<field name="type">equity</field>
<field name="utctime">2014-11-21T21:00:05+0000</field>
<field name="volume">42887245</field>
</resource>
</resources>
</list>

Once the document is loaded into an XDocument object, we will parse the object to extract the
data we need to show on the page. This is done by repeated calls to a method called
GetData(System.Xml.LINQ.XDocument, System.String). Here is the code:

private string GetData(XDocument doc, string name)


{
//get the requested attribute value from the XDocument
return doc.Root.Element("resources").Element("resource").Elements().Where(n =>
n.FirstAttribute.Value == name).First().Value;
}

I will not go into the details of this implementation, suffice to say that it will attempt to get a hold of
an XML element that has an attribute called name with the 'value' indicated by the String parameter
passed in. It will just return the value of the XML element which is the quote data we are interested
in.
Back to the FetchQuote method, which will load the retrieved data into local page variables.
Following this, it will return control to the caller, the Click event handler of the button. This will
display a Panel control and transfer the values of the page level variables to label controls on the
page to display the data.
In the next installment, I will be modifying the application to load the data for stock symbols in the
background, periodically, so that we do not lose time to load the data from Yahoo every time
someone asks for a quote from the application. This will be done via background threads, the kind
of pattern you should not be using. The implementation of this concept is detiled in the second
blog post.
November 25, 2014 - thread implementation
To continue the saga of developing ASP.net applications that make use of background threads, we
will look at how to 'optimize' the application that I have proposed in the first article. The objective
would be to have the application load the data in the background via a thread that would update
the price of certain stock symbols every X seconds.
To do this, what I have seen many of my customer's do, is to spawn a new .Net thread in the
background and have this thread run an infinite loop with the following pseudo-logic:
1. When the application loads up, start the background thread and have it execute the infinite loop
2. Once in the infinite loop, the thread will update the price for the symbols in the list
3. When it has retrieved the information for the price of the symbols, it will sleep for a given
amount of time
4. It will then resume the loop from the beginning and attempt to refresh the prices again.
So let's look how this pseudo logic can be transformed into code. Keep in mind that I am doing the
bare minimum to keep the application as simple as possible and focus on the essentials.
I will first start by declaring a POCO (short for Plain Old CRL Object) class that will represent a
stock quote. Here is the code listing:

//base libraries
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
//added imports
namespace NotPatterns
{
public class StockQuote
{
//class properties
public string CompanyName { get; set; }
public string SymbolName { get; set; }
public double Price { get; set; }
public int Volume { get; set; }
public DateTime LastUpdate { get; set; }
}
}
This class only contains a couple of properties that expose both get and set so that we can store
the data related to a stock quote inside an instance of the class. This will represent our Business
Layer (Model).
When the application loads into the process memory (into the w3wp.exe worker process), the
Application_Start event is fired. This seems like a good place to add the code to create a
background thread.
The first method I will implement is located in the Global.asax file (but I could have implemented
this inside another class if I had wanted to as well). This method is called UpdateQuotes. Here is
the code listing:

private void UpdateQoutes()


{
//declare an array of strings to contain the stock
string[] stockSymbols = { "MSFT", "AAPL", "GOOG", "AMZN" };
string url = "http://finance.yahoo.com/webservice/v1/symbols/";
string stockUrl; StockQuote quote; XDocument xdoc;
do
{
//go through each of the symbols and run them
foreach (String stockSymbol in stockSymbols)
{
stockUrl = url + Server.UrlEncode(stockSymbol) + "/quote";
xdoc = XDocument.Load(stockUrl);
//create a new qoute
quote = new StockQuote();
quote.CompanyName = GetData(xdoc, "name");
quote.Price = Convert.ToDouble(GetData(xdoc, "price"));
quote.Volume = Convert.ToInt32(GetData(xdoc, "volume"));
quote.SymbolName = GetData(xdoc, "symbol");
quote.LastUpdate = DateTime.Now;
//save the symbol
Application[stockSymbol] = quote;
}
//sleep for 100 Seconds
System.Threading.Thread.Sleep(100000);
} while (true);
}
What the method does is that it will declare an array of four stock symbols (just to keep it simple –
we could use something more dynamic afterwards) that will be updated every X seconds.
Following this declaration, it will go into an infinite loop, represented by the do{} while(true)
statement.
Each of the symbols in the array will be inspected, and we will try to obtain the current price for the
symbol, by making a call to the Yahoo Finance API using the XDocument object. For each symbol
we compose the correct URL and then we ask the XDocument object to retrieve the XML datagram
corresponding to the stock quote.
Once we have loaded the XML inside the XDocument object, the method will create a new
instance of the StockQuote class and populate its properties with data extracted from the XML –
via the GetData(System.Xml.Linq.XDocument, System.String) method, just like in the previous
sample. The newly created instance of StockQuote will be added to the Application object, an
object that is available in all parts of the application and that can be thought of as a global
dictionary of variables. (Some of you might remark that I could have checked if I already had an
entry for the symbol in question inside the Application object and if so, I could just have performed
an update on the object instead of creating a new instance every time, and you would be right to do
so. However, in essence I am trying to keep the app basic, and not necessarily optimized).
Following the loading of the financial data for all symbols, the loop will put the thread to sleep 100
seconds (1minute 40 seconds). After this, the loop will be executed again and again, until the end
of time, or the end of the process, whichever comes first.
Now for the interface to display these four stock symbols in a web-page. To do this, I have created
a second page for the application, called AutoStock.aspx. This page contains a repeater control
that is strongly–typed data-bound to an object of type StockQuote, via the ItemType property. If
you are new to strongly typed data-binding, I would suggest you have a look at my ASP.net 4.5
Webforms video tutorial:
http://linqto.me/n/ASPNet45
Here are the tags for the repeater control – note the ItemType tag that indicates the type of object
that will be displayed by the control and the SelectMethod tag which indicates which method in the
code behind which will be called to load the elements to display when the control is loaded:

<asp:Repeater ID="rptStocks" runat="server" ItemType="NotPatterns.StockQuote" SelectMethod="


GetQuotes">
<ItemTemplate>
<div style="float:left">
<fieldset>
<legend><%# Item.SymbolName %></legend>
Company Name: <%# Item.CompanyName %>
<br />
<br />
Price: <%# Item.Price %> $
<br />
<br />
Volume: <%# Item.Volume %> shares
<br />
<br />
Last Updated: <%# Item.LastUpdate.ToLongTimeString() %>
</fieldset>
</div>
</ItemTemplate>
</asp:Repeater>

Inside the repeater control, we just display a fieldset tag for each stock quote, and inside this we
display, the company name, the price and other information via strongly typed data-binding.
In the code behind, the GetQuotes() method does all the loading of the pricing data from the
Application object – here is the code:

public IEnumerable<NotPatterns.StockQuote> GetQuotes()


{
//get the stocks from the application object
List<NotPatterns.StockQuote> stocks = new List<NotPatterns.StockQuote>();
//load the stocks
if (Application.Count == 4)
{
stocks.Add((NotPatterns.StockQuote)Application["MSFT"]);
stocks.Add((NotPatterns.StockQuote)Application["AAPL"]);
stocks.Add((NotPatterns.StockQuote)Application["GOOG"]);
stocks.Add((NotPatterns.StockQuote)Application["AMZN"]);
}
return stocks;
}

The method declares a variable of type List<StockQuote> and attempts to add the stock quotes
from the Application object to the newly created list. We check if the count of items in the
Application object is equal to 4, since we only have four items in the stock array defined in the
Global.asax. Should the background thread not have finished loading the prices for the first time
before we show the page, we don't want to show null data and crash the page, hence the reason
for the test. It ensures that the data was loaded by the background thread at least once.
There is also a refresh button on the page, witch a Click event handler in the code behind:

protected void cmdRefresh_Click(object sender, EventArgs e)


{
//force the rebinding
rptStocks.DataBind();
}

All this does is that it forces the repeater control to data-bind once again – and hence to call the
GetQuotes() method and reload the data from the Application object. Note that the data will not be
reloaded by the background thread when this new call to GetQuotes() comes in. It will be refreshed
only when the background thread wakes up the next time around and loads new data from Yahoo.
You can find the sample completed with this new code in my OneDrive as well, by following this
link:
https://onedrive.live.com/?cid=9A83CB6EACC8118C&id=9A83CB6EACC8118C%21131
In the next installment, I will discuss the problems with this kind of pattern and why it is not
recommended you make use of it in your ASP.net applications.

December 16, 2014 - threading side effects


In the final article of the series on the dangers of ASP.net background threading, to illustrate the
dangers of such an architecture, I will start by introducing one more modification to the code of the
sample application. This modification will be added to the code of the Global.asax that starts off the
infinite loop thread that runs outside of the ASP.net thread pool. Here is the listing again, but notice
the lines of code that have been added:

private void UpdateQoutes()


{
//declare an array of strings to contain the stock
string[] stockSymbols = { "MSFT", "AAPL", "GOOG", "AMZN" };
string url = "http://finance.yahoo.com/webservice/v1/symbols/";
string stockUrl; StockQuote quote; XDocument xdoc; int loopIteration = 1;
do
{
//should we have a loop iteration that yields modulo 6 = 0, crash
if ((loopIteration % 5) == 0)
{
throw new Exception("Random crash");
}
//go through each of the symbols and run them
foreach (String stockSymbol in stockSymbols)
{
stockUrl = url + Server.UrlEncode(stockSymbol) + "/quote";
xdoc = XDocument.Load(stockUrl);
//create a new qoute
quote = new StockQuote();
quote.CompanyName = GetData(xdoc, "name");
quote.Price = Convert.ToDouble(GetData(xdoc, "price"));
quote.Volume = Convert.ToInt32(GetData(xdoc, "volume"));
quote.SymbolName = GetData(xdoc, "symbol");
quote.LastUpdate = DateTime.Now;
//save the symbol
Application[stockSymbol] = quote;
}
//sleep for 100 Seconds
System.Threading.Thread.Sleep(100000);
//increment the loop iteration
loopIteration = loopIteration + 1;
} while (true);
}

The first thing added is the creation of a private variable called loopIteration which we set to the
value 1. Then inside the do {} while(true) infinite loop, I added a check to see if the result of the
division of the value of the new variable by 5 is not zero – that is to say, each time the value of the
variable is a multiple of 5 (5, 10, 15, etc) the if branch will be taken and an exception will be thrown
by the code. If the if statement is not taken, the value of the variable will be incremented by one at
the end of the loop.
If you attempt to run the sample in IIS, you will see that after a time, the application pool will crash,
and you will get an event 5011 logged by WAS (the Windows Process Activation Service) inside
the System application log:
A process serving application pool 'MvcSample' suffered a fatal communication error with the
Windows Process Activation Service. The process id was '2952'. The data field contains the error
number.
So what just happened?
When request execution happens inside IIS, ASP.net gives you a safety net. Almost all exceptions
(except for a System.OutOfMemoryException, System.StackOverflowException and
System.ExecutionEngineException) are caught by the runtime, if they are not caught by your
application directly. Hence an exception like FileNotFoundException that would occur during a
page execution (request 3 in the picture below) would wind up with a 500 error page being sent to
the connecting user – who would see the ASP.net yellow screen of death, but the w3wp.exe
process hosting the application would not crash. Hence all other threads inside the process could
go on treating requests, and the only impacted person would be the user requesting that particular
page.
For thread that we launched with the Application_Start() event handler, there is no associated
context and the Thread itself is not part of the ASP.net thread pool. Hence, when an exception
occurs, if it is not handled in the application code, it will be handed directly to the operating system
to treat: the way Windows deals with such an exception is by crashing the w3wp.exe process –
and all other threads and requests inside it. This is what happens when the throw statement is
executed in the loop. If you are unlucky enough to send a request exactly when this happens, you
will see a message indicating that "This page cannot be displayed" in your browser.

Another, more subtle danger is application domain unloading and reloading. The application
domain is a data structure that loads the entire code of your ASP.net application inside the
w3wp.exe process. Since we cannot unload .dlls (assemblies) in .Net, when a change is made to
the application on disk – files are changed inside the bin folder, the web.config file is updated, the
entire application domain has to unload and reload with a new copy of your application. You can
read more about this process by following this link:
http://linqto.me/AppDomainUnload
Supposing that the application domain has to be unloaded, but that the thread we launched at the
beginning of the application is still running and holding on to objects in the current instance of the
application domain, the unload cannot complete. Hence, you can wind up with behavior of the
following sort: you perform a change to your application, and you do not see the change when
refreshing the application in the browser. This is because the old app domain cannot unload until
the spawned thread finishes dealing with all the objects it was holding on to inside the old app
domain – and since we are in an infinite loop, this will be never.
Also, when you attempt to recycle the application pool in IIS, you may see warnings from WAS in
the event log indicating that the w3wp.exe process serving the pool took too long to shut down,
and hence was killed. IIS has a mechanism by which, a w3wp.exe process serving an application
pool is allowed 90 seconds to gracefully stop all threads and shut down when a recycle has to
occur. Passed this time period (controlled by the shutdownTimeLimit -
http://www.iis.net/configreference/system.applicationhost/applicationpools/add/processmodel -
parameter in the configuration), WAS will issue a kill process and force shutdown the w3wp.exe
process. In the case of the sample application, the looping thread will never relinquish control and
will not allow the process to shut down even after 90 seconds, so WAS will have to proceed with a
kill.
Conclusion:
It is never a good idea to spawn up background threads in your application. If you need to have
something treated on another thread outside the thread that does request treatment, consider
calling the Threadpool.QueueWorkItem (http://msdn.microsoft.com/en-
us/library/system.threading.threadpool.queueuserworkitem%28v=vs.110%29.aspx ) method call –
this will use a free thread from the ASP.net threadpool to execute the code you give it. Another
possibility is to consider asynchronous execution using the new .Net syntax with async and await. I
will be doing a series on this next year (2015) so stay tuned.

By Paul Cociuba
http://linqto.me/about/pcociuba

You might also like