Sie sind auf Seite 1von 126

DESDE UN FRAME O IFRAME SE PIERDER LOS VALORES DE SESSION O COOKIES

Es posible que al estar dentro de un iframe o frame, al cambiar de pgina, se pierdan los valores de las sessiones o de las cookies con algunos navegadores, por ejemplo, con internet explorer. Para solucionar esto, hay que aadir una lnea, justo antes de hacer el cambio de pgina, un ejemplo: Session("NUM") = TABLA.Tables("ACCESO").Rows(0)("NUM") HttpContext.Current.Response.AddHeader("p3p", "CP=\""IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""") Response.Redirect("Datos.aspx")

Numero de Usuarios en Linea en ASP


Utilizaremos el Global Asa para contabilizar las personas que tenemos online en la web. Utilizaremos una variable de session para almacenar los usuarios online. Cdigo Fuente: sub application_onStart() 'sentencias que se ejecutan al entrar el primer usuario application("numero_usuarios")=0 end sub sub session_onStart() application.lock application("numero_usuarios") = application("numero_usuarios") + 1 application.unlock end sub sub session_onEnd() 'sentencias que se ejecutan cada vez que entra un usuario application.lock application("numero_usuarios") = application("numero_usuarios") - 1 application.unlock end sub Ya tenemos la variable de sesion "numero_usuarios" preparada. En la pgina que queramos mostrar el nmero de usuarios online: response.write application("numero_usuarios")

How to show number of online users / visitors for ASP.NET website?


Posted: 24-Mar-2008 Updated: 8-Apr-2008 Views: 64166

There are many ways to count number of active visitors on your ASP.NET website. They differ in technique and accuracy. here is the simplest approach that delivers acceptable accuracy when configured optimally: Step 1: - first we need to add these lines to our global.asax file (if your website do not have it, create it by right-clicking on website in solution explorer, and choosing Add New Item > Global Application Class option) void Application_Start(object sender, EventArgs e)

{
// Code that runs on application startup Application["OnlineUsers"] = 0;

}
void Session_Start(object sender, EventArgs e)

{
// Code that runs when a new session is started

Application.Lock(); Application["OnlineUsers"] = (int)Application["OnlineUsers"] + 1; Application.UnLock(); }


void Session_End(object sender, EventArgs e)

{
// Code that runs when a session ends. // Note: The Session_End event is raised only when the sessionstate mode // is set to InProc in the Web.config file. If session mode is set to StateServer // or SQLServer, the event is not raised.

Application.Lock(); Application["OnlineUsers"] = (int)Application["OnlineUsers"] - 1; Application.UnLock(); }


This will allow us that whenever some distant web visitor opens our website in his browser, and new session is created for him, our "OnlineUsers" variable in the global HttpApplicationState class instance is increased. Also when user closes his browser or does not click on any links in our website, session expires, and our "OnlineUsers" global variable is decreased. To know more about ApplicationState and HttpApplicationState class visit this MSDN link: msdn2.microsoft.com/en-us/library/system.web.httpapplicationstate(VS.80).aspx NOTE: we are using Application.Lock and Application.Unlock methods to prevent multiple threads from changing this variable at the same time. By calling Application.Lock we are receiving exclusive right to change the values in Application state. But we must not forget to call Application.Unlock() afterwards. Step 2: In order for this to work correctly we need to enable sessionstate and configure its mode to InProc value (in our web.config file):

<system.web> <sessionState mode="InProc" cookieless="false" timeout="20" /> </system.web> In-process mode stores session state values and variables in memory on the local Web server. It is the only mode that supports the Session_OnEnd event that we used previously. Timeout value (in minutes, not in seconds) configures how long our sessions are kept 'alive' - in other words here we set how long our users can be inactive before considered Offline. In this example timeout is set to 20 minutes, so while our visitors click on some links in our website at least once in a 20 minutes, they are considered online. If they do not open any pages on our website longer than 20 minutes, they are considered Offline, and their session is destroyed, so our online visitor counter is decreased by 1. (You can experiment with lower or higher values of Timeout settings to see what is the best for your website). Ok, so now we are done with configuration steps, let us see how to use this: To show number of online visitors/users on your ASPX page you can use this code:

Visitors online: <%= Application["OnlineUsers"].ToString() %>

Next you could put this code snippet in you UserControl, or inside Asp.Net AJAX UpdatePanel control, and use Timer to refresh it in regular intervals without refreshing the whole page, but that is another story
Found errors in this FAQ? Have a suggestion? Click here Printer Friendly version of this page

(Current rating: 4.42 out of 5 for 86 votes)

Show Comments (17)

NUMERO DE USUARIOS ONLINE CON ASP.NET 2.0 Publicado por ericgh el abril 13, 2009 1 comentario A continuacin describiremos como hacer para mostrar el nmero de usuarios que se encuentran navegando en nuestro sitio Web (Usuarios Online). 1.- Agregamos un nuevo elemento a nuestro sitio Web de tipo Clase de aplicacin global que deber de tener una extensin .asax

Elemento de tipo Clase global de ASP.NET

2.- Una vez agregado nos muestra el contenido del archivo con algunos eventos por default. 3.- Comenzamos a agregar cdigo en el evento Application_Start y quedaria algo como lo siguiente:

void Application_Start(object sender, EventArgs e) { // Cdigo que se ejecuta al iniciarse la aplicacin Application["activos"] = 0; Application["fecha"] = DateTime.Now; }
4.- Agregamos codigo a los eventos Session_Start y Session_End.

void Session_Start(object sender, EventArgs e) { // Cdigo que se ejecuta cuando se inicia una nueva sesin Application.Lock(); Application["activos"] = (int)Application["activos"] + 1; Application.UnLock(); }

void Session_End(object sender, EventArgs e) { // Cdigo que se ejecuta cuando finaliza una sesin. // Nota: El evento Session_End se desencadena slo con el modo sessionstate // se establece como InProc en el archivo Web.config. Si el modo de sesin se establece como StateServer // o SQLServer, el evento no se genera. Application.Lock(); Application["activos"] = (int)Application["activos"] 1; Application.UnLock(); }
5.- Por ultimo mostrarmos el numero de usuarios en la pagina aspx que deseemos de la siguente forma: lblNumerousuariosOnLine.Text = Application["activos"].ToString(); Listo !!!, ya tenemos nuestro propio contador de usuarios online.

asp .net mostrando cuantos usuarios hay online

bueno lo primero tenemos que crear un archivo global.asax y agregar el siguiente codigo

Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs) ' Code that runs when a new session is started Try If IsNumeric(Application.Item("contador")) = False Then Application.Item("contador") = 1 End If Dim x1 As Single x1 = Val(Application.Item("contador").ToString) x1 = x1 + 1 Application.Item("contador") = x1 Application.Item("urlref") = Me.Request.UrlReferrer.ToString Catch ex As Exception

End Try End Sub Sub Session_End(ByVal sender As Object, ByVal e As EventArgs) ' Code that runs when a session ends. ' Note: The Session_End event is raised only when the sessionstate mode ' is set to InProc in the Web.config file. If session mode is set to StateServer ' or SQLServer, the event is not raised. Try If IsNumeric(Application.Item("contador")) = False Then Application.Item("contador") = 0 End If Dim x1 As Single x1 = Val(Application.Item("contador").ToString) x1 = x1 - 1 Application.Item("contador") = x1 Catch ex As Exception End Try End Sub

que hace cuando se inicia una sesion se sumara a la variable contador +1 cuando el servidor genere el timeout hara el -1 bueno para mostrar los usuarios online es facil basta en el master page o la pagina principal poner un control label o y asignarle el valor Application.Item("contador")) Try label1.text=Application.Item("contador")) .tostring Catch ex As Exception label1.text="no anda naiden xD" End Try apliquen un try por si las moscas saludos............

There are many ways to count number of active visitors on your ASP.NET website. They differ in technique and accuracy. here is the simplest approach that delivers acceptable accuracy when configured optimally: Step 1: - first we need to add these lines to our global.asax file (if your website do not have it, create it by right-clicking on website in solution explorer, and choosing Add New Item > Global Application Class option) void Application_Start(object sender, EventArgs e)

{
// Code that runs on application startup Application["OnlineUsers"] = 0;

}
void Session_Start(object sender, EventArgs e)

{
// Code that runs when a new session is started

Application.Lock(); Application["OnlineUsers"] = (int)Application["OnlineUsers"] + 1; Application.UnLock(); }


void Session_End(object sender, EventArgs e)

{
// Code that runs when a session ends. // Note: The Session_End event is raised only when the sessionstate mode // is set to InProc in the Web.config file. If session mode is set to StateServer // or SQLServer, the event is not raised.

Application.Lock(); Application["OnlineUsers"] = (int)Application["OnlineUsers"] - 1; Application.UnLock(); }


This will allow us that whenever some distant web visitor opens our website in his browser, and new session is created for him, our "OnlineUsers" variable in the global HttpApplicationState class instance is increased. Also when user closes his browser or does not click on any links in our website, session expires, and our "OnlineUsers" global variable is decreased. To know more about ApplicationState and HttpApplicationState class visit this MSDN link: msdn2.microsoft.com/en-us/library/system.web.httpapplicationstate(VS.80).aspx NOTE: we are using Application.Lock and Application.Unlock methods to prevent multiple threads from changing this variable at the same time. By calling Application.Lock we are receiving exclusive right to change the values in Application state. But we must not forget to call Application.Unlock() afterwards.

Step 2: In order for this to work correctly we need to enable sessionstate and configure its mode to InProc value (in our web.config file): <system.web> <sessionState mode="InProc" cookieless="false" timeout="20" /> </system.web> In-process mode stores session state values and variables in memory on the local Web server. It is the only mode that supports the Session_OnEnd event that we used previously. Timeout value (in minutes, not in seconds) configures how long our sessions are kept 'alive' in other words here we set how long our users can be inactive before considered Offline. In this example timeout is set to 20 minutes, so while our visitors click on some links in our website at least once in a 20 minutes, they are considered online. If they do not open any pages on our website longer than 20 minutes, they are considered Offline, and their session is destroyed, so our online visitor counter is decreased by 1. (You can experiment with lower or higher values of Timeout settings to see what is the best for your website). Ok, so now we are done with configuration steps, let us see how to use this: To show number of online visitors/users on your ASPX page you can use this code:

Visitors online: <%= Application["OnlineUsers"].ToString() %>


Next you could put this code snippet in you UserControl, or inside Asp.Net AJAX UpdatePanel control, and use Timer to refresh it in regular intervals without refreshing the whole page, but that is another story

Howto Create a Hit Counter Using the Global.asax File in ASP.NET 1.x
If you have a live Web site on the World Wide Web, you may be interested in how many people are visiting your site. You can of course analyze the log files of your Web server but that information is usually difficult to read. The log files contain information for each and every request a visitor has made to your site, including resources like images, Flash movies and so on. This makes it near impossible to extract information about individual users. It would be a lot easier if you could count the number of individual users that have visited you since you started your site. It would also be useful if you could see the number of users that are currently browsing your site. This article will show you how to accomplish these two tasks by storing the hit counters in static variables using code in the Global.asax file. The disadvantage of this method is that this information is lost when you restart the Web server. Two other articles on this site demonstrate how to store this information in a text file and in adatabase, so the value for the counter will be preserved when you restart your Web server. There is also a Classic ASP version of this article available

Prerequisites
The code in this article uses Sessions in ASP.NET, so you'll need to have them enabled on your server, by configuring the <sessionState> element in the Web.config file. Refer to the References section at the end of this article for more details. You'll also need to have access to a file called Global.asax in the root of your site. If you run your own Web server, this is not a problem; you can simply create the file yourself. If you are using an ISP, you'll need to check with them if they support the use of the Global.asax file as, unfortunately, not all ISPs allow this. This article also assumes you're using Visual Studio .NET 2002 or 2003, as it shows code and ASPX pages using the Code Behind model. Don't worry if you don't have Visual Studio .NET; it should be relatively easy to use the code in your own Code Editor like Macromedia Dreamweaver MX or Notepad.

Counting Users
One of the easiest ways to count individual users is in the Session_Start event that you can define in theGlobal.asax file. This event is fired whenever a user requests the first page in your Web site. This way, you have the ability to count each unique visitor only once during their visit. As long as the Session remains active on the server, the user won't be counted again. After the Session has timed out (it will automatically time out after a certain interval when no new pages have been requested) or has been explicitly ended, a request to a page will create a new Session, and the user will be counted again. To keep track of the total number of users that have visited your site since you started the Web server, you can increase a counter for each request a user makes. Let's call this counter TotalNumberOfUsers. You can store that counter in a static variable in the Global class. This Global class is defined in the file Global.asax.cs, the Code Behind file for Global.asax. By creating static variables, you can be sure there is always just one instance of your hit counter variable present. Because the class defined in the Global.asax file is accessible throughout the entire application, you can retrieve and display the value for the counter on other pages in your site. You can also create a second counter, called CurrentNumberOfUsers for example, that counts the number of active Sessions on your server. Just as with TotalNumberOfUsers, you increase the value of this counter whenever a new Session is started. However, you should decrease its value again when the Session ends. so you can keep track of the number of users that are currently visiting your site.

Let's take a look at how you can accomplish this: You should start by making sure you have a file called Global.asax (note that the extension is different from ordinary aspx pages) in the root of your Web site. Usually, when you create a new Visual Studio ASP.NET Web Application, the Global.asax file is already there, and the skeleton for important events like Session_Startand Session_End are already present. If you don't have the file, open the Visual Studio .NET Solution Explorer (Ctrl+Alt+L), right-click your Web project and choose Add | Add New Item... from the context menu. Scroll down the list with Web Project Items until you see Global Application Class. Alternatively, expand Web Project Items and then click Utility to limit the list of Web items. Select the Global Application Class and click Open to add the Global.asax file to your Web site project. The page will open in Design View so you'll need to click the link "click here to switch to code view" to view the Code Behind file for the Global.asax file. You'll see some default using statements, followed by the definition for theGlobal class. You'll expand this class by adding a few private variables for the two hit counters. These private variables will then be made accessible through public properties. Using properties instead of public fields helps keeping your code cleaner and more stable. Calling code is not allowed to just arbitrarily change the field's value; it has to change the value through a public Set method. In this example, you'll make the code even a bit more safe by removing the Set method altogether. This makes it impossible for calling code to change the value of the counter; all it can do is read its value.

Modifying Global.asax
1. Locate the code that starts with public class Global : System.Web.HttpApplication and add the following shaded lines of code:

namespace HitCounters { /// <summary> /// Summary description for Global. /// </summary> public class Global : System.Web.HttpApplication { private static int totalNumberOfUsers = 0; private static int currentNumberOfUsers = 0;

/// <summary> /// Required designer variable.

Whenever the Web application starts, the Global class is constructed and the two hit counters will be initialized to 0.
2. The next step is to add code to the Session_Start event. This event will fire once for each user when they request the first page in your Web application, so this place is perfect for your hit counter. Inside this event, the values of the two hit counters are increased; one for the total number of users and one for the current number of users. Locate the skeleton for the Session_Start event and add the following code:

protected void Session_Start(Object sender, EventArgs e) { totalNumberOfUsers += 1; currentNumberOfUsers += 1; } 3. Just as with the Session_Start event, you'll need to write some code for the Session_End event. However, instead of increasing the counters, you should decrease the counter for the current number of users only. This means that whenever a user Session times out (usually 20 minutes

after they requested their last page), the counter will be decreased, so it accurately holds the number of current users on your site. You should leave the counter for the total number of users untouched. Locate the Session_End event, and add this code: protected void Session_End(Object sender, EventArgs e) { currentNumberOfUsers -= 1; }

Making Your Counters Accessible by Other Pages


Since the hit counters are stored in the Global class, you need some way to get them out of there, so you can display them on a management page for example. The easiest way to do this, is to create two public properties. Because the Global class is in many respects just an ordinary class, it is easy to add public properties to it. To add the properties, locate the skeleton for the Application_End event, and add the following code right below it:
protected void Application_End(Object sender, EventArgs e) { } public static int TotalNumberOfUsers { get { return totalNumberOfUsers; } } public static int CurrentNumberOfUsers { get { return currentNumberOfUsers; } }

With these two read-only properties in place, your calling code is now able to access the values of your hit counters. For example, to retrieve the number of users browsing your site right now, you can use this code:HitCounters.Global.CurrentNumberOfUsers where HitCounters is the default namespace for your Web application as defined on the Property Pages for the Web project in Visual Studio .NET.

Testing it Out
To test out your hit counters, create a new Web form and call it HitCounter.aspx. You can save the form anywhere in your site. In Design View, add two labels to the page and call them lblTotalNumberOfUsers andlblCurrentNumberOfUsers respectively. Add some descriptive text before the labels, so it's easy to see what value each label will display. You should end up with something similar to this in Code View:
<body> <form id="frmHitCounter" method="post" runat="server"> Total number of users since the Web server started: <asp:label id="lblTotalNumberOfUsers" runat="server"></asp:label><br /> Current number of users browsing the site: <asp:label id="lblCurrentNumberOfUsers" runat="server"></asp:label><br />

</form> </body>

Press F7 to view the Code Behind for the hit counter page, and add the following code to the Page_Load event:
private void Page_Load(object sender, System.EventArgs e) { int currentNumberOfUsers = HitCounters.Global.CurrentNumberOfUsers; int totalNumberOfUsers = HitCounters.Global.TotalNumberOfUsers; lblCurrentNumberOfUsers.Text = currentNumberOfUsers.ToString(); lblTotalNumberOfUsers.Text = totalNumberOfUsers.ToString(); }

The first two lines of code retrieve the total number of visitors and the current number of visitors from theGlobal class. The next two lines simply display the values for the counters on the appropriate labels on the page. To test it out, save the page and view it in your browser. You'll see there is one current user. Also, note that the total number of users is 1. Open another browser (don't use Ctrl+N, but start a fresh instance or use an entirely different brand of browser) and open the counter page. You'll see there are two current users, and two users in total. Wait until both the Sessions have timed out (the default timeout defined in Web.config is 20 minutes) and open the hit counter page again. You'll see there is one current user, but the total number of users has been maintained and should be 3.

Summary
This article demonstrated how to create a hit counter that keeps track of the current and total number of users to your site. It stores these counters in static variables in the Global class so they are available in each page in your Web site. A big disadvantage of storing these variables in static variables is that their values get lost when the Web server is restarted. Two other articles on this site will demonstrate how you can save the counter value for the total number of users in a text file or in a database. By saving the counter to a text file or database, its value can be maintained, even when you restart or reboot the Web server.

Howto Create a Hit Counter Using a Text File in ASP.NET (http://Imar.Spaanjaars.Com/227/howto-create-a-hit-counter-using-a-text-file-inaspnet-1x) Howto Create a Hit Counter Using a Database in ASP.NET (http://Imar.Spaanjaars.Com/238/howto-create-a-hit-counter-using-a-database-inaspnet-1x-with-c-sharp)

Related Articles

Howto Create a Hit Counter Using a Text File in ASP.NET 1.x


If you have a live Web site on the World Wide Web, you may be interested in how many people are visiting your site. You can of course analyze the log files of your Web server but that information is usually difficult to read. The log files contain information for each and every request a visitor has made to your site, including resources like images, Flash movies and so on. This makes it near impossible to extract information about individual users. It would be a lot easier if you could count the number of individual users that have visited you since you started your site. It would also be useful if you could see the number of users that are currently browsing your site. This article will show you how to accomplish these two tasks by storing the hit counters in static variables in theGlobal class and in a text file using code in the Global.asax file. This article extends the ideas from a previous article where the values of the counters were just stored in static

variables. By writing the counters to a file you can maintain their values, even when you restart the Web server. There is also a Classic ASP version of this article available.

Prerequisites
The code in this article uses Sessions in ASP.NET, so you'll need to have them enabled on your server, by configuring the <sessionState> element in the Web.config file. Refer to the References section at the end of this article for more details. You'll also need to have access to a file called Global.asax in the root of your site. If you run your own Web server, this is not a problem; you can simply create the file yourself. If you are using an ISP, you'll need to check with them if they support the use of the Global.asax file as, unfortunately, not all ISPs allow this. You'll also need to be able to write to a text file from within the Global.asax file. This means that the account your Web site is running under (usually, the ASPNET account) needs sufficient permissions to write to the file. Finally, this article assumes you're using Visual Studio .NET 2002 or 2003, as it shows code and ASPX pages using the Code Behind model. Don't worry if you don't have Visual Studio .NET; it should be relatively easy to use the code in your own Code Editor like Macromedia Dreamweaver MX or Notepad.

Counting Users
Just as in the article where the counters were stored in the Global class, you can make use of theSession_Start event, defined in the Global.asax file to keep track of your users. This event is fired for every user whenever they request the first page in your Web site. This way, you have the ability to count each unique visitor only once during their visit. As long as the Session remains active on the server, the user won't be counted again. After the Session has timed out (it will automatically time out after a certain interval when no new pages have been requested) or has been explicitly ended, a request to a page will create a new Session,Session_Start will fire and the user will be counted again. To keep track of the total number of users that have visited your site since you started the Web server, you can increase a counter for each request a user makes. Let's call this counter totalNumberOfUsers. You can store that counter in a static variable in the Global class, so you can retrieve and display it on other pages in your site. You can also create a second counter, called currentNumberOfUsers for example, that counts the number of active Sessions on your server. Just as with totalNumberOfUsers, you increase the value of this counter whenever a new Session is started. However, you should decrease its value again when the Session ends. so you can keep track of the number of users that are currently visiting your site. Besides storing these values in the Global class, you can also write the value of totalNumberOfUsers to a text file, so its values will survive server restarts. When your server is restarted, code in the Global.asax file will read in the old value from the text file, so your counter will continue with the value it had before the restart. Don't underestimate the problem of restarting your Web server. Even if you have your stable Windows 2003 box running for months without a reboot, the new IIS Process Recycling feature may restart your Web application every day or even every few hours. You should start by making sure you have a file called Global.asax (note that the extension is different from ordinary aspx pages) in the root of your Web site. Usually, when you create a new Visual Studio ASP.NET Web Application, the Global.asax file is already there, and the skeleton for important events like Session_Startand Session_End are already present in its Code Behind file. If you don't have the file, open the Visual Studio .NET Solution Explorer (Ctrl+Alt+L), right-click your Web project and choose Add | Add New Item... from the context menu. Scroll down the list with

Web Project Items until you see Global Application Class. Alternatively, expand Web Project Items and then click Utility to limit the list of Web items. Select the Global Application Class and click Open to add the Global.asax file to your Web site project. The page will open in Design View so you'll need to click the link "click here to switch to code view" to view the Code Behind file for the Global.asax file. You'll see some default using statements, followed by the definition for theGlobal class. I'll show you how to expand this class in the remainder of this article by adding a few private variables for the two hit counters. These private variables will then be made accessible through public properties. Using properties instead of public fields helps keeping your code cleaner and more stable. Calling code is not allowed to just arbitrarily change the field's value; it has to change the value through a public Setmethod. In this example, you'll make the code even a bit more safe by removing the Set method altogether. This makes it impossible for calling code to change the value of the counter; all it can do is read its value.

Modifying Global.asax
1. Locate the code that starts with public class Global : System.Web.HttpApplication and add the following shaded lines of code:

namespace HitCounters { /// <summary> /// Summary description for Global. /// </summary> public class Global : System.Web.HttpApplication { private static int totalNumberOfUsers = 0; private static int currentNumberOfUsers = 0;

/// <summary> /// Required designer variable. 2. The code that writes the counters to a file, makes use of the StreamWriter class. This class is located in the System.IO namespace, so you'll need to add a reference to this namespace by adding a usingstatement, at the top of the page somewhere below the other using statements: System.ComponentModel; System.Web; System.Web.SessionState; System.IO; The next step is to add code to the Session_Start event. This event will fire once when a user requests the first page in your Web application, so this place is perfect for your hit counter. Inside this event, the values of the two hit counters are increased; one for the total number of users and one for the current number of users. Once the values are increased, the value of totalNumberOfUsers is written to a text file. Locate the skeleton for the Session_Start event and add the following code: protected void Session_Start(Object sender, EventArgs e) { totalNumberOfUsers += 1; currentNumberOfUsers += 1; string counterFile = Server.MapPath("/Counter.txt"); if (File.Exists(counterFile)) { File.Delete(counterFile);

using using using using 3.

} StreamWriter sw = File.CreateText(counterFile); sw.WriteLine ("Total\t" + totalNumberOfUsers); sw.Close(); } 4. Just as with the Session_Start event, you'll need to write some code for the Session_End event. However, instead of increasing the counters, you should decrease the counter for the current number of users only. This means that whenever a user Session times out (usually 20 minutes after they requested their last page), the counter will be decreased, so it accurately holds the number of current users on your site. You should leave the counter for the total number of users untouched. Locate the Session_End event, and add this line of code:

protected void Session_End(Object sender, EventArgs e) { currentNumberOfUsers -= 1; }

How It Works
The code that runs in the Session_Start event performs a few important steps; first of all, the values for the two hit counters are increased. Next, the code checks whether the counter file is already present. If it is, it gets deleted by calling the static Delete method of the File class. Then a new text file is created and the value of thetotalNumberOfUsers is written to this new file, preceded by the word Total and a Tab character. The code that runs in the Session_End event simply decreases the value of the current number of users. There is no need to touch the counter for the total number of users.

Making Your Counters Accessible by Other Pages


Since the hit counters are stored in the Global class, you need some way to get them out of there, so you can display them on a management page for example. The easiest way to do this, is to create two public properties. Because the Global class is in many respects just an ordinary class, it is easy to add public properties to it. To add the properties, locate the skeleton for the Application_End event, and add the following code just below it:
protected void Application_End(Object sender, EventArgs e) { } public static int TotalNumberOfUsers { get { return totalNumberOfUsers; } } public static int CurrentNumberOfUsers { get { return currentNumberOfUsers; } }

With these two read-only properties in place, your calling code is now able to access the values of your hit counters. For example, to retrieve the number of users browsing your site right now, you can use this code:HitCounters.Global.CurrentNumberOfUsers where HitCounters is the default namespace for your Web application as defined on the Property Pages for the Web project in Visual Studio .NET.

Reading the Counter When the Web Server Starts


As long as the Web server keeps running, this code will run fine. For each new Session that is created, the counters are increased by one and the value of totalNumberOfUsers is written to the file. If, however, the Web server stops unexpectedly, or your restart or reboot the Web server yourself, the values fortotalNumberOfUsers and currentNumberOfUsers are lost. But because the value for totalNumberOfUsershas also been stored in a text file, it's easy to retrieve the counter again from that file when the Web server starts. To read in the value from the Counter.txt file, you'll need to add some code to the Application_Startevent that is also defined in the Global.asax file:
protected void Application_Start(Object sender, EventArgs e) { int counterValue = 0; string counterFile = Server.MapPath("/Counter.txt"); if (File.Exists(counterFile)) { using (StreamReader sr = new StreamReader(counterFile)) { string result = sr.ReadLine(); if (result != null) { string delimStr = "\t"; char [] delimiter = delimStr.ToCharArray(); string [] arrResult = null; arrResult = result.Split(delimiter); if (arrResult.Length == 2) { counterValue = Convert.ToInt32(arrResult[1]); } } } } totalNumberOfUsers = counterValue; }

This code may look a bit complicated, but it's actually rather simple. A StreamReader object (sr) is used to read in a file. The StreamReader class defines a method ReadLine to read in a file line by line. Since all you're interested in is the first line, this method is called just once. If the file is empty, this method returns null, so you'll need to check for that. If line equals null, the code in the if block will not run, and the counter will get its default value of 0 (from the local variable counterValue). If ReadLine does return a string, the code in the if block will run. The string result is then split into two elements by splitting on a Tab character (\t). If you look at the code that writes to the file in the beginning of this article, you can see that the word Total, then a Tab and then the value of the counter are written to the file. Since all you're interested in is the value for the counter, you'll need to split the line in two elements; both sides of the Tab character. Because the Split method of the String class requires a char array that defines the character to split on, you'll need the additional step of converting delimStr to the array delimiter which can then be passed to the Split method of the string result. If the Length of the array equals 2 you can be sure you read in a valid line. The second element,arrResult[1], is then used as the value for the local variable counterValue, by converting it to an int usingConvert.ToInt32.

At the end of the code block, the static variable totalNumberOfUsers gets the value of counterValue, which holds either 0 or the value retrieved from the Counter file. It would have been easier to leave out the TOTAL in the text file, so there is no need to split the line of text you retrieved from the file. I did include it in this example though, because it can be useful if you want to store multiple counters in the same text file. This way, you can save individual counters as TOTALUSERS, TOTALDOWNLOADS and so on all in the same file, while you can still see which value means what.

Testing it Out
To test out your hit counters, create a new Web form and call it HitCounter.aspx. You can save the form anywhere in your site. In Design View, add two labels to the page and call them lblTotalNumberOfUsers andlblCurrentNumberOfUsers respectively. Add some descriptive text before the labels, so it's easy to see what value each label will display. You should end up with something similar to this in Code View:
<body> <form id="frmHitCounter" method="post" runat="server"> Total number of users since the Web server started: <asp:label id="lblTotalNumberOfUsers" runat="server"></asp:label><br /> Current number of users browsing the site: <asp:label id="lblCurrentNumberOfUsers" runat="server"></asp:label><br /> </form> </body>

Press F7 to view the Code Behind for the hit counter page, and add the following code to the Page_Load event:
private void Page_Load(object sender, System.EventArgs e) { int currentNumberOfUsers = HitCounters.Global.CurrentNumberOfUsers; int totalNumberOfUsers = HitCounters.Global.TotalNumberOfUsers; lblCurrentNumberOfUsers.Text = currentNumberOfUsers.ToString(); lblTotalNumberOfUsers.Text = totalNumberOfUsers.ToString(); }

The first two lines of code retrieve the total number of visitors and the current number of visitors from theGlobal class. The next two lines simply display the values for the counters on the appropriate labels on the page. To test it out, save the page and open it in your browser. You'll see there is one current user. Also, note that the total number of users is 1. Open another browser (don't use Ctrl+N, but start a fresh instance or use an entirely different brand of browser) and open the counter page. You'll see there are two current users, and two users in total. Wait until both the Sessions have timed out (the default timeout defined in Web.config is 20 minutes) and open the hit counter page again. You'll see there is one current user, but the total number of users has been maintained and should be 3.

Summary
This article demonstrated how to create a hit counter that keeps track of the current and total number of users to your site. It stores these counters in static variables in the Global class so they are available in each page in your Web site. It also stores the value for the total number of users in a text file so its value won't be lost when the Web server restarts. A disadvantage of using text files is that it's difficult to scale out your Web site to lots of users.

Only one user has access to the file at any given moment, so if you have a real busy site, you'll soon run into problems. Take a look at the following article to see how you can improve the counter page even further by using a database instead of a text file.

Howto Create a Hit Counter Using a Database in ASP.NET 1.x with C#


If you have a live Web site on the World Wide Web, you may be interested in how many people are visiting your site. You can of course analyze the log files of your Web server but that information is usually difficult to read. The log files contain information for each and every request a visitor has made to your site, including resources like images, Flash movies and so on. This makes it near impossible to extract information about individual users. It would be a lot easier if you could count the number of individual users that have visited you since you started your site. It would also be useful if you could see the number of users that are currently browsing your site. This article will show you how to accomplish these two tasks by storing the hit counters in shared variables in theGlobal class and in a database using code in the Global.asax file. The counters in the shared variables are used to display them on a page in your Web site; either as a counter so your visitors can see it as well, or somewhere on a page in your Admin section, so only you have access to them. By writing the counters to a database you can maintain their value even when you restart the Web server, while you still have a fast and scalable solution. This article extends the ideas from two previous articles where the values of the counters were just stored instatic variables in the Global class and in a text file. There are also Classic ASP and VB.NET versions of this article available.

Prerequisites
The code in this article uses Sessions in ASP.NET, so you'll need to have them enabled on your server, by configuring the <sessionState> element in the Web.config file. Refer to the References section at the end of this article for more details. You'll also need to have access to a file called Global.asax in the root of your site. If you run your own Web server, this is not a problem; you can simply create the file yourself. If you are using an ISP, you'll need to check with them if they support the use of the Global.asax file as, unfortunately, not all ISPs allow this. You'll also need to be able to write to and read from a database from within the Global.asax file. This means that the account your Web site is running under (usually, this is the ASPNET account) needs sufficient permissions to write to the database file and the folder it resides in. Finally, this article assumes you're using Visual Studio .NET 2002 or 2003, as it shows code and ASPX pages using the Code Behind model. Don't worry if you don't have Visual Studio .NET; it should be relatively easy to use the code in your own Code Editor like Macromedia Dreamweaver MX or Notepad.

Counting Users
Just as in the article where the counters were stored in the Global class, you can make use of theSession_Start event, defined in the Global.asax file to keep track of your users. This event is fired whenever a user requests the first page in your Web site. This way, you have the ability to count each unique visitor only once during their visit. As long as the Session remains active on the server, the user won't be counted again. After the Session has timed out (it will automatically time out after a certain interval when no new pages have been requested) or has been explicitly ended, a request to a page will create a new Session, Session_Start will fire and the user will be counted again. To keep track of the total number of users that have visited your site since you started the Web server, you can increase a counter for each request a user makes. Let's call this counter totalNumberOfUsers. You can store that counter in a static variable in the Global class, so you can retrieve and display it on other pages in your site. You can also create a second counter, called currentNumberOfUsers for

example, that counts the number of active Sessions on your server. Just as with totalNumberOfUsers, you increase the value of this counter whenever a new Session is started. However, you should decrease its value again when the Session ends. so you can keep track of the number of users that are currently visiting your site. Besides storing these values in the Global class, I'll show you how to save them in a database, so the value for the counter is preserved, even when the Web server is stopped and restarted. When your server is restarted, code in the Global.asax file will read in the old value from the database, so your counter will continue with the value it had before the restart. Don't underestimate the problem of restarting your Web server. Even if you have your stable Windows 2003 box running for months without a reboot, the new IIS Process Recycling feature may restart your Web application every day or even every few hours. This example uses a Microsoft Access database that is called Website.mdb. The database has just one single table called Counters. This table has two columns called CounterType and NumberOfHits. The CounterTypecolumn defines the type of counter you want to store in the database. The table looks as follows:

Figure 1 - The Counters Table In this example, the type of counter will be UserCounter, to indicate you are counting users. You can expand on this example and count individual pages, for example. In that case, you could store the page name in theCounterType column to indicate which page you are tracking. The NumberOfHits column will hold the number of hits for the counter. In this example, it stores the number of visitors to your site. The code assumes that you have saved this database (which is available in the code download for this article) in a folder called C:\Databases. If you decide to store your database at a different location, make sure you adjust the path in the code that references the database. You'll also need to make sure that the ASPNET account has sufficient permissions to both the database and the folder Databases. Once you have set up the database, you should make sure you have a file called Global.asax (note that the extension is different from ordinary aspx pages) in the root of your Web site. Usually, when you create a new Visual Studio ASP.NET Web Application, the Global.asax file is already there, and the skeleton for important events like Session_Start and Session_End are already present in its Code Behind file. If you don't have the file yet, open the Visual Studio .NET Solution Explorer (Ctrl+Alt+L), right-click your Web project and choose Add | Add New Item... from the context menu. Scroll down the list with Web Project Items until you see Global Application Class. Alternatively, expand Web Project Items and then click Utility to limit the list of Web items. Select the Global Application Class and click Open to add the Global.asax file to your Web site project. The page will open in Design View so you'll need to click the link "click here to switch to code view" to view the Code Behind file for the Global.asax file. You'll see some default using statements, followed by the definition for theGlobal class. I'll show you how to expand this class in the remainder of this article by adding a few private variables for the two hit counters. These private variables will then be made accessible through public properties. Using properties instead of public fields helps keeping your code cleaner and more stable. Calling code is not allowed to just arbitrarily change the field's value; it has to change the value through a public Setmethod. In this example, you'll make the code even a bit more safe by removing the Set method altogether. This makes it impossible for calling code to change the value of the counter; all it can do is read its value.

Modifying Global.asax

1.

Locate the code that starts with public class Global : System.Web.HttpApplication and add the following shaded lines of code:

namespace HitCounters { /// <summary> /// Summary description for Global. /// </summary> public class Global : System.Web.HttpApplication { private static int totalNumberOfUsers = 0; private static int currentNumberOfUsers = 0;

/// <summary> /// Required designer variable. 2. The code that writes the counters to the database, makes use of objects like the OleDbConnection, located in System.Data.OleDb namespace, so you'll need to add a reference to this namespace by adding a using statement, at the top of the page somewhere below the other using statements:

using System.ComponentModel; using System.Web; using System.Web.SessionState; using System.Data.OleDb;

3.

The next step is to add code to the Session_Start event. This event will fire once for each user when they request the first page in your Web application, so this place is perfect for your hit counters. Inside this event, the values of the two hit counters are increased; one for the total number of users and one for the current number of users. Once the values are increased, the value of totalNumberOfUsers will be written to the database as well. Locate the skeleton for the Session_Start event and add the following code:

protected void Session_Start(Object sender, EventArgs e) { // Increase the two counters. totalNumberOfUsers += 1; currentNumberOfUsers += 1; // Save the Total Number of Users to the database. string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Databases\Website.mdb; User ID=Admin;Password="; string sql = @"UPDATE Counters SET NumberOfHits = " + totalNumberOfUsers + " WHERE CounterType = 'UserCounter'"; OleDbConnection conn = new OleDbConnection(connectionString); OleDbCommand cmd = new OleDbCommand(sql, conn); // Open the connection, and execute the SQL statement. cmd.Connection.Open(); cmd.ExecuteNonQuery(); cmd.Connection.Close(); }

4.

Just as with the Session_Start event, you'll need to write some code for the Session_End event as well. However, instead of increasing the counters, you should decrease the counter for the current number of users only. This means that whenever a user Session times out (usually 20 minutes after they requested their last page), the counter will be decreased, so it accurately holds the number of current users on your site. You should leave the counter for the total number of users untouched. Locate the Session_End event, and add this line of code:

protected void Session_End(Object sender, EventArgs e) { currentNumberOfUsers -= 1;

How It Works
The code that runs in the Session_Start event performs a few important steps; first of all, the values for the two hit counters are increased. Next, a connection string and a SQL statement are created. The connection string points to the database Website.mdb located at C:\Databases. The SQL statement is a simple UPDATE statement that will update the value for the NumberOfHits column. You need to make sure that just the UserCounter record is updated, and the WHERE clause in the SQL statement takes care of that. This WHERE clause will make sure that only the right record is modified. Notice that just the value of the TotalNumberOfUsers counter is saved. There is no need to store the current number of users; after all, when the Web server is restarted, there are no current users yet. Next the connection object and a command object are constructed. I am using an OleDb connection in this example because a Microsoft Access database is used. If you're using SQL Server or another type of database, you'll need to construct a different kind of connection object, like a SqlConnection. The command object is used to send the SQL statement to the database over the open connection. Finally, the connection is opened, the command executed and the connection is closed again. The code that runs in the Session_End event simply decreases the value of the current number of users. There is no need to touch the counter for the total number of users.

Making Your Counters Accessible by Other Pages


Since the hit counters are stored in the Global class, you need some way to get them out of there, so you can display them on a management page for example. The easiest way to do this, is to create two public properties. Because the Global class is in many respects just an ordinary class, it is easy to add public properties to it. To add the properties, locate the skeleton for the Application_End event, and add the following code just below it:

protected void Application_End(Object sender, EventArgs e) { }

public static int TotalNumberOfUsers { get { return totalNumberOfUsers; } } public static int CurrentNumberOfUsers {

get { return currentNumberOfUsers; } }

With these two properties in place, your calling code is now able to access the values of your hit counters. For example, to retrieve the number of users browsing your site right now, you can use this code:HitCounters.Global.CurrentNumberOfUsers where HitCounters is the default namespace for your Web application as defined on the Property Pages for the Web project in Visual Studio .NET. You also saw this namespace at the top of the Code Behind file for the Global class.

Reading the Counter When the Web Server Starts


As long as the Web server keeps running, this code will run fine. For each new Session that is created, the counters are increased by one and the value of totalNumberOfUsers is written to the file. If, however, the Web server stops unexpectedly, or your restart or reboot the Web server yourself, the values fortotalNumberOfUsers and currentNumberOfUsers are lost. But because the value for totalNumberOfUsershas also been saved in the database, it's easy to retrieve the counter again when the Web server starts. To read in the value from the database, you'll need to add some code to the Application_Start event that is also defined in the Global.asax file:

protected void Application_Start(Object sender, EventArgs e) { // Get the Total Number of Users from the database. string connectionString = @"Provider=Microsoft.Jet.OLEDB.4.0; Data Source=C:\Databases\Website.mdb; User ID=Admin;Password="; string sql = @"SELECT NumberOfHits FROM Counters WHERE CounterType = 'UserCounter'"; OleDbConnection conn = new OleDbConnection(connectionString); OleDbCommand cmd = new OleDbCommand(sql, conn); // Open the connection, and execute the SQL statement. cmd.Connection.Open(); OleDbDataReader reader = cmd.ExecuteReader(); if (reader.Read()) { totalNumberOfUsers = reader.GetInt32(0); } else { totalNumberOfUsers = 0; } // Close the reader and the connection reader.Close(); cmd.Connection.Close();

} This code is more or less the same as the code that was used to write the value to the database. What's different here is that a SELECT statement is used to retrieve the value for the hit counter from the database. The sameWHERE clause is used to make sure you get the value for the right counter. What's also different is the use of an OleDbDataReader to retrieve the value from the database. If the Readmethod returns true, it means that the requested counter has been found. In that case, the

value from theNumberOfHits column is stored in the private variable called totalNumberOfUsers. The GetInt32 method makes sure the value is retrieved as an int. If the counter is not found, the private variable is reset to 0. (Note that it is unlikely that the record is not found, as it is defined in the database. If you ever delete this record, theUPDATE statement that sets the counter in the Session_Start will not run correctly, because it expects the record to be present). At the end, the OleDbDataReader and the Connection are closed. This is good practice, as leaving DataReaders and Connections open can severely limit the number of concurrent users your site can serve.

Testing it Out
To test out your hit counters, create a new Web form and call it HitCounter.aspx. You can save the form anywhere in your site. In Design View, add two labels to the page and call them lblTotalNumberOfUsers andlblCurrentNumberOfUsers respectively. Add some descriptive text before the labels, so it's easy to see what value each label will display. You should end up with something similar to this in Code View:

<body> <form id="frmHitCounter" method="post" runat="server"> Total number of users since the Web server started: <asp:label id="lblTotalNumberOfUsers" runat="server"></asp:label><br /> Current number of users browsing the site: <asp:label id="lblCurrentNumberOfUsers" runat="server"></asp:label><br /> </form> </body> Press F7 to view the Code Behind for the hit counter page, and add the following code to the Page_Load event:

private void Page_Load(object sender, System.EventArgs e) { int currentNumberOfUsers = HitCounters.Global.CurrentNumberOfUsers; int totalNumberOfUsers = HitCounters.Global.TotalNumberOfUsers; lblCurrentNumberOfUsers.Text = currentNumberOfUsers.ToString(); lblTotalNumberOfUsers.Text = totalNumberOfUsers.ToString();

} The first two lines of code retrieve the total number of visitors and the current number of visitors from theGlobal class. The next two lines simply display the values for the counters on the appropriate labels on the page. To test it out, save the page and view it in your browser. You'll see there is one current user. Also, note that the total number of users is 1. Open another browser (don't use Ctrl+N, but start a fresh instance or use an entirely different brand of browser) and open the counter page. You'll see there are two current users, and two users in total. Next, restart your Web server. If you are using IIS, you can choose Restart IIS... from the All Tasks context menu for your Web server in the IIS Management Console. Alternatively, you can recompile your application in Visual Studio .NET. Whenever you do a recompile, the Web application will restart automatically. Open HitCounter.aspx again. You'll see that currently you're the only user browsing the site, but the total number of users has maintained its value.

Summary
This article demonstrated how to create a hit counter that keeps track of the current and total number of users to your site. It stores these counters in static variables in the Global class so they are available in each page in your Web site. It also stores the value for the total number of users in a database so its value won't be lost when the Web server restarts, either unexpectedly, or on purpose. By using a database, you have created a solution that can easily be scaled to lots of users. If you have a real busy Web site, you can change the code from this article so it uses a real Database Management System, like Microsoft SQL Server or Oracle. These kind of work beasts can easily serve thousands and thousands of users a day allowing for lots of concurrent users.

Related Articles

When Sessions End - Once And For All! at www.asp101.com(http://www.asp101.com/articles/john/sessionsend/default.asp) Howto Create a Hit Counter Using a Text File in ASP.NET (http://Imar.Spaanjaars.Com/223/howto-create-a-hit-counter-using-the-globalasaxfile-in-aspnet-1x) Howto Create a Hit Counter Using the Global.asax file in ASP.NET(http://Imar.Spaanjaars.Com/227/howto-create-a-hit-counter-using-a-text-file-inaspnet-1x) Howto Create a Hit Counter Using a Database ("Classic ASP" version)(http://Imar.Spaanjaars.Com/165/howto-create-a-hit-counter-using-a-database

References

Configuring ASP.NET Applications to Use the Appropriate Session State(http://technet2.microsoft.com/WindowsServer/en/Library/51aa77d2-4485-4cb9-a75f9186dc5d775f1033.mspx) <sessionState> Element (http://msdn.microsoft.com/library/enus/cpgenref/html/gngrfsessionstatesection.asp)

Download Files

Source Code for this Article(http://Imar.Spaanjaars.Com/Downloads/Articles/HitCounterInDatabaseASPNET.zip) Source Code for this Article for Visual Studio 2008(http://Imar.Spaanjaars.Com/Downloads/Articles/HitCounterInDatabaseASPNET2008.zip)

Requiring Users to Confirm their E-mail Address after they Create an Account
Over the past couple of weeks I received a number of e-mails from readers with more or less the same question: how do you require users to confirm their e-mail addresses before they are allowed to log in with an account they just created. Rather than answer them individually by e-mail, I decided to write this article to explain the principles.

Introduction
In this article Ill show you how you can let users sign up for an account that they need to confirm first before they can sign in with it. By using the standard ASP.NET features for account management (Membership, theCreateUserWizard control, built-in e-mail sending capabilities), it turns out this is pretty easy to do. Heres a short rundown of all the required steps: 1. 2. 3. 4. Configure Membership, create a page using the standard CreateUserWizard control that sends out a standard e-mail with the user name and password. Disable the account when it is is created so users can't log in until they confirm their e-amail address. When the account is created, generate a unique ID for the user, save it the users profile, and then customize the e-mail message by including a link to a confirmation page that includes this unique ID. When the user clicks the confirmation link in the e-mail, retrieve the unique ID from the query string and use it to validate the account and approve the user.

Ill dig a little deeper into each step in the following sections. Youll find the full source code for the demo application at the end of the article. This article was written using Visual Studio 12 and SQL Server LocalDB. However, if you follow the instructions and create a new site from scratch, it would equally work in Visual Studio 2008 and 2010.

1. Setting the Stage


The first thing you need to do is modify your site so users can sign up for an account. This part is pretty simple and is identical to what you would normally do. I wont describe this part in detail but instead describe the steps I followed to set up the demo site. 1. 2. Create a new web site or web application in Visual Studio (the source you can download is for a web site project). Set up Membership by executing the following NuGet command: Install-Package Microsoft.AspNet.Providers 3. Create a page that contains a CreateUserWizard control so users can sign up for an account. This page is called SignUp.aspx in the sample application. Create an e-mail message body in the App_Data folder that contains text to welcome the user. You can use the standard <% UserName%> and <% Password %> placeholders to inject the user name and password. For example:

4.

Dear <% UserName %> Your account has been created. Please find your account details below: Username: <% UserName %> Password: <% Password %> This file is saved as ~/App_Data/YourNewAccount.txt in the sample application. 5. Set up the MailSettings element on the CreateUserWizard control so it uses this mail template like this:

<asp:CreateUserWizard ID="CreateUserWizard1" runat="server" > <MailDefinition BodyFileName="~/App_Data/YourNewAccount.txt" From="imar@example.com" Subject="Your new account"> </MailDefinition> <WizardSteps>

<asp:CreateUserWizardStep runat="server" /> <asp:CompleteWizardStep runat="server" /> </WizardSteps> </asp:CreateUserWizard> 6. Configure the system.net element in Web.config so it can successfully send out e-mail. In the sample application I am using a local pickup folder. (see http://imar.spaanjaars.com/496/using-a-local-pickup-folder-for-email-delivery for more details). Create a page with a Login control so users can sign in to your site. In the sample application, this page is called Login.aspx. Test the application. For each account you create you should receive an e-mail. You should be able to log in using the user name and password you supplied.

7. 8.

2. Disabling Created Users


This step is really easy because the CreateUserWizard has built-in support for this. All you need to do is setDisableCreatedUser to True, like this: <asp:CreateUserWizard ID="CreateUserWizard1" runat="server" DisableCreatedUser="True"> With this setting on, you should no longer be able to log om with new new accounts you create on the site.

3. Inserting a Confirmation Link in the E-mail Message


This action consists of a few steps: 1. 2. Generate a unique ID for the user and store it in the users profile. A good location to do this is in the CreateUserWizards CreatedUser event, like this: protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e) { ProfileCommon userProfile = ProfileCommon.Create(CreateUserWizard1.UserName) as ProfileCommon; accountConfirmationKey = Guid.NewGuid().ToString(); userProfile.AccountConfirmationKey = accountConfirmationKey; userProfile.Save(); } For this code to work, I added the following profile property to Web.config: <profile defaultProvider="DefaultProfileProvider"> <properties> <add name="AccountConfirmationKey"/> </properties> <providers> <add name="DefaultProfileProvider" type="System.Web.Providers.DefaultProfileProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" applicationName="/" /> </providers> </profile> Notice how the code explicitly creates a profile using ProfileCommon.Create. Since the user account has just been created, Profile is not active for the current page yet so you need to get it explicitly. This also means you need to call Save. The random ID (created using Guid.NewGuid()) is stored in the users profile and in a field in the class so you can use it when sending the e-mail, discussed next. 3. Modify the outgoing message. The CreateUserWizard has a handy SendingMail event you can hook into to customize the e-mail. You access the MailMessage instance on the e.Message property. Heres the code from the sample application that builds up a link to the current web site, embeds the unique user ID, and then adds the link to the MailMessages body: protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e)

4.

5. 6. 7. 8.

{ string confirmLink = string.Format("{0}://{1}/Confirm.aspx?ConfirmationKey={2}&UserName={3}", Request.Url.Scheme, Request.Url.Authority, accountConfirmationKey, CreateUserWizard1.UserName); e.Message.Body = e.Message.Body.Replace("##ConfirmLink##", confirmLink); } Note: I could have combined the code in the CreatedUser and SendingMail events into a single block called from SendingMail. However, separating it like this feels a bit cleaner.

9.

Modify the e-mail body to include a placeholder for the link. Heres the full text for that message from the sample application: 10. Dear <% UserName %>, 11. 12. Your account has been created. However, before you can use it you need to confirm 13. your e-mail address first by clicking the following link: 14. 15. #ConfirmLink## 16. 17. Please find your account details below: 18. 19. Username: <% UserName %> Password: <% Password %>

20. Change the CompleteSuccessText property of the CreateUserWizard control to inform the user the account is not activated immediately, but needs manual confirmation first. Heres the full code for the CreateUserWizard: 21. <asp:CreateUserWizard ID="CreateUserWizard1" runat="server" DisableCreatedUser="True" 22. OnCreatedUser="CreateUserWizard1_CreatedUser" OnSendingMail="CreateUserWizard1_SendingMail" 23. CompleteSuccessText="Your account has been successfully created. You'll 24. receive an e-mail with a confirmation link that you need to click to confirm 25. your e-mail address and activate your account." 26. > <MailDefinition BodyFileName="~/App_Data/YourNewAccount.txt" From="imar@example.com" Subject="Your new account"> </MailDefinition> <WizardSteps> <asp:CreateUserWizardStep runat="server" /> <asp:CompleteWizardStep runat="server" /> </WizardSteps> </asp:CreateUserWizard>

When users now sign up for a new account, they receive something like the following in their Inbox:

4. Activating the User Account


When the user clicks the confirmation link in the e-mail message, he's being sent to the Confirm.aspx page, along with the confirmation ID and UserName in the query string. A typical link could look like this:

http://localhost:6864/Confirm.aspx?ConfirmationKey=ef05127f-a050-41b9-9132be8a8aeea925&UserName=Imar
The localhost:6864 part varies depending on where you run this code, and would include your full domain name when used on a production site. In the code behind of Contfirm.aspx, you then get the user name from the query string and use it to create aProfile instance. This profile instance should have a value for the AccountConfirmationKey property that matches the confirmation key sent in the query string. If the two match, you can create a MembershipUser for the requested user name and activate the account by setting IsApproved to true. Heres the code from the sample application that shows a way you can implement this: protected void Page_Load(object sender, EventArgs e) { string userName = Request.QueryString.Get("UserName"); string accountKey = Request.QueryString.Get("ConfirmationKey"); var profile = ProfileCommon.Create(userName) as ProfileCommon; if (accountKey == profile.AccountConfirmationKey) { var user = Membership.GetUser(userName); user.IsApproved = true; Membership.UpdateUser(user); Status.Text = "Account confirmed successfully."; } else { Status.Text = "Something went wrong while confirming your account."; } }

As you can see, implementing this functionality is pretty straightforward, as most of what you need is supported out of the box. Hooking into some events to customize behavior is a great way to make modifications to existing functionality without building your own security system from scratch.

Extending the Sample


The sample application that comes with this article is pretty simple so its easy to focus on the concept without getting confused by too many details. For a real-world website, you may want to implement the following features:

Key expiration. Along with the unique ID you could save the date and time the key was generated in the profile as well. Then when the key is validated in Confirm.aspx you could check this date and decide not to activate the user when the key has expired. If you dont like sending the user name and password over e-mail and the query string, you could leave them out of the mail message. Then in Confirm.aspx you could add a TextBox and a Button so the user can manually enter their user name and click a confirm button. In the Code Behind you would replace the code that gets the user name from the query string with code that gets it from the text box.

Downloads
The full source code for this application (C# only)

Where to Next?
Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

Approving Users and Assigning them to Roles After They Sign Up for an Account
Back in July I wrote an article that showed how you can require your users to confirm their e-mail addressesbefore they can access your site after signing up for a new account. In this article I describe a similar but slightly different technique where an administrator of the site can approve the account before the user gains access to the site.

Approving Users
If you haven't read the original article yet, you're encouraged to do it now as it explains the core principle of approving user accounts. In this article, I'll only describe the variations needed to let an administrator approve the account. From a high-level perspective, here's what you need to do to let an administrator of your site approve the account of a newly signed up user: 1. 2. 3. Let the user sign up for an account Intercept the sending of the e-mail and either change the existing e-mail so it's send to the administrator of the site, or create an additional e-mail message instead. Add a link to the mail message body that lets an administrator approve the account. Create a page that lets an administrator approve the account, and optionally assign it to one or more roles.

You'll see how to accomplish these steps next.

1. Let the user sign up for an account


This is similar to the implementation in the original article: add a CreateUserWizard to a page (calledSignUp.aspx in the demo site), and set DisableCreatedUser to True so the user account isn't activated automatically when it gets created. Then write code for the SendingMail event and redirect the e-mail to an administrator instead of to the user that signed up for the account. Here's the code for the CreateUserWizard(note: you find a fully working example in the download for this article): <asp:CreateUserWizard ID="CreateUserWizard1" runat="server" DisableCreatedUser="True" OnCreatedUser="CreateUserWizard1_CreatedUser" OnSendingMail="CreateUserWizard1_SendingMail" CompleteSuccessText="Your account has been successfully created. You won't be able to log in until your account has been approved by an administrator."> <MailDefinition BodyFileName="~/App_Data/NewAccount.txt" From="imar@example.com" Subject="A new account has been created"> </MailDefinition> <WizardSteps> <asp:CreateUserWizardStep runat="server" /> <asp:CompleteWizardStep runat="server" /> </WizardSteps> </asp:CreateUserWizard>

2. Intercept the sending of the e-mail


In the code behind of SignUp.aspx, you can modify the e-mail message that is normally send to the user, and send it to an administrator instead, like this: protected void CreateUserWizard1_SendingMail(object sender, MailMessageEventArgs e) { // Remove the original recipient e.Message.To.Clear(); // Add the Administrator account as the new recipient e.Message.To.Add("administrator@example.com"); string confirmLink = string.Format("{0}://{1}/Confirm.aspx?ConfirmationKey={2}&UserName={3}", Request.Url.Scheme, Request.Url.Authority, _accountConfirmationKey, CreateUserWizard1.UserName); e.Message.Body = e.Message.Body.Replace("##ConfirmLink##", confirmLink); } First, this code clears the To collection by calling Clear. This removes the original recipient so the user that signed up for an account doesn't receive a copy of the message. Then the e-mail address of the Administrator is added by calling Add on the To collection and passing in the administrator's e-mail

address. The remainder of the code is identical to the code presented in the previous article. Also, the code in the CreatedUser event to generate a random confirmation key for the user is exactly the same. To see how this code looks, check out the original article or download the source at the end of this article.

3. Create a page that lets an administrator approve the account and assign it to roles
The demo that comes with this article does not only let an administrator approve the account; it also lets the administrator assign the new user to zero or more roles. To implement this, I did the following:

Enable Roles in web.config: <roleManager defaultProvider="DefaultRoleProvider" enabled="true">

In Global.asax, make sure the roles are created automatically when they don't exist: void Application_Start(object sender, EventArgs e) { if (!Roles.RoleExists("Administrators")) { Roles.CreateRole("Administrators"); } if (!Roles.RoleExists("Members")) { Roles.CreateRole("Members"); } } This is optional and you can leave out this step if you're sure the required roles already exists in your database. Display the roles when the Confirm.aspx page is loaded. For this, I added a CheckBoxList to the page that looks like this: <asp:CheckBoxList ID="RolesList" runat="server" /> And in Code Behind I assign the list of available roles using the static GetAllRoles method of the Rolesclass that comes with ASP.NET: protected void Page_Load(object sender, EventArgs e) { if (!Page.IsPostBack) { RolesList.DataSource = Roles.GetAllRoles(); RolesList.DataBind(); } _userName = Request.QueryString.Get("UserName"); _accountKey = Request.QueryString.Get("ConfirmationKey"); }

When the account is approved (with code identical to the code presented in the original article), I assign the account to the roles that the administrator selected like this: protected void SaveChanges_Click(object sender, EventArgs e) { var profile = ProfileCommon.Create(_userName) as ProfileCommon; if (_accountKey == profile.AccountConfirmationKey) { var user = Membership.GetUser(_userName); user.IsApproved = true; Membership.UpdateUser(user); foreach (ListItem role in RolesList.Items) { if (role.Selected) { Roles.AddUserToRole(_userName, role.Value);

} } Status.Text = "Account confirmed successfully."; } else { Status.Text = "Something went wrong while confirming your account."; }

This code simply loops through all the available items of the RolesList control. When the Selectedproperty is true, the administrator checked that role and the user is added to it by callingRoles.AddUserToRole. Once this code has run, the new account is active, and has been assigned to the roles the administrator has selected for that account.

Extending the Sample


This is just a short demo to show the underlying principles. If you want to use this in a real-world website, you're advised to make the following changes:

Block the Confirm.aspx using URL authorization so only administrators can access it. Currently the file can be requested by all users. Consider if you still want to send the user that signed up for an account an e-mail or not. In that case, you need to create a new MailMessage using the classes in the System.Net.Mail namespace to send a separate e-mail to the administrator from the SendingMail event. Centralize the e-mail addresses in the web.config. Storing e-mail addresses in pages directly as is done with SignUp.aspx makes your site harder to maintain.

Downloads
The full source code for this application (C# only)

Where to Next?
Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

ASP.NET N-Layered Applications - Introduction (Part 1)


Note: this is part one in a series of ten. If you rather read this entire series off-line, you can buy the full series as a convenient PDF document that comes with the full source. Besides the convenience, buying the PDF will also make you feel good as it shows your appreciation for the articles and helps me pay the bills for my server and hosting so I can keep running imar.spaanjaars.com and continue to provide you with great content. For more details, check outthis post that shows you how you can buy the entire series right now. Now that the RTM versions of Visual Studio 2012 and .NET 4.5 have been out for a while, it seems like a good time to finally write the follow up to my popular series on N-Layered design using ASP.NET 3.5 that I wrote in 2008 and early 2009. I have been wanting to do this for a long time, but there were always other things on my Todo list with a higher priority. The wait has been worth it though; since the last series targeting .NET 3.5 that I published in late 2008 and early 2009, new and compelling technologies have been released that make writing an N-Layered application such as the Contact Manager a lot easier to write. The following list has links to all articles in this series:

Part Part Part Part Part Part Part Part Part Part

1 - Introduction 2 - Setting up the Solution in Visual Studio 3 - Making your Projects Unit Testable 4 - Implementing a Model 5 - Implementing a Repository using Entity Framework Code First (not yet published) 6 - Implementing an ASP.NET MVC 4 Frontend (not yet published) 7 - Implementing a Web Forms 4.5 Frontend (not yet published) 8 - Implementing a WCF 4.5 Frontend (not yet published) 9 - Importing Data Using the API (not yet published) 10 - Extensions, Tools and Wrapping Up (not yet published)

Introduction
In this new article series you'll see how to design and build an N-Layered ASP.NET application using ASP.NET MVC 4, ASP.NET 4.5 Web Forms and a number of other up-to-date technologies such as Entity Framework 5 and WCF. In this series, I'll build a sample application to manage contact people called the ContactManager v4.5 application, similar to the demo application demonstrated in the previous article series. Over the next 10 articles I'll dissect the sample application (that you can download at the end of each article, starting with Part 2) and show you how I designed and built it. A big thanks to the people who reviewed tbis article and helped me find and fix issues in the text and code:

Ben Fox Paul Hudson Bart van Uden Spiro Uyar

Your contributions have helped greatly in improving this article series. Many thanks! Although you find full details in the remainder of this series, heres a quick list of all the technologies and concepts Ill be using for the ContactManager application.

Entity Framework (EF) 5 with Code First for all data access. MVC 4, Web Forms 4.5, WCF and a command line tool for four different frontend implementations. Unit and integration tests to make the model and application testable. NuGet to quickly bring in additional libraries and assemblies. FluentAssertions to make unit tests more straightforward to write and easier to read, especially for non-technical people. A Dependency Injection (DI) framework called StructureMap to make it easier to program against interfaces and determine the concrete types at run time as well as improve the testability of your code. A framework called AutoMapper to automatically map between your own domain objects and View Models in MVC and other applications. DynamicQuery, a helper library from Microsoft to write string based LINQ expressions for sorting and filtering data.

FileHelpers, a third-party library to read CSV files which Ill use in Part 9 to import data from a text file through the applications API into the database. NLog, a logging framework for .NET.

Why an N-Layered Architecture?


Using an N-Layered architecture for your ASP.NET applications brings a number of benefits, such as:

Separation of concerns - by putting code in separate layers, you separate the various parts of your application, such as data access, business logic and the UI. This makes it easier to design and build the application and makes it possible for developers in multiple disciplines (database, server side programming, frontend development, design) to work on the application in parallel.

Abstraction - With a layered architecture it's easier to look at a complete application and understand the roles and responsibilities of individual layers and the relationship between them. Each layer has its own responsibilities which allows you to analyze them in isolation. Testability - with a layered architecture, it's much easier to test each layer separately with unit tests as there are fewer dependencies between the various layers. This means, for example, that you can test your business logic or your UI without requiring a real database to test against. Replaceability - It'll be easier to swap out layers. For example, you can replace your data access technology without affecting the other layers higher up in the stack. Reuse - You can reuse one or more layers in different applications. You'll see the benefits of this in part 6 through 9 where the same data access and business layers are reused in four different frontend applications without requiring any changes to the lower layers.

Note that there is a big difference between N-Layers and N-Tiers. N-Layers deal with separate software layers and helps you group code logically within the application. N-Tiers on the other hand deals with the physical location of your software components: e.g. the machines where your code runs. This article series deals with N-Layer exclusively, although you could reuse much of it in an N-Tier application as well.

Introducing the Contact Manager Application


In this article series Ill use the same sample application that I used in the previous article series: a simple contact manager application that enables you to manage your contacts and their contact data such as phone numbers and e-mail addresses. But rather than a single Web Forms demo application, the new sample solution has four different frontend applications: an ASP.NET MVC 4 web site, a Web Forms site, a WCF service project and a Command Line application. When you start up one of the two web applications (the MVC or the Web Forms version) you see the home screen with a short welcome text. The People menu shows a list with all the contact people in the system with links to edit and delete them, and to manage their contact data:

Figure 1-1 The MVC site showing all contact people (click to enlarge) When you click Edit you see the following page:

Figure 1-2 Editing a contact person in the MVC site (click to enlarge) By clicking one of the address links for a contact person in the list with people (visible in Figure 1-1), you see a screen that lets you manage address details. Figure 1-3 shows the Web Forms version of the

Edit address screen. The user has already pressed Save and the validation (from the Address class in the Model project) has kicked in:

Figure 1-3 Editing an Address in the Web Forms application (click to enlarge) When you click the Email addresses or Phone numbers link in the list of contact people, you see a list of associated contact details for that person:

Figure 1-4 Managing contact data in the Web Forms application (click to enlarge)

From here, you can manage the existing data (edit and delete) as well as create new e-mail addresses for this contact. The WCF project lets you execute CRUD (Create, Read, Update and Delete) methods against the contact people in the database over the network which is useful for machine-to-machine interactions. Finally, the Command Line tool shows how to import data from a source like a CSV file to get existing data into the database through the applications API. As you can see, the functionality is rather simple which makes it easier to focus on the core concepts. However, when designing and building the sample application I havent taken any shortcuts or oversimplified things. Anything you see in the sample solution can be used to build real-world, large scale web applications.

History of the Contact Manager Application


This is the third version of the Contact Manager Application used to demonstrate N-Layer design concepts in ASP.NET. The first version was released in January 2007 and came as a single Web Site Project with all the UI, data access and business logic in a single project. The second version was released in November 2008. It introduced a Web Site Project for the UI as well as a number of class library projects for the business logic layer, the entities, the data access layer and the validation. The previous design brought a lot of advantages in terms of separation of concerns and code that was relatively easy to understand and maintain. However, it did have a number of drawbacks that made it more difficult to use as Ive learned in the past few years while building real-world web sites and applications based on this design. Ill discuss these drawbacks in the next section. The solution to these drawbacks are discussed in the remainder of this article series.

Room for Improvement


Heres a list of some of the issues that I ran into when building applications based on the previous design:

The solution required quite a lot of code in each of the layers. You needed code in the dumb data object, you needed a Manager class in the Business layer for validation of business rules, you needed a Manager class in the Data layer for database access and you needed quite a lot of code in stored procedures. Probably the biggest downside of this code is that most of it is repetitive, forcing you to write the same code over and over again for each of your implemented main entities. Because of the tight coupling with the database layer, it was a challenge to test both the DAL and the code that uses the database layer, especially when used in other applications such as an ASP.NET MVC web site. The solution required a lot of stored procedures, making maintenance and testing hard. For simple CRUD operations you needed at least four stored procedures (GetItem, GetList, InsertUpdateItem andDeleteItem) while you needed even more code to implement advanced scenarios such as filtering and sorting. Adding members to the data entities was pretty difficult. Besides adding the member to a class in theBusinessEntities project, you also needed to add support for it in the various Manager classes and stored procedures. This meant lots of updates in lots of different places for something as simple as adding a new property. The solution contained a lot of code to interact with the database. With the many ORM (Object Relational Mapping) systems available today, you really shouldn't have to write your own data access code anymore. For more information, check out: http://lostechies.com/jimmybogard/2012/07/24/dont-write-your-own-orm/. The framework used its own validation mechanism. While this has served me (and others) well over the years, better alternatives are now available that make it easier to implement validation in your business entities. In addition, frameworks like ASP.NET MVC and Entity Framework (EF) have built-in support for this newer validation mechanism. The application used an anemic design model, where business logic is implemented in separate classes that modify the state of your model objects. This is now considered an anti-pattern.

A Look Ahead
Youll see how I am addressing these concerns in the new version of the application over the next 10 articles. To give you an idea of what to expect in this series, heres a short summary of each of the 10 articles:

Part 1 - Introduction In this article (which is what youre reading right now), youll get a high-level overview of the architecture and see how I set up my projects, namespaces, classes etc. Ill describe the purpose and responsibility of each of the main projects and how they work together. Part 2 - Setting up the Solution in Visual Studio In this article Ill show you how to setup the solution using Microsoft Visual Studio 2012. Ill show you how to organize your projects and solution on disk, and how to prepare the solution for integration with TFS so it allows for easy team development and branching. Ill show you how to use NuGet to add and maintain third party libraries in the projects. Part 3 - Making your Project Unit Testable This article shows you how to add unit test projects to your solution and how to set them up. Ill be using a third party library called FluentAssertions to make your tests easier to write and understand. Part 4 - Implementing a Model In this article youll see how to set up the domain model for the application. It borrows heavily from the original application by reusing the main classes from the BusinessEntities project. This part focuses purely on the domain model, as interaction with the database is handled by a separate Visual Studio project that uses EF Code First, discussed in Part 5. Part 5 - Implementing a Repository with Entity Framework 5 Code First In this article youll see how to use Entity Framework 5 Code First to implement a data access layer that maps your model to an underlying (SQL Server) database. Ill show you how to use the repository pattern to centralize data access code and make it available to other calling code. This article also talks about validation. Validation was a big feature of the 3.5 version of my framework, so it makes sense to implement it in the new version as well. Youll see how to implement a validation strategy that is somewhat similar to the previous design in that it provides both property and object level validation. However, using built-in functionalities from the .NET Framework and the Entity Framework will make it much easier to implement the same validation in other applications such as an ASP.NET MVC site. Part 6 - Putting it all together - Implementing an MVC 4 Frontend In this article youll see how to implement an MVC 4 frontend using the model and repositories introduced in the earlier articles. The demo application enables you to manage contact people as well as their contact details such as addresses, e-mail addresses and phone numbers. Youll see how to use Dependency Injection to inject the repository and other dependencies into the MVC controllers and how the controllers then use the repository to get data in and out of the database. Part 7 - Putting it all together - Implementing a Web Forms 4.5 Frontend In this article youll see how to implement an ASP.NET 4.5 Web Forms frontend using the model and repositories introduced in the earlier articles. The frontend of the application is almost the same as the MVC application, but now everything is implemented using ASP.NET 4.5 Web Forms and the new model binding capabilities introduced in ASP.NET 4.5. Part 8 - Putting it all together - Implementing a WCF 4.5 Frontend In this article youll see how to implement a WCF 4.5 service frontend using the model and repositories introduced in the earlier articles. The WCF service enables calling applications to retrieve contact people. In addition it also allows a calling application to create new and modify and/or delete existing contact people. Part 9 - Putting it all together - Importing Data from the old Database using the API This article shows you how to use the API of the application to import legacy data from an existing data source such as a CSV file. This serves as an example on accessing data using an application that has no UI and that just uses the applications API. Part 10 Extensions, Tools and Wrapping Up In the final part of the series Ill show you some interesting tools that you can use when building applications like the ContactManager. Ill also look at some extensions you could write and then summarize the full series. Note: Part 2 and 3 of the series contain a lot of hands-on, step by step instructions as these articles show you how to setup a solution like the Spaanjaars.ContactManager application yourself. You can use these instructions pretty much as-is for your own applications. The remaining parts in the series then analyze the working code for the Spaanjaars.ContactManager application that you can download at the end of each article. Ill show a lot of the code in detail, and explain how it works, but you wont find detailed step by step instructions on how to add the code and files to the various projects.

Overview of the Architecture


In this section Ill give you an overview of the complete application. Youll see the main architecture, how I set up the various Visual Studio projects and how I linked them together. In addition youll see many of the important classes and other types inside each of the projects and learn about their responsibilities. From a high level point of view, the architecture of the Spaanjaars.ContactManagerV45 solution looks as follows:

Figure 1-5 The Architecture of the Spaanjaars.ContactManagerV45 Application (click to enlarge) The blue boxes at the bottom represent the data access layer, the green box in the middle represents the business layer and the orange boxes at the top represent the UI. The business layer also contains the model with all the main entities but thats not shown in this diagram yet. Youll see more of the model in Part 4. At the bottom, you see a SQL Server database which is, just as in the previous series, the relational database used for the application. Above the database you can see the Entity Framework DbContext; the main class used for Entity Framework 5 Code First which is what Ill use in this article series. Above this you can see a layer containing concrete repositories which use the Entity Framework DbContext internally. Note that this is just an implementation decision. The concrete repositories implement the interfaces defined in the green Repository Interfaces layer which means you can swap the concrete repositories and the Entity Framework for alternatives; for example you could build a concrete repository that uses NHibernate or Teleriks OpenAccess ORM. The user interface

applications that you see at the top of the diagram would never know you swapped the underlying data access technology as all they are aware of are the interfaces in the business layer. The exception to this is the command line application tool that youll see in Part 9 of this series. Since this application can be considered a one-off or throw away application, I havent bothered trying to decouple it from the concrete repositories that use EF. Youll see much more of this in the remainder of this series as I dig deeper into the various layers and explain how they are constructed. From a Visual Studio perspective, the application looks as follows:

Figure 1-6 The Solution Explorer showing the Spaanjaars.ContactManagerV45 Application Notice how I used Visual Studio Solution Folders to group related project types (such as Tests and Frontend (UI) projects). This makes it easier to understand how the solution is organized and it helps you to quickly show or hide a particular group of projects youre working with. At the bottom of the Solution Explorer you can see three projects. The Spaanjaars.Infrastructure project contains a number of plumbing classes and interfaces used throughout the solution. TheSpaanjaars.ContactManager45.Model project contains the core domain classes such as Person and Addressand is somewhat similar to the BusinessEntities project from the 3.5 version of my N-Layer design. TheRepositories.EF project contains all the code to interact with a SQL Server database using Entity Framework (EF) 5 Code First. Note that for the project names I use the pattern: Company.Project.Layer where Company is your companys or your clients name, Project is the name of the application and Layer specifies the type of project in the stack. You see more of this at the beginning of Part 2. The Frontend folder contains four UI or frontend projects: one using ASP.NET MVC 4, one using ASP.NET Web Forms 4.5, one using WCF and a Command Line tool used for import of data. Youll see these projects in later articles in this series. Under the hood, these projects make use of the various Model and Repositoriesprojects. The Tests Solution Folder contains a number of test projects for unit, integration and UI / MVC / WCF tests. These projects are discussed in Part 3. This may look a little overwhelming, leading you to wonder why you need so many projects for a relatively simple application. If thats the case, its important to realize you typically dont need that many projects. In my sample application I have four different frontends, demonstrating N-Layer design in various types of applications. Also, for these projects I have separate test projects, quickly increasing the total number of projects. For my new design, the minimum number of projects you need is four: the

three projects in the root of the solution explorer and at least one frontend application that uses these three projects. To see how these projects relate to each other, consider the following model diagram that shows the dependencies of the two Web frontend and the WCF projects:

Figure 1-7 A model diagram showing various components of the Application (click to enlarge) This figure shows how the Model project references the Infrastructure project, and nothing else (except for the .NET framework libraries of course which are not shown in this diagram.) The Repositories.EF project using Entity Framework (EF) references the Model project as well the Infrastructure project. The three Frontend projects (MVC, Web Forms and WCF) have a reference to the Model and Infrastructure projects as well as a reference to the Repositories.EF project. This latter reference isnt strictly needed as all the code in the UI projects is based on interfaces defined in the Model project. Using a Dependency Injection framework such as Ninject or StructureMap you could inject the concrete types in the EF project at run-time, without any compile-time dependency on this project. However, I prefer to write the bootstrapper code (code that configures the Dependency Injection framework, discussed in detail in Part 6 and 8) in my project over configuration files, and so the UI projects each have a reference to the EF project. If I wanted to switch to a repository that uses another ORM such as NHibernate or other data access technology such as ADO.NET, all I would need to do is replace the project reference and rewrite the bootstrapper code. Youll see more of this in part 5 when the EF Repository is implemented. Although the details of the individual projects are discussed in great detail in the remainder of this article series, heres an overview of how all the different projects work together:

The Model project defines all the core entities and their validation rules. Here you find classes such asPerson and EmailAddress. You also find an IPeopleRepository which is an interface that defines the contract for working with Person objects. The types in the Model project are used by the UI projects. For example, the MVC project uses Person to display information about people in the system, as well as accept modifications to those objects (Insert, Update and Delete). These types are not directly used by the UI (such as Views) but are converted to View Models as youll see later in the series. The UI projects dont directly access the database to get their data. Instead, they use repositories that in turn access the database. A repository makes it easier to centralize data access code and make it available to other calling code. In my application, the Model project defines the contract for the repository which is then implemented in the Repositories.EF project. This project uses Entity Framework under the hood to get data in and out of the database. The MVC and other UI projects use a concrete PeopleRepository from the Repositories.EF project. However, they dont have a hardcoded link to this class as that would make it both difficult to replace EF with another database technology and unit test your UI applications. Instead, the UI projects work with the IPeopleRepository interface, while a concrete EF implementation is supplied at run-time using a concept called Dependency Injection. The Spaanjaars.Infrastructure project provides low-level plumbing services used by all the other projects. The various test projects have references to other parts of the application they are testing. For example, the integration tests project has a reference to the Repositories.EF project as it accesses a real database during its tests.

The application makes use of the Repository pattern. For alternatives to this pattern, see:

http://lostechies.com/jimmybogard/2012/09/20/limiting-your-abstractions/ http://lostechies.com/jimmybogard/2012/10/08/favor-query-objects-over-repositories/

Ill discuss each of the projects in the Solution Explorer next. Youll find a high-level overview here with pointers to other articles in the series for more in-depth information. Spaanjaars.Infrastructure This is a fairly simple project with only a few classes, shown in Figure 1-8:

Figure 1-8 The Solution Explorer for the Spaanjaars.Infrastructure Project As you can tell from its name, this project isnt directly tied to the ContactManager application, Instead, I placed it in the more general Spaanjaars.Infrastructure namespace (which could be your company name or other root level namespace you might use) so it can easily be reused across multiple projects. This project provides three plumbing interfaces that the rest of the application uses. Figure 1-9 shows the class diagram for this project:

Figure 1-9 The Class Diagram of the Spaanjaars.Infrastructure Project (click to enlarge) The IRepository interface defines the contract that concrete repositories need to implement. It defines the members you interact with to get data in and out of the underlying data source. Youll see an implementation of this interface along with the unit of work related interfaces in Part 5 when you see how to build a concrete repository using Entity Framework. Its easy to build your own repository that targets a different database or ORM. All it needs to do is implement this interface and then you can plug it into another application such as a public facing ASP.NET MVC website.

DomainObject<T> and ValueObject<T> are the base classes for the various domain classes in the Modelproject. DomainObject<T> is the base class for entities that have an identity and is used by classes such asPerson. ValueObject<T> is used by pure value objects that dont have their own identity. In the sample application, Address has been implemented as a ValueObject<T> to demonstrate the differences. Youll see more of this in Part 3. Finally, in Part 5 youll see what the types in the DataContextStorage folder are used for and learn about the lifetime of an Entity Framework object context. Spaanjaars.ContactManager45.Model The Model project is somewhat similar to the BusinessEntities project in the .NET 3.5 version of this application. It features the applications core types such as Person, Address and PhoneNumber. It also features a number of collections as well as a few enumerations to define types of contact records and people, respectively. Heres what the Solution Explorer for the project looks like:

Figure 1-10 The Solution Explorer for the Spaanjaars.ContactManager45.Model Project Notice the four core types: Address, EmailAddress, Person, and PhoneNumber. If youve read the previous article series, these should all look familiar (except that Person was previously called ContactPerson). For the sake of demonstration, I let Address inherit from ValueObject<T> which means its considered a value type while all other classes inherit from DomainObject<T>. These last three types also have a collection counterpart that inherits from the custom, generic CollectionBase<T> type. The IPeopleRepository interface provides a contract that the other applications in the project work against. Youll see a lot more of this in Part 4 and 5 of this article series. Figure 1-11 shows the complete Class Diagram for the Model project. In later articles in this series Ill dig deeper into the various types and their members.

Figure 1-11 The Class Diagram of the Spaanjaars.ContactManager45.Model Project

You see more of the repositories in the next section, while a detailed explanation of the EF implementation can be found in Part 5 of this article series. Spaanjaars.ContactManager45.Repositories.EF This project contains all the implementation for working with contact people in a SQL Server database using Entity Framework 5 Code First. Figure 1-12 shows the Solution Explorer for this project.

Figure 1-12 The Solution Explorer for the Spaanjaars.ContactManager45.Repositories.EF Project This project contains concrete implementations of the repository and unit of work related interfaces you saw earlier. In addition, it contains a number of classes related to setting up the Entity Framework, and initializing and configuring the database using the fluent API and database creating strategy classes. You see how all of this works when setting up Entity Framework in Part 5. For now, heres the complete class diagram:

Figure 1-13 The Class Diagram for the Spaanjaars.ContactManager45.Repositories.EF project (click to enlarge) Spaanjaars.ContactManager45.Web.Mvc This project contains the ASP.NET MVC 4 implementation of the frontend to work with contact people and their associated contact data in a web application. Its discussed in detail in Part 6 of this article series. Here youll see Dependency Injection at work when the concrete repositories for the Entity Framework (or any other type you build) are injected into the application at run-time. Spaanjaars.ContactManager45.Web.WebForms This project contains the Web Forms implementation of the frontend to work with contact people and their associated contact data in a web application. Its discussed in detail in Part 7 o f this article series. Spaanjaars.ContactManager45.Web.Wcf This project contains a WCF service to work with contact people in your system over remote services. The WCF service has methods to retrieve, add, update and delete people from the system. The WCF project is discussed in detail in Part 8 of this article series. Spaanjaars.ContactManager45.Import

This project contains a command line tool that can import contact people and their contact data from a CSV file. The purpose of this project is to demonstrate how to use the applications public API from other applications. Part 9 of this series shows how I built the import tool. In addition to the core libraries and the four frontend projects, the solution contains four test projects, nicely grouped together under a Solution folder called Tests. You will see how to set up the test projects in Part 3. Tests are then added to these projects in the remainder of the articles. Spaanjaars.ContactManager45.Tests.Unit This project contains unit tests for the solution. Youll find some basic tests for the entities and their members, tests for validation, and more. Part 3 of this series digs deeper into this project. Spaanjaars.ContactManager45.Tests.Integration Since this application relies heavily on a database, it makes sense to have a number of integration tests that make use of the database. This way, you can test the interaction of the various components, as well as some database specific logic such as unique constraints. Once again Part 3 of this series digs deeper into this project. Spaanjaars.ContactManager45.Tests.Frontend.Mvc In this project youll find a number of tests for the ASP.NET MVC frontend. While the purpose of this article is not to show you how to write unit tests for MVC or other application frameworks, the tests in this project serve to demonstrate that with the framework presented in this series, unit testing is easy because of the way you can inject concrete types using a Dependency Injection framework while your application programs against an interface. This makes it much easier to test your controllers that have dependencies on components such as repositories. Spaanjaars.ContactManager45.Tests.Frontend.Wcf In this project you find a number of tests for the WCF services project. Just as with the MVC project, I am using Dependency Injection to decouple the service methods from their dependencies such as repositories to enable unit testing. This article series is meant as an introduction to architecting N-Layered web applications using ASP.NET 4.5 and Entity Framework 5 Code First. This means Ill dig as deep into these technologies as appropriate to explain the topic. However, it also means I wont provide a lot of details about side issues. For example; I may be using an open source framework to make unit testing easier in the sample application, but I wont dig into the details on how to retrieve and install this framework, or how to configure it for the sample application and how to use it.

Stuff I Like to Do
At the end of each article, Ill provide a section called Stuff I Like to Do where I mention a number of asides and provide links and guidance where appropriate. For this first article, theres nothing to add yet, other than maybe a suggestion to read Part 1 of the original article series at http://imar.spaanjaars.com/476/n-layered-web-applications-with-aspnet-35-part-1-generalintroduction so that you have a general idea of how the application was designed previously.

Summary
In this article, you saw a brief overview of the ContactManager v4.5 application. I described some of the applications history, and highlighted some shortcomings of the .NET 2.0 and 3.5 versions of the application. You then saw an overview of the new framework including the various components (Visual Studio projects) that are involved. The article concluded with a description of each project in the solution so you can see what their responsibilities are and how they fit together. Each of these projects is discussed in more detail in later parts of this article series. In the next part, youll see how to setup the solution in Visual Studio. Youll see how to add the Class Library projects and four Frontend projects (an MVC 4 site, a Web Forms application, a WCF service and a command line tool) to the solution. Ill be using all of these projects in the remaining articles in this series.

Downloads

Full source for this application in C#

Where to Next?
Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

ASP.NET N-Layered Applications - Setting up the Solution in Visual Studio (Part 2)


Note: this is part two in a series of ten. If you rather read this entire series off-line, you can buy the full series as a convenient PDF document that comes with the full source. Besides the convenience, buying the PDF will also make you feel good as it shows your appreciation for the articles and helps me pay the bills for my server and hosting so I can keep running imar.spaanjaars.com and continue to provide you with great content. For more details, check outthis post that shows you how you can buy the entire series right now. This is Part 2 in a series of 10 that show you how to build N-Layered applications using ASP.NET 4.5 and Entity Framework 5 Code First. The previous article provided some history of the architecture of the Contact Manager application and gave a broad overview of the new architecture. In this installment, things get a bit more concrete when you see how to setup a solution in Visual Studio 2012. The VS solution is going to contain three class libraries: one for the Infrastructure, one for the applications Model and one to hold the Entity Framework (EF) Repository implementation. Ill also add four frontend projects (an ASP.NET MVC 4, a Web Forms project, a WCF service project, and a windows command line application) which are discussed in detail in Part 6, 7, 8 and 9 of this series respectively. In the next article in this series Ill extend the solution with four more projects for unit, integration, UI and service tests. If you havent read Part 1 of this series yet, youre encouraged to do so first. The following list has links to all articles in this series:

Part Part Part Part Part Part Part Part Part Part

1 - Introduction 2 - Setting up the Solution in Visual Studio 3 - Making your Projects Unit Testable 4 - Implementing a Model 5 - Implementing a Repository using Entity Framework Code First (not yet published) 6 - Implementing an ASP.NET MVC 4 Frontend (not yet published) 7 - Implementing a Web Forms 4.5 Frontend (not yet published) 8 - Implementing a WCF 4.5 Frontend (not yet published) 9 - Importing Data Using the API (not yet published) 10 - Extensions, Tools and Wrapping Up (not yet published)

Note: as mentioned in Part 1, this article and the next article (Part 3) contain a lot of hands-on, step by step instructions that show you how to setup a solution like the Spaanjaars.ContactManager application. You can use these instructions pretty much as-is for your own applications. The remaining parts in the series analyze the working code for the Spaanjaars.ContactManager application. Ill show a lot of the code in detail, and explain how it works, but you wont find detailed step by step instructions on how to add the code and files to the various projects. Instead, you're encouraged to download the code at the end of each article to see how it works.

Naming Conventions
If youve read the previous article series, youll recognize the naming conventions I use for my projects and root namespaces. For the main projects I use the pattern: Company.Project.Layer where Company is your companys or your clients name, Project is the name of the application and Layer specifies the type of project in the stack. I can further divide the layer in specific project types. This gives me names such asSpaanjaars.ContactManager45.Model and Spaanjaars.ContactManager45.Web.Mvc. My test projects follow the same pattern for the root name and are then further divided in the type of tests (Unit, Integration etc.) leading to names such as Spaanjaars.ContactManager45.Tests.Unit. Note that the Infrastructure project I introduced in the preceding article is independent of the ContactManager application and can be reused across multiple applications. As such, its called Spaanjaars.Infrastrucurerather than Spaanjaars.ContactManager45.Infrastrucure.

Setting up the Solution


In the following section youll find detailed instructions on setting up the solution. This is useful if you want to create your own project from scratch. If you just want to see the sample code or run the application, you can skip all these steps and simply open the solution that comes with this article series in Visual Studio 2012. You find a link to the source code at the end of each article. Note: these steps are heavily borrowing from an earlier article I wrote about setting up a project for team development and TFS. I decided to repeat part of the steps here and make them more specific for the Spaanjaars.ContactManager application. 1. 2. 3. Start Visual Studio 2012 and choose File | New Project. At the top of the dialog, choose .NET Framework 4.5 from the drop-down list. In the Other Project Types category click Visual Studio Solutions and then click Blank Solution. As the name of the Solution, enter Spaanjaars.ContactManager45 and as the Location choose C:\Projects. Note: substitute Spaanjaars and ContactManager with your own company and project names.

Figure 2-1 The New Project Dialog in Visual Studio 2012 (click to enlarge) 4. 5. Click OK. Close Visual Studio and open the project folder (at C:\Projects\Spaanjaars.ContactManager45) in File Explorer (Windows Explorer on Windows 7 and earlier). Create a new folder called Main and then drag all of the Spaanjaars.ContactManager45.* files fromC:\Projects\Spaanjaars.ContactManager45 into this new Main folder. Your structure now looks like this:

Figure 2-2 File Explorer Showing the Solution (click to enlarge) This Main folder is used later for Branching in TFS. This all feels a bit clumsy but I see no other way to create the solution with this name and store it in a folder called SolutionName/Main. Fortunately, this is a one-time operation. 6. 7. 8. Open the Solution in Visual Studio by double-clicking the .sln file in the Main folder. Right-click the Solution in the Solution Explorer and choose Add | New Project. In the tree on the left choose your programming language, and then choose Class Library from the Windows category. 9. At the top of the dialog, make sure that .NET Framework 4.5 is selected. 10. As the name of the project, enter Spaanjaars.ContactManager45.Model. 11. As the location for the project enterC:\Projects\Spaanjaars.ContactManager45\Main\Applications:

Figure 2-3 The Add New Project Dialog for the Model Project (click to enlarge)

Notice the inclusion of the Applications folder in the path. This way you can group all projects that make up the core application in a single folder. In the next article Ill use a folder called Tests inside the Main folder to group all Test projects. 12. Click OK to add the project. 13. On disk, your solution now has the following structure:

Figure 2-4 File Explorer Showing the Model Project (click to enlarge) 14. Back in Visual Studio, delete the default Class1.cs file as you dont need it. 15. Repeat steps 7 through 12 and 14 two more times and add the following Class Library projects: 1. Spaanjaars.ContactManager45.Repositories.EF 2. Spaanjaars.Infrastructure Make sure you dont forget the \Applications part in the projects location, as VS defaults to the solutions folder instead. Note that the Infrastructure project is generic enough to be placed in a namespace which is outside the ContactManager application. This makes it possible to reuse the classes defined in this project in other solutions based on the same model. For this sample application I put the project in the Applications folder, but if youre reusing it across multiple projects youll want to store it elsewhere such as in C:\Projects directly. In the next section youll see how to add four frontend projects to the solution. In your own projects you dont need all four of them; just pick the one(s) you need. If you want to follow along with this series, just add all four projects. 16. Right-click the Solution in the Solution Explorer and choose Add | New Solution Folder. Name the folderFrontend. 17. The next steps show you how to add an ASP.NET MVC 4 application to the solution. If you prefer a Web Forms or another type of application instead, skip to step 21 or later. Right-click the new Frontend folder and choose Add | New Project. In the tree on the left, click the Web category and then choose ASP.NET MVC 4 Web Application. 18. As the name of the project, enter Spaanjaars.ContactManager45.Web.Mvc. 19. As the location for the project enterC:\Projects\Spaanjaars.ContactManager45\Main\Applications. 20. Click OK to add the project. 21. In the New ASP.NET MVC 4 Project dialog, choose Internet as the template. Make sure Razor is selected as the View Engine and if necessary, clear the checkbox for creating a unit test project. The unit test projects are added separately to the solution in the next article. 22. Repeat steps 17 through 20, but this time add a new ASP.NET Web Forms Application and name itSpaanjaars.ContactManager45.Web.WebForms. 23. Repeat steps 17 through 20 again, but this time add a new WCF Service Application and name itSpaanjaars.ContactManager45.Web.Wcf. 24. Repeat steps 17 through 20 again, but this time add a new Console Application from the Windows category and name it Spaanjaars.ContactManager45.Import.

Tip: if you forget to store one of the projects in the Applications folder, remove the project from the Solution Explorer (right-click the project and choose Remove). Move the project to the Applications folder using File Explorer and then add the project to the solution again using its Add Existing Project option. 25. Your Solution Explorer should now look similar to Figure 2-5

Figure 2-5 The Solution Explorer with all Application Projects 26. From the Model project, add a reference to the Infrastructure project. Next, from theRepositories.EF project, add a reference to the Infrastructure and Model projects. Finally, from each of the four frontend projects add a reference to the Infrastructure, Model and Repositories.EFprojects. 27. Next, right-click the Solution and choose Rebuild Solution. This compiles the application and makes sure that everything is ready for the next steps.

Optimizing the Solution


Here are a few tips to get the Visual Studio solution in a good shape: 1. Use NuGet to update all packages that were added by Visual Studio when you created the new projects. Libraries like jQuery, jQuery UI and Entity Framework are updated regularly, and are likely to be outdated when you added them to the solution. To update the packages, right-click the solution and choose Manage NuGet Packages for Solution. Next, click Updates on the left and then update each individual package that has updates. Consider enabling NuGet Package Restore. With this feature enabled, Visual Studio downloads missing packages whenever you build your solution. This is useful if you work in a team and use a shared code repository such as TFS, because packages added by one member are downloaded automatically the next time another team member builds the solution. To enable this feature, right-click the Solution and choose Enable NuGet Package Restore. You also need this option to build the sample application that comes with this article. See the Readme.txt file in the download for more details. Delete unneeded .cs files and other boilerplate stuff you dont need. For example, if y ou havent already done so, remove the Class1.cs files from the class library projects. In addition, remove theIService1.cs, Service1.svc and Service1.svc.cs files from the WCF project.

2.

3.

Adding your Solution to TFS


Now that the skeleton for the solution is ready, its a good time to add it to your source control system. If you dont use such a system, you can skip this section (although you should seriously consider using one; you can get a free hosted TFS solution for up to five team members at http://tfs.visualstudio.com/). The following section uses TFS as the source control system, but similar concepts apply to other source control systems. 1. 2. 3. Using Team Explorer, connect to your TFS Server. On the Solution Explorer, right-click the Solution and choose Add Solution to Source Control. Click the appropriate TFS Project.

4.

As the name for the solution folder, enter Spaanjaars.ContactManager45/Main. The /Main part is not a typo. In fact it's very important as itll create an additional folder in TFS which you can set up as main branch later.

Figure 2-6 The Add Solution to Source Control Dialog 5. 6. Click OK. Your Source Control Explorer (accessible from the Team Explorer) should now look like this:

Figure 2-7 The Source Control Explorer (click to enlarge)

7. 8. 9.

Right-click the Main folder in the Source Control Explorer and choose Check In. As a comment, enter something like Initial Commit and click Check In. Still in the Source Control Explorer, right-click the Main folder and choose Branching and Merging | Convert to Branch. 10. Enter a description such as Main Branch and click Convert. 11. Thats it. From now on, other developers can get a local copy of this solution simply by opening the .slnfile from the Main folder. When they compile the application, Visual Studio will automatically attempt to download the missing packages (provided you enabled NuGet Package Restore as explained earlier) removing the need to store these packages in TFS. For more information about creating a branch, check out the original article on adding solutions to TFS (http://imar.spaanjaars.com/565/recommendations-for-setting-up-a-visual-studio-solution-for-tfs). In addition, check out the Branching and Merging guide at http://vsarbranchingguide.codeplex.com/.

Stuff I Like to Do
Here are a few tips to keep your solution in great shape, and easy to manage: 1. 2. 3. Scan the list of installed packages for each project and remove the ones you dont need. Adding them back in later is easy to do. From time to time, scan the Updates for the installed packages. Then for each package, consider whether you want to upgrade or not. Some updates cause breaking changes or require you to change code first. I like to keep a document in my Solution called Readme.txt or Stuff I Learned.txt where I keep a list of interesting blog posts, references to open source projects, sample implementations and more. To add this file, follow these steps: 1. In the folder where the .sln file resides on disk (atC:\Projects\Spaanjaars.ContactManager45\Main) create a new folder called Documentation. 2. Inside this new folder create a new text file called Readme.txt. 3. Switch to Visual Studio, right-click the Solution and choose Add | New Solution Folder. Name the folder Documentation. 4. Right-click this new folder and choose Add | Existing Item. Browse for the Readme.txt file in theDocumentation folder and click Add to add the file to the solution. 5. If youre using TFS or another source control system, right-click the solution in the Solution Explorer and choose Check in. This enables you to store the solution files and folders in TFS as well.

Summary
In this article, you saw how to set up a Visual Studio solution and a number of projects. By following the recommendations from this article with regards to project naming and their location on disk your solution will be easy to manage for you and anybody else in your team that may need to have access to it. By storing all your projects in folders below the .sln file, opening the application from source control is as easy as double-clicking the .sln file in the Source Control Explorer. In the next article youll see how to add various flavors of unit test projects to the solution. If youre not interested in unit testing (yet), you can skip directly to Part 4. However, I still encourage you to read Part 3 as it might change your mind on whether unit testing is something for you or not.

Downloads

Full source for this application in C#

Where to Next?
Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

ASP.NET N-Layered Applications - Making your Projects Unit Testable (Part 3)


Note: this is part three in a series of ten. If you rather read this entire series off-line, you can buy the full series as a convenient PDF document that comes with the full source. Besides the convenience, buying the PDF will also make you feel good as it shows your appreciation for the articles and helps me pay the bills for my server and hosting so I can keep running imar.spaanjaars.com and continue to provide you with great content. For more details, check outthis post that shows you how you can buy the entire series right now. This is Part 3 in a series of 10 that show you how to build N-Layered applications using ASP.NET 4.5 and Entity Framework 5 Code First. In this part youll see how to make your solution unit testable. In addition, youll see how to setup a project for Integration tests which work similar to unit tests but that target the database directly. If you havent read the earlier parts in this series yet, youre encouraged to do so first. The following list has links to all articles in this series:

Part Part Part Part Part Part Part Part Part Part

1 - Introduction 2 - Setting up the Solution in Visual Studio 3 - Making your Projects Unit Testable 4 - Implementing a Model 5 - Implementing a Repository using Entity Framework Code First (not yet published) 6 - Implementing an ASP.NET MVC 4 Frontend (not yet published) 7 - Implementing a Web Forms 4.5 Frontend (not yet published) 8 - Implementing a WCF 4.5 Frontend (not yet published) 9 - Importing Data Using the API (not yet published) 10 - Extensions, Tools and Wrapping Up (not yet published)

Note: as mentioned in Part 1, this article (and the previous) will contain a lot of hands-on, step by step instructions that show you how to setup a solution like the Spaanjaars.ContactManager application. You can use these instructions pretty much as-is for your own applications. The remaining parts in the series analyze the working code for the Spaanjaars.ContactManager application. Ill show a lot of the code in detail, and explain how it works, but you wont find detailed step by step instructions on how to add the code and files to the various projects.

Making Your Projects Unit Testable


To ensure a better quality of your software, its highly recommended to add unit tests to your projects. This way, you can test your code during development, minimizing the chance of introducing issues and finding and fixing them before they ever make it into production code. This article does not explain the need for unit testing in detail nor does it explain how to write good unit tests. For a good introduction into unit testing, check out the following references:

The Art of Unit Testing (Roy Osherove, Manning Publications, 2009: http://www.amazon.com/Art-Unit-Testing-Examples-Net/dp/1933988274) http://msdn.microsoft.com/en-us/library/bb385902%28v=vs.90%29.aspx http://msdn.microsoft.com/en-us/library/hh694602.aspx http://geekswithblogs.net/thomasweller/archive/2011/02/21/an-introductory-presentationabout-testing-with-mstest-visual-studio-and.aspx

This article does, however, show you how to differentiate your types of tests (using different Test Projects in Visual Studio) and how to configure the solution so that the test projects can see the relevant assemblies in the solution. In many previous solutions I built, I use more than one test project, described in the following table: Type Unit Suggested name suffix Tests.Unit Description This project contains all the unit tests that dont have a dependency on a database or the UI. In the sample application, it contains tests for model entity properties, model validation, and more. For applications with a larger model you could further separate the unit tests into separate Visual Studio projects, each named after the area of the application they are targeting.

Integration

Tests.Integration

Frontend

Tests.Frontend.Mvc

Frontend

Tests.Frontend.Wcf

This test project contains integration tests that have dependencies to other components of the system, such as a database. In the sample project you find tests that use theRepositories.EF project to interact with a SQL Server database directly. For applications with a larger model you could further separate the integration tests into separate Visual Studio projects, each named after the area of the application they are targeting. This test project contains tests that target the presentation layer. It could contain Coded UI tests and tests targeting the ASP.NET MVC controller framework. In the sample application you only find unit tests for MVC controllers but you could easily add more tests to this project. This test project contains tests for the various service methods inside the WCF service project.

In the next steps youll see how to add these four Test Projects to the solution. I am showing you how to add all four; one for each frontend application added to the solution in the previous article. If, however, your solution has fewer frontend implementations, only add the test projects for your particular frontend(s). In order to better organize my solution, I prefer to group all my test projects in a Solution Folder called Tests. This is not required, but it makes it easier to get access to all your test projects at once, or hide them when youre working on the actual code for the project. 1. 2. To add a Solution Folder for the tests, right-click the Solution in the Solution Explorer and choose Add | New Solution Folder. Name the folder Tests. Right-click this new Tests folder and choose Add | New Project. Select your preferred programming language and then, from the Test category, select Unit Test Project. Name the projectSpaanjaars.ContactManager45.Tests.Unit and change the Location for the project toC:\Projects\Spaanjaars.ContactManager45\Main\Tests. By storing your test projects in the Testsfolder you separate them from the actual implementation projects that are stored in the Applicationsfolder. In the Target Framework drop-down list make sure .NET Framework 4.5 is selected. This project is going to contain the core unit tests for the Contact Manager application.

Figure 3-1 The Add New Project Dialog (click to enlarge) 3. 4. Click OK to add the project to the solution. Add another Unit Test Project to the Tests Solution Folder, name itSpaanjaars.ContactManager45.Tests.Integration and make sure its saved in the

5.

6.

7.

folderC:\Projects\Spaanjaars.ContactManager45\Main\Tests as well. This project will contain tests that are going to access the database directly. Add another Unit Test Project to the Tests Solution Folder, name itSpaanjaars.ContactManager45.Tests.Frontend.Mvc and make sure its saved in the folderC:\Projects\Spaanjaars.ContactManager45\Main\Tests. This project will contain tests that target the ASP.NET MVC 4 project. Add another Unit Test Project to the Tests Solution Folder, name itSpaanjaars.ContactManager45.Tests.Frontend.Wcf and make sure its saved in the folderC:\Projects\Spaanjaars.ContactManager45\Main\Tests. This project will contain tests that target the WCF service project. In these four new test projects, add references to the following projects in your solution: References

Project Tests.Unit

Spaanjaars.ContactManager45.Infrastructure Spaanjaars.ContactManager45.Model Spaanjaars.ContactManager45.Infrastructure Spaanjaars.ContactManager45.Model Spaanjaars.ContactManager45.Respositories.EF Spaanjaars.ContactManager45.Infrastructure Spaanjaars.ContactManager45.Model Spaanjaars.ContactManager45.Web.Mvc System.Web.Mvc (found in %programfiles(x86)%\Microsoft ASP.NET\ASP.NET MVC 4\Assemblies by default) Spaanjaars.ContactManager45.Infrastructure Spaanjaars.ContactManager45.Model Spaanjaars.ContactManager45.Web.Wcf

Tests.Integration

Tests.Frontend.Mvc

Tests.Frontend.Wcf

Your Solution Explorer should now look like this:

Figure 3-2 The Solution Explorer with the new Unit Test Projects On disk your Solution should look like this in File Explorer:

Figure 3-3 File Explorer Showing the new Unit Test Projects (click to enlarge) 6. Finalize the configuration of your projects. For example, you can delete the existing default Unit Test files (called UnitTest1.cs inside each project). You can also add additional packages such asFluentAssertions (for which youll find instructions later in this article) or references to external libraries. Finally, do a full rebuild of the entire solution to ensure everything is set up correctly and resolve any compilation errors you may have.

7.

In the next section youll see how to add a simple test to three of the four Unit Test projects in order to ensure your projects, including the Infrastructure, Model and Repositories.EF projects as well as the Unit Test projects itself, have been set up correctly. In order for this to work, Ill also add a few classes to the core projects with some temporary implementation. That code will be expanded or replaced in later articles. 8. In the Model project, add a new public class called Person and give it an automatically implemented property of type int called Id. You should end up with code like this:

1 2 3 4 5 6 7

namespace Spaanjaars.ContactManager45.Model { public class Person { public int Id { get; set; } } }

9.

In the project Spaanjaars.ContactManager45.Tests.Unit add a new Unit Test file calledPersonTests.cs and modify the code as follows.

1 2

using Microsoft.VisualStudio.TestTools.UnitTesting; using Spaanjaars.ContactManager45.Model;

3 4 5 6 7 8
[TestMethod] namespace Spaanjaars.ContactManager45.Tests.Unit { [TestClass] public class PersonTests {

9 10 11 12 13 14 15 16
} }

public void NewPersonHasEmptyId() { var person = new Person(); Assert.AreEqual(0, person.Id); }

10. Run all the tests (theres only one at the moment) in the solution by pressing Ctrl+R, followed by an A (Ctrl+R, A) or by choosing Tests | Run | All Tests from the main menu. Then check the Test Explorer (which you can open using Test | Windows | Test Explorer). You should see that the test has passed:

Figure 3-4 Test Explorer Showing Success Note: You would normally write a test that fails first, to avoid ending up with false positives. You would then implement some code to make the test pass. In this case, the test is so simple (and not really meant to test the functionality of the Person class, but rather the setup of the test project itself) that I decided to write a "green test" directly. 11. Next, add a new public class called PeopleRepository.cs to theSpaanjaars.ContactManager45.Repositories.EF project. Dont forget to add public in front of the class or itll default to internal. Theres no need to add any code to the class for now. 12. In the project Spaanjaars.ContactManager45.Tests.Integration, add a new Unit Test file, call itPeopleRepositoryTests.cs and modify the code as follows:

1 2 3 4 5 6

using Microsoft.VisualStudio.TestTools.UnitTesting; using Spaanjaars.ContactManager45.Repositories.EF;

namespace Spaanjaars.ContactManager45.Tests.Integration { [TestClass]

7 8 9 10 11 12 13 14

public class PeopleRepositoryTests { [TestMethod] public void CanInstantiatePeopleRepository() { var peopleRepository = new PeopleRepository(); Assert.IsNotNull(peopleRepository); } }

15
}

16
Note: this is a pretty useless test. You should have other tests that implicitly check whether you can instantiate a new PeopleRepository class and then work with that instance. However, for now this test is useful to make sure that the Integration project has the correct references to the Repositories.EF project. 13. Press Ctrl+R, A again. Both tests should pass. 14. In the test project Spaanjaars.ContactManager45.Tests.Frontend.Mvc add a new Unit Test file calledHomeControllerTests.cs and modify its code as follows:

1 2 3 4 5 6 7 8

using System.Web.Mvc; using Microsoft.VisualStudio.TestTools.UnitTesting; using Spaanjaars.ContactManager45.Web.Mvc.Controllers;

namespace Spaanjaars.ContactManager45.Tests.Frontend.Mvc { [TestClass] public class HomeControllerTests

9 10 11 12 13

{ [TestMethod] public void IndexHasNoModel() { var controller = new HomeController(); var result = controller.Index() as ViewResult;

14 15 16 17 18
} } }

Assert.AreEqual(null, result.Model);

15. Press Ctrl+R, A once more. All three tests should now pass, as shown in Figure 3-5:

Figure 3-5 Test Explorer Showing Green Tests For now, these tests are really simple and only serve to verify the setup and relationships between the various projects. I skipped the tests for the WCF service as the current project doesnt have any code files and adding a WCF service requires more background which Ill cover in Part 8 of this series. Ill be adding more tests to the test projects as I progress through this article series. I wont show you the code for all of the tests though; Ill only highlight some of the more important ones. Youre encouraged to check out the source code that comes with this article series to see all the tests.

Using Fluent Assertions


There are a number of open source frameworks available that make unit tests easier to read and more obvious. One of those frameworks is FluentAssertions created by Dennis Doomen. This framework allows you write the assertions for your test in a fluent way. E.g. rather than writing something like this:

Assert.AreEqual(3, id);

You can now write something like this:

id.Should().Be(3);

Although you may need to get used to this new syntax at first, I generally find it more intuitive to read. Its very useful to quickly see what your tests do but more importantly, non-technical people involved in a project can now more or less read unit tests too. This enables them to help you write the proper tests. Under the hood, the various FluentAssertions methods check your values and raise exceptions when a condition is not met. This exception is eventually caught by MS test or another test framework you may be using. In order to change your test projects to use FluentAssertions, follow these steps: 1. 2. Inside Visual Studio, open up the Package Manager Console by choosing Tools | Library Package Manager | Package Manager Console. Select your Integration test project from the Default project drop-down (calledSpaanjaars.ContactManager45.Tests.Integration if youre following along with the walkthroughs in this article series). In the Package Manager Console type Install-Package FluentAssertions and hit enter. Repeat step 2 and 3, three more times, but now add FluentAssertions to the Unit tests project, theFrontend.Mvc project and the Frontend.Wcf project. Open up the PersonTests class in the Unit Tests project and at the top of the file add the following using statement:

3. 4. 5.

1
6.

using FluentAssertions;

Change the last line of the NewPersonHasEmptyId test to the following:

1
7. 8.

person.Id.Should().Be(0);

With this change, the code almost reads like English; the ID of the new person created in code should be zero. Next, run your test(s) to see if everything still works. If they pass (and they should), you should see a nice green checkmark in the Unit Test Explorer:

Figure 3-6 Test Explorer Showing Green Tests You can find out more about FluentAssertions on the projects site at CodePlex.com:http://fluentassertions.codeplex.com/.

Stuff I Like to Do
Heres a quick list of things I like to do when it comes to unit testing:

Use FluentAssertions, as just explained. Its one of the first things I add to a Visual Studio test project. Write a base class for all your tests and let your test classes inherit from it. Even if you dont add any behavior yet, its useful to have all your test classes inherit a common base class to which you can add shared functionality as you go. In the code download youll find a base class in each of the four test projects. In the Integration tests project the base class is used to

initialize the database (generated by EF) for each set of tests. Youll see more of this in Part 5 when the database initializer is discussed. Set up an automated build in TFS to run all your tests whenever code is checked in. This is a great way to ensure your code is always in a valid state. For more details, see: Professional Team Foundation Server 2012 (Ed Blankenship et al., Wrox, 2013,http://www.wrox.com/WileyCDA/WroxTitle/Professional-Team-FoundationServer-2012.productCd-1118314093.html) http://msdn.microsoft.com/en-us/library/ms181716.aspx Consider getting a Unit Test runner such as the ones supplied by ReSharper or CodeRush. Although the test runner in Visual Studio 2012 has improved somewhat since Visual Studio 2010, I find the third party runners easier and more powerful to work with. More details can be found here: Unit Testing with CodeRush (http://www.devexpress.com/Products/Visual_Studio_Addin/Coding_Assistance/unit_test_runner.xml) Unit Testing with ReSharper (http://www.jetbrains.com/resharper/webhelp/Unit_Testing__Index.html)

Summary
In this article you saw how to add a number of different unit test projects to your solution and how to set them up. While you could technically add all your tests to a single unit test project, I prefer to create separate projects for different types of tests. This allows me to decide when to run which tests. For example, because Integration tests generally run slower than plain unit tests (because they access databases and other slow resources), I could decide to run my unit tests after each build while the integration tests are only run when I check in code into TFS. At this point, each test project contains a simple unit test that is used purely to check if the test projects were setup correctly. In later parts in this article series youll see how to add more useful tests to the different test projects. With all the plumbing done, the next step is to start building the model. In the next part in this article series youll see how to set up the model using POCO Plain Old CLR Objects - classes. That model is then used in Part 5 that describes how to build a repository that targets Entity Framework 5 Code First to interact with the database. In the articles following Part 5 Ill show you how to use the model and the repositories to build various frontend applications.

Downloads

Full source for this application in C#

Where to Next?
Wonder where to go next? You can post a comment on this article. You can read existing comments below or you can post a comment yourself on this article .

ASP.NET N-Layered Applications - Implementing a Model (Part 4)


Note: this is part four in a series of ten. If you rather read this entire series off-line, you can buy the full series as a convenient PDF document that comes with the full source. Besides the convenience, buying the PDF will also make you feel good as it shows your appreciation for the articles and helps me pay the bills for my server and hosting so I can keep running imar.spaanjaars.com and continue to provide you with great content. For more details, check outthis post that shows you how you can buy the entire series right now. This is Part 4 in a series of 10 that show you how to build N-Layered applications using ASP.NET 4.5 and Entity Framework 5 Code First. In this part youll see how to build a model using POCO classes Plain Old CLR Objects that have no dependencies to external frameworks (such as a requirement to inherit from an Entity Framework base class). In addition, you will see how to create unit tests for your POCO classes as well as lay a foundation for validation of these classes. If you havent read the earlier parts in this series yet, youre encouraged to do so first. The following list has links to all articles in this series:

Part Part Part Part Part Part Part Part Part Part

1 - Introduction 2 - Setting up the Solution in Visual Studio 3 - Making your Projects Unit Testable 4 - Implementing a Model 5 - Implementing a Repository using Entity Framework Code First (not yet published) 6 - Implementing an ASP.NET MVC 4 Frontend (not yet published) 7 - Implementing a Web Forms 4.5 Frontend (not yet published) 8 - Implementing a WCF 4.5 Frontend (not yet published) 9 - Importing Data Using the API (not yet published) 10 - Extensions, Tools and Wrapping Up (not yet published)

Introduction
In Part 1 of this article series you saw a brief overview of the functionality of the ContactManager application version 4.5. Most of the functionality is very similar to the design presented in the 2.0 and 3.5 versions of my N-Layered architecture articles. Because the functionality is so similar, Ill skip the requirements gathering phase. Normally, when you start a new project you dont know up front how your application and model should look. To figure out the type of application, the underlying model and the functionality, you typically have workshops with your client to gather all the requirements. These requirements then drive the design of the application and the model, which is a representation of the objects in your domain that your application is going to work with. In the 2.0 version of this series I wrote about the requirements for the ContactManager application. Youre encouraged to check out the Design - Gathering Requirements section in the original article to find out more about the model for that application. In the new series, the model I use is pretty similar, as youll see in the following sections. To learn more about how to gather requirements to design your applications and models, check out the following publications:

http://imar.spaanjaars.com/416/building-layered-web-applications-with-microsoft-aspnet-20part-1#gatheringrequirements Practicing Domain-Driven Design (Scott Millett, under development: https://leanpub.com/Practicing-DDD) Implementing Domain-driven Design (Vaughn Vernon, 2013, http://www.amazon.com/Implementing-Domain-Driven-Design-VaughnVernon/dp/0321834577/)

Based on the model from the previous article series, the application needs the following classes: Class Name Person Address EmailAddress PhoneNumber Description This This This This class class class class represents represents represents represents a contact person used to keep track of your contacts. a physical address that can be associated with a person. an e-mail address of a person. a phone number of a person.

In addition to these classes, the model also needs the following types: Type Name PersonType ContactType People EmailAddresses PhoneNumbers Type Enum Enum Class Description Defines the type of a person, such as Friend, Family or Colleague. Defines the type of the e-mail addresses and phone numbers, such as Business or Personal. These classes are created to hold a collection of each of the main entities in the model. While you could use more generic collections such as List<T>, I prefer to create separate collections for each main type. You will see how to create these collections later.

The following diagram shows all of these types. Later sections of this article describe the various types in more detail, including their underlying code and place in the application.

Figure 4-1 The Class Diagram for the Model project(click to enlarge) If you look carefully at the list of types in the diagram, youll notice the collection class for Address is missing. The reason for this is that the current application doesnt need it. The person class has two properties of type address called HomeAddress and WorkAddress respectively. This is a change from the original design where a contact person could have a collection of addresses as well. Ive done this to show you the concept of Value Objects which are discussed next. Entity Framework (EF) doesnt work well with collections of Value Objects and thus I decided to add the Address class as singular properties directly on the Person class.

Where Does the Model Fit In?


The classes defined in the Model layer flow between the concrete repositories and the user interface. The UI should preferably not know anything, or at least as little as possible about the concrete repositories and should work with the repository interfaces instead. If you think back about the architecture diagram from Part 1, the Model classes would be placed between the concrete repositories and the associated interfaces and between the repository interfaces and the UI. Figure 4-2 shows the updated diagram:

Figure 4-2 Model Classes in the Architecture Diagram (click to enlarge)

Defining Your Types


Once youve identified the core types for your application, the next step is to place them in one of two groups: Entities or Value Objects, two terms that come from the Domain Driven Design language. A lot has been written about the differences between the two (see the links at the end of this section), so I

wont repeat the complete discussion here. Instead, Ill summarize the differences and explain what the differences mean for the ContactManager application. An Entity is an object that is identified by a unique ID, rather than by the value it represents. The canonical example is the Person class. If two Person instances have the same name, do you consider them to represent the same person? Most likely not, as the name would not uniquely identify the person, and theres a high probability that even though these instances contain the same name they refer to two different people in the real world. A Value Object on the other hand is identified by its properties and the values they contain. The canonical example here is Address: two instances of Address that contain the data 327 Washington Blvd Venice, California 90291 are most likely considered the same; they dont have (or need) an identity on their own. You can read more about the differences between Entities and Value Objects in the following articles:

http://stackoverflow.com/questions/75446/value-vs-entity-objects-domain-driven-design http://lostechies.com/jimmybogard/2008/05/21/entities-value-objects-aggregates-and-roots/ http://devlicio.us/blogs/casey/archive/2009/02/13/ddd-entities-and-value-objects.aspx

To make the distinction in your code between these two types, its a good idea to create two base classes that your entities can inherit from. You see how to do this next.

Creating the Infrastructure


In this section you see how to implement the Infrastructure project by creating two base classes: one for an Entity and one for a Value Object. Note: Ill show the implementation of a number of types step by step. That means that the code you see may not be the final code in the project. Creating Base Classes for Entities and Value Types A base class for an Entity requires at least an identity property which is typically called Id, although, youre free to make up another name. Since the base class should be reusable across multiple type definitions, its a good idea to make the type of this Id column generic so that classes that inherit this base class can determine the actual type (for example, an int or a Guid). The class could also have an IsTransient method that determines if the object is new (has not been assigned an ID by the underlying database) or not. To implement this base class, I added a new class file to the Spaanjaars.Infrastructure project, called it DomainEntity.cs and added the following code:

1 2 3 4 5 6 7 8 9 10

namespace Spaanjaars.Infrastructure { public abstract class DomainEntity<T> { /// <summary> /// Gets or sets the unique ID of the entity in the underlying data store. /// </summary> public T Id { get; set; }

/// <summary>

11 12 13 14 15 16 17 18 19
}

/// Checks if the current domain entity has an identity. /// </summary> /// <returns>True if the domain entity is transient (i.e. has no identity yet), /// false otherwise. /// </returns> public bool IsTransient() { return Id.Equals(default(T)); }

20
}

21
Heres the class diagram for the complete base class from the sample project. Ill discuss the members for comparison and validation later.

Figure 4-3 The DomainEntity<T> class With the base class defined, I can now modify the Person class so it inherits DomainEntity and sets the type ofId to an int. To implement that change, I modified Person in the Model project as follows:

1 2

using Spaanjaars.Infrastructure; namespace Spaanjaars.ContactManager45.Model {

3 4

public class Person : DomainEntity<int> {

5 6 7
}

Notice how I used DomainEntity<int> to define the type of the Id property as an int. I also removed the Idproperty from the Person class as it now inherits that from the DomainEntity base class. With the Person class done, I could now modify the NewPersonHasEmptyId test method so it now uses theIsTransient method instead of checking for a hard-coded value of zero:

1 2 3 4 5 6

[TestMethod] public void NewPersonHasEmptyId() { var person = new Person(); person.IsTransient().Should().BeTrue(); }

In the sample project that comes with this article series youll also see implementation code for validation inside the DomainEntity<T> class. This is discussed later in the series. Implementing a ValueObject base class is simpler as it doesnt require an identity. I added the following class called ValueObject to the Spaanjaars.Infrastructure project:

1 2 3

public abstract class ValueObject<T> where T : ValueObject<T> { }

Note the constraint on this type using the where clause. Although it seems to state the obvious, or even may cause a circular reference, this code makes sure that a class that inherits ValueObject<T> can only pass itself for the T parameter. In other words, the following is valid:

public class Address : ValueObject<Address>

because the Address type passed for the T parameter does inherit ValueObject<Address>. The following is invalid because int does not inherit ValueObject<int>:

public class Address : ValueObject<int>

Heres how the complete ValueObject class looks like:

Figure 4-4 The ValueObject<T> class Ill explain the other members of this class in this and later parts in the series when I discuss modifying these classes to implement equality comparison and validation.

Adding Properties to the Person Class


With the base class done, its time to add a few basic properties to the Person class such as a name, a type and date of birth. Later in this article Ill modify Person once more when I add properties for the various contact details. Before I show you the new Person class, first take a look at the two enumerations that I introduced in the beginning of this article to define the type of a person and of a contact record. I added two new enums to a newEnums folder inside the Model project and completed them with the following code:

1 2 3 4 5 6

namespace Spaanjaars.ContactManager45.Model { /// <summary> /// Determines the type of a contact person. /// </summary> public enum PersonType {

7 8 9 10 11 12 13

/// <summary> /// Indicates an unidentified value. /// </summary> None = 0,

/// <summary> /// Indicates a friend.

14 15 16 17 18 19

/// </summary> Friend = 1,

/// <summary> /// Indicates a family member. /// </summary> Family = 2,

20 21 22 23 24 25 26 27 28 29 30
/// Determines the type of a contact record. namespace Spaanjaars.ContactManager45.Model { /// <summary> } } /// <summary> /// Indicates a coworker. /// </summary> Colleague = 3

31 32 33 34 35 36 37 38 39 40

/// </summary> public enum ContactType { /// <summary> /// Indicates an unidentified value. /// </summary> None = 0,

/// <summary> /// Indicates a business contact record.

41 42 43 44 45 46

/// </summary> Business = 1,

/// <summary> /// Indicates a personal contact record. /// </summary> Personal = 2

47 48 49 50 51 52
}

Enum support for Entity Framework Code First has been added in version 5. Its a very useful (and much needed) addition to the framework, as using enums is quite common. The cool thing about enums in EF is that it just works. You dont have to define any special behaviors for your enums to roundtrip to the database correctly. With the enums done, I completed the Person class as follows:

1 2 3 4 5 6 7 8 9 10 11 12

using System; using Spaanjaars.Infrastructure;

namespace Spaanjaars.ContactManager45.Model { public class Person : DomainEntity<int> { public string FirstName { get; set; } public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public PersonType Type { get; set; } } }

13
Here's how its Class Diagram looks:

Figure 4-5 The Person Class NOTE: throughout the model classes youll find attributes on properties like this:

1 2

[Required] public string FirstName { get; set; }

This marks the first name of a person as being required. These attributes are supported by EF, but it also has an alternative available in the form of the Fluent API that enables you to configure your business rules like a required field, a maximum length and so on, at the DbContext level rather than at the entity level. This way you can centralize your business rules and keep the entity classes really clean. This is just a preference though; many of the validation rules set by the API can just as well be applied using data annotation attributes such as the Required attribute. Since the Fluent API requires a DbContext, you need to create one first. The sections Building the Object Context and Configuring your models business rules in Part 5 will have more details. I typically apply low level attributes like Required at the class level, and define database specific information (such as the length of a field) in the configuration of EF. Notice how the name of the person consists of a first name and a last name. In many places in the application the full name of the user is displayed, so it makes sense to make a (read-only) property for that. Before I implemented the property, I first wrote the following unit tests in the PersonTests class in the Unit Tests project:

1 2 3 4

[TestMethod] public void FirstAndLastNameResultsInFullName() { var person = new Person() { FirstName= "Imar", LastName= "Spaanjaars" }; person.FullName.Should().Be("Imar Spaanjaars");

5 6 7 8 9

[TestMethod] public void EmptyFirstNameReturnsLastName() {

10 11 12 13 14 15
{ }

var person = new Person() { LastName = "Spaanjaars" }; person.FullName.Should().Be("Spaanjaars");

[TestMethod] public void EmptyLastNameReturnsFirstName()

16 17 18 19 20 21 22 23 24
} }

var person = new Person() { FirstName = "Imar" }; person.FullName.Should().Be("Imar");

[TestMethod] public void AllEmptyReturnsEmpty() { var person = new Person(); person.FullName.Should().Be(string.Empty);

25 26 27
I did not write all tests before I added the FullName property. I initially wrote the first test, and then used my refactoring tool to implement the FullName property and have it throw a NotImplementedException. I then completed all the other tests and implemented the property. Finally, I ran all tests to make sure they ran successfully. I needed a few refactoring steps before the code was working as expected. In your own projects, the order of tests and implementation may vary from topic to topic. I am not a strict test driven developer and sometimes write the implementation first, followed by a bunch of tests to validate my code works correctly. However, it can often be very beneficial to write tests before you write implementation, so you can focus on the What (the public API of your code) rather than on the How (the actual implementation). These tests ensure that the FullName property returns logical data, even if one of the fields (or both) is missing. Since a completely empty name doesnt make a lot of sense, youll want to make one of these (or both) a required field. Youll see later how it is done in Part 5 of this series. With the unit tests done, I implemented the property as follows:

public string FullName

2 3 4 5 6

get { string temp = FirstName ?? string.Empty; if (!string.IsNullOrEmpty(LastName)) { if (temp.Length > 0)

7 8 9 10 11 12 13 14 15 16
} } }

{ temp += " "; } temp += LastName;

return temp;

Since this is a read-only property, EF will ignore it and it wont be persisted in the database. With the basics of the Person class done, the next step is to add classes for the contact detail records. Once those are done, Ill revisit the Person class again and add properties for addresses, phone numbers and e-mail addresses.

Adding the Contact Detail Classes


As you saw earlier in this article, the Person class has a few properties that contain contact information. For the contact data, the project needs the following three classes:

Address PhoneNumber EmailAddress

For this article series, I implemented Address as a ValueObject and the other two as entities. You could argue that PhoneNumber and EmailAddress are great candidates for Value Objects and I would fully agree. However, I want to implement these types as collections (so you can have multiple instances of each attached to a contact person). To implement this one to many relationship in EF, the other end (i.e. the PhoneNumber and theEmailAddress) needs to have its own identity (e.g. an Id property). That conflicts with the absence of an identity in a ValueObject, and as such PhoneNumber and EmailAddress are implemented as entities. For these three classes, the sample project contains the following code:

1 2

// PhoneNumber using Spaanjaars.Infrastructure;

3 4 5 6 7 8
public string Number { get; set; } namespace Spaanjaars.ContactManager45.Model { public class PhoneNumber : DomainEntity<int> { [Required]

9 10 11 12 13 14 15 16 17 18 19
} }

public ContactType { get; set; } public Person Owner { get; set; } public int OwnerId { get; set; }

// EmailAddress using Spaanjaars.Infrastructure;

namespace Spaanjaars.ContactManager45.Model { public class EmailAddress : DomainEntity<int>

20 21 22 23 24 25 26 27 28 29
}

{ [Required] [EmailAddressAttribute] public string EmailAddressText { get; set; } public ContactType { get; set; } public Person Owner { get; set; } public int OwnerId { get; set; } }

30 31 32 33 34 35

// Address using Spaanjaars.Infrastructure;

namespace Spaanjaars.ContactManager45.Model { public class Address : ValueObject<Address>, IValidatableObject {

36 37 38 39 40 41 42 43 44 45

private Address() { }

public Address(string street, string city, string zipCode, string country, ContactType contactType) { Street = street; City = city; ZipCode = zipCode; Country = country; ContactType = contactType; }

46 47 48 49 50 51 52 53 54 55 56
public bool IsNull { get { return (string.IsNullOrEmpty(Street) && public string Street { get; private set; } public string ZipCode { get; private set; } public string City { get; private set; } public string Country { get; private set; } public ContactType { get; private set; }

57 58 59 60 61 62 63 64 65 66

string.IsNullOrEmpty(ZipCode) && string.IsNullOrEmpty(City) && string.IsNullOrEmpty(Country)); } } } }

EmailAddress and PhoneNumber participate in a one to many relationship: one Person can have zero to many instances of type EmailAddress and PhoneNumber. To create the relationship, I added the Owner property to these two classes. This way you can assign a person to these classes and link back to the Person from anEmailAddress or PhoneNumber. Besides the Ower property, I also added an OwnerId property of type int. EF supports "foreign key properties" which let you assign one entity to another simply by using its ID. So for example, rather than doing this:

1 2

var emailAddress = new EmailAddress { ... }; emailAddress.Owner = _personRepository.FindById(123);

you can assign the ID directly like this:

1 2

var emailAddress = new EmailAddress { ... }; emailAddress.OwnerId = 123;

This could save you from an additional call to the database when you only have the person's ID available (for example, when creating a new EmailAddress in a Web Form where the ID of the person is passed in the query string). Obviously, you can still assign the Owner property a value if you happen to have a valid instance of Person. The class diagram for the three classes with contact details looks as follows:

Figure 4-6 The Address, EmailAddress and PhoneNumber classes Note: The IHasOwner interface and Validate methods are discussed later in this article. EmailAddress and PhoneNumber inherit DomainEntity<int> which gives them an Id property of type int.Address inherits ValueObject<Address> which makes it a value object. For value objects, its a good practice to make them immutable. That means that once youve created an instance of an object and filled it with data through the constructor, you shouldnt be able to change it anymore. This is easily accomplished with a constructor that has parameters for all properties of the class, like this:

1 2 3 4 5 6 7 8

public Address(string street, string city, string zipCode, string country, ContactType contactType) { Street = street; City = city; ZipCode = zipCode; Country = country; ContactType = contactType; }

9
In addition, the setters of the properties have been marked private so they are only accessible from within the class:

public string Street { get; private set; }

And finally, in order for the Entity Framework to create instances of Address, it needs a parameterless constructor. This breaks the POCO requirements somewhat as you must implement this constructor to support EF. However, the constructor can be made private, so its not accessible by regular external code.

private Address() { }

Personally, I am fine with this requirement as I feel it doesnt break my model design. Dealing with Collections When dealing with collections and Entity Framework, theres something to be aware off. When you add entities to a collection that is tracked by Entity Framework (for example, because the parent of the collection has been added to the context) they are automatically added to the context and thus to the database. Consider this example:

1 2 3 4

var person = new Person(); person.EmailAddresses.Add(new EmailAddress { EmailAddressText = "imar@spaanjaars.com" }); myContext.People.Add(person); myContext.SaveChanges();

When this code executes, EF inserts two new records: one in the Person table and one in the EmailAddressestable. The row in the EmailAddresses table will have a foreign key pointing to the Person table (if this is all new to you, dont worry yet; Ill dig deeper into this in Part 5). However, if you try to remove an EmailAddress, things work a bit differently. Consider this code:

1 2 3

var person = myContext.People.First(x => x.Id = id); person.EmailAddresses.Clear(); myContext.SaveChanges();

This code retrieves an existing person, clears the EmailAddresses collection and then saves the changes. What you might expect to happen is that the e-mail addresses that were previously assigned to the person are actually deleted from the database. This is, however, not the case. The only thing that happens is that EF clears the foreign key that points to the person. In other words, the e-mail address itself is not deleted from the database; it just no longer points to the Person row. If you Google for this problem you find many solutions that show you how to mark the EmailAddress objects as deleted by setting their EntityState property to Deleted. However, as youll see later, you wont have direct access to the EF data context from the locations where youre removing e-mail addresses from the PersonsEmailAddresses collection. This is, however, relatively easy to fix in the DbContext itself as youll see in Part 5. In order for the DbContext to understand which objects it should remove, you can let these entities implement a custom interface that you can detect in the DbContext and take the appropriate action. Again, Part 5 shows how to implement the code in the DbContext so for now Ill just show you the interface that the removable objects implement:

1 2 3 4 5 6 7

public interface IHasOwner { /// <summary> /// The Person instance this object belongs to. /// </summary> Person Owner { get; set; } }

EmailAddress and PhoneNumber then implement this interface:

1 2 3 4 5 6 7

public class EmailAddress : DomainEntity<int>, IHasOwner { }

public class PhoneNumber : DomainEntity<int>, IHasOwner { }

The interface is implemented by the Owner property (shown earlier) in each of the two classes. Youll see this interface again in Part 5. If you look in the sample code that comes with this article series, youll notice that these classes contain more code. Most of that code is related to validation, which is discussed in Part 5. With the classes added to the project, I could write a few simple unit tests that demonstrate I can instantiate these classes and set their properties. However, most of that would come down to testing the .NET framework (do property getters and setters work for example) rather than testing my own code. Ill write unit and integration tests for these classes later to test concepts like validation, which should implicitly cover instantiating and using these objects. Therefore, I am not adding any more tests for now.

Implementing Equality Comparison


When working with a model, youre going to need the ability to compare two instances of a class in your model with each other. You could have an instance of a Person that you want to compare with an existing instance that is being submitted to your application using a WCF service for example. Or you may want to see if a persons personal address is the same has her business address. The default implementation for comparison of classes in .NET is to use reference equality; in other words, .NET checks if two references are pointing to the same object. Consider this example (which you find in thePersonTests class inside the Unit Tests project):

1 2 3 4 5 6 7

[TestMethod] public void TwoPeopleWithSameIdAreTheSame() { var person1 = new Person { Id = 1, FirstName = "Imar", LastName = "Spaanjaars" }; var person2 = new Person { Id = 1, FirstName = "Imar", LastName = "Spaanjaars" }; (person1 == person2).Should().BeTrue(); }

When you run this test now, it fails. The variables person1 and person2 are referring to two different instances of Person. This means that the equality check (==) returns false. However, it would make perfect sense if the check returned true since Person is an Entity whose identity and uniqueness is defined by the Id property. Both Person instances have the same ID, so from an application perspective, they should be considered the same.

In contrast, two Addresses (implemented as Value Types) should be considered the same when the values for all of their properties match. Consider this test (that I added to the AddressTests class inside the Unit Tests project):

1 2 3 4 5 6 7

[TestMethod] public void TwoIdenticalAddressesShouldBeTheSame() { var address1 = new Address("Street", "City", "ZipCode", "Country", ContactType.Business); var address2 = new Address("Street", "City", "ZipCode", "Country", ContactType.Business); (address1 == address2).Should().BeTrue(); }

Again, when you run this test it would fail. The variables address1 and address2 each refer to a different instance. The default of the == operator for objects is to check reference equality, and so these two objects are not considered the same. To fix these issues, and have .NET consider your entities to be the same if they have the same ID and consider your Value Objects to be the same when all of their properties match, you need to override Equals and the equality and inequality operators (== and !=). For both implementations, I borrowed code from the Domain Oriented N-Layered .NET 4.0 Sample App (athttp://microsoftnlayerapp.codeplex.com/), a sample application and reference guide for implementing N-Layered applications in .NET. While there is some overlap between this guide and mine, youll find the Microsoft version is more complex and extensive, and much more geared towards large enterprise-scale applications. Their sample application contains an implementation to compare Value Objects that uses reflection if necessary. Implementing their code into my ValueObject<T> class results in the following code:

1 2 3 4 5 6

public abstract class ValueObject<T> : IEquatable<T> where T : ValueObject<T>, IValidatableObject { public abstract IEnumerable<ValidationResult> Validate( ValidationContext validationContext);

public IEnumerable<ValidationResult> Validate()

7 8 9 10 11

{ var validationErrors = new List<ValidationResult>(); var ctx = new ValidationContext(this, null, null); Validator.TryValidateObject(this, ctx, validationErrors, true); return validationErrors;

12 13 14 15 16 17

private bool CheckValue(PropertyInfo p, T other) { var left = p.GetValue(this, null); var right = p.GetValue(other, null); if (left == null || right == null)

18 19 20 21 22 23 24 25 26
}

{ return false; }

if (typeof(T).IsAssignableFrom(left.GetType())) { return ReferenceEquals(left, right); } return left.Equals(right);

27 28
public bool Equals(T other)

29 30 31 32 33 34 35 36 37 38

{ if ((object)other == null) { return false; }

if (ReferenceEquals(this, other)) { return true; }

39 40 41 42 43 44 45
} if (publicProperties.Any()) { return publicProperties.All(p => CheckValue(p, other)); //compare all public properties PropertyInfo[] publicProperties = GetType().GetProperties();

46 47 48 49 50 51 52 53 54 55
}

return true;

public override bool Equals(object obj) { if ((object)obj == null) { return false; }

if (ReferenceEquals(this, obj))

56
{

57 58 59 60 61 62 63 64 65
} }

return true;

var item = obj as ValueObject<T>;

if ((object)item != null) { return Equals((T)item);

66 67 68 69 70 71
}

return false;

public override int GetHashCode() { int hashCode = 31; bool changeMultiplier = false;

72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89

int index = 1;

PropertyInfo[] publicProperties = this.GetType().GetProperties();

if (publicProperties.Any()) { foreach (var item in publicProperties) { object value = item.GetValue(this, null);

if ((object)value != null) { hashCode = hashCode * ((changeMultiplier) ? 59 : 114) + value.GetHashCode(); changeMultiplier = !changeMultiplier; } else { hashCode = hashCode ^ (index * 13); //only for support {"a",null,null,"a"} <>

90 91 92

{null,"a","a",null} } }

93 94 95 96 97 98
}

} return hashCode;

public static bool operator ==(ValueObject<T> left, ValueObject<T> right) { if (Equals(left, null))

99 100 101 102 103 104 105 106 107


} }

{ return (Equals(right, null)) ? true : false; } return left.Equals(right);

public static bool operator !=(ValueObject<T> left, ValueObject<T> right) { return !(left == right);

108
}

109 110 111 112 113 114 115 116


This code contains a version of Equals that checks if the value compared against is null. If its not, it then checks if both sides are referring to the same instance, and if thats not the case, it uses reflection to compare each individual property. It also overrides the == (equals) and != (not equals) operators by calling the Equalsmethod. Finally, it overrides GetHashCode to generate a value for the object used in hash tables, again using reflection. If you dont like the reflection implementation, you can always override Equals (object obj) in the Addressclass (or any other class that inherits ValueObject) and compare its properties directly.

The DomainEntity base class requires a slightly different approach: it only needs to compare the IDs of the two objects, taking nullability and a transient state into account as well. Heres the full implementation of that class:

1 2 3 4 5 6

public abstract class DomainEntity<T> : IValidatableObject { public T Id { get; set; }

public bool IsTransient() { return Id.Equals(default(T));

7 8 9 10 11 12 13 14 15 16 17 18

public override bool Equals(object obj) { if (obj == null || !(obj is DomainEntity<T>)) { return false; }

if (ReferenceEquals(this, obj)) { return true; }

19 20 21 22 23 24 25
} if (item.IsTransient() || IsTransient()) { return false; var item = (DomainEntity<T>)obj;

26 27 28 29 30 31
}

return item.Id.Equals(Id);

public override int GetHashCode() { if (!IsTransient()) {

32 33 34 35 36 37 38 39 40 41
} }

return Id.GetHashCode() ^ 31;

return base.GetHashCode();

public static bool operator ==(DomainEntity<T> left, DomainEntity<T> right) { if (Equals(left, null)) return (Equals(right, null)) ? true : false; else return left.Equals(right);

42 43 44 45 46 47 48 49 50 51 52

public static bool operator !=(DomainEntity<T> left, DomainEntity<T> right) { return !(left == right); }

public abstract IEnumerable<ValidationResult> Validate( ValidationContext validationContext);

public IEnumerable<ValidationResult> Validate()

53 54 55 56 57

{ var validationErrors = new List<ValidationResult>(); var ctx = new ValidationContext(this, null, null); Validator.TryValidateObject(this, ctx, validationErrors, true); return validationErrors; }

58 59 60 61 62 63

Again, Equals checks if the other side is null or not a DomainObject<T> (in which case they should never be considered the same). It also checks if the two references are not actually the same instance. If thats not the case, the code checks if one of the objects (or both) is in a transient state:

1 2 3 4

if (item.IsTransient() || IsTransient()) { return false; }

If one of them (or both) is transient, the code assumes they are not equal. This is necessary when creating new objects. Without that check, all new objects that havent saved in the database would be considered equal which of course is not correct. If none of the conditions above are met, the code checks the Id property of both objects. If they are the same, the objects are considered equal. Otherwise they are considered to be different. The following set of Unit Tests demonstrate the behavior of this implementation. These are just a few samples to show the general concept; the code that comes with this article has other tests to cover additional scenarios. The following piece of code shows some of the tests for the DomainEntity classes:

1 2 3 4 5

[TestClass] public class DomainEntityTests { #region Nested helper classes

6 7 8 9 10 11

internal class PersonWithIntAsId : DomainEntity<int> { }

internal class PersonWithGuidAsId : DomainEntity<Guid> { }

#endregion

12 13
[TestMethod]

14 15 16 17 18 19 20 21 22 23

public void TransientLeftIsNotEqual() { var personLeft = new PersonWithIntAsId(); var personRight = new PersonWithIntAsId { Id = 1 }; personLeft.Equals(personRight).Should().BeFalse(); }

[TestMethod] public void TwoTransientsAreNotEqual() { var personLeft = new PersonWithIntAsId();

24 25 26 27 28 29 30 31 32
}

var personRight = new PersonWithIntAsId(); personLeft.Equals(personRight).Should().BeFalse();

[TestMethod] public void NewPersonWithIntAsIdIsTransient() { var person = new PersonWithIntAsId(); person.IsTransient().Should().BeTrue();

33 34 35 36 37 38

[TestMethod] public void PersonWithIntAsIdWithValueIsNotTransient() { var person = new PersonWithIntAsId { Id = 4 }; person.IsTransient().Should().BeFalse();

39 40 41 42 43 44 45 46 47 48 49

[TestMethod] public void NewPersonWithGuidAsIdIsTransient() { var person = new PersonWithGuidAsId(); person.IsTransient().Should().BeTrue(); }

[TestMethod] public void PersonWithGuidAsIdWithValueIsNotTransient() {

50 51 52 53 54 55 56 57 58 59
}

var person = new PersonWithGuidAsId { Id = Guid.NewGuid() }; person.IsTransient().Should().BeFalse();

[TestMethod()] public void EntitiesWithSameIdentityShouldBeEqual() { var entityLeft = new PersonWithIntAsId { Id = 1 }; var entityRight = new PersonWithIntAsId { Id = 1 };

60 61 62 63 64
}

bool resultOnEquals = entityLeft.Equals(entityRight); bool resultOnOperator = entityLeft == entityRight;

resultOnEquals.Should().BeTrue(); resultOnOperator.Should().BeTrue();

65
}

66 67 68 69 70
Similarly, I have tests for the ValueObject class. In the examples below, I use the Address class (that inheritsValueObject) but in the code download you find a few other tests as well.

1 2 3 4 5 6 7 8 9 10

[TestClass] public class AddressTests { [TestMethod] public void TwoIdenticalAddressesShouldBeTheSame() { var address1 = new Address("Street", "City", "ZipCode", "Country", ContactType.Business); var address2 = new Address("Street", "City", "ZipCode", "Country", ContactType.Business); (address1 == address2).Should().BeTrue(); }

11 12 13 14 15
[TestMethod] public void DifferentAddressesShouldNotBeTheSame() { var address1 = new Address("Some other street", "City", "ZipCode",

16 17 18 19 20 21 22 23 24 25 26

"Country", ContactType.Business); var address2 = new Address("Street", "City", "ZipCode", "Country", ContactType.Business); (address1 != address2).Should().BeTrue(); }

[TestMethod] public void InstanceOfValueObjectDoesNotEqualNull() { var address1 = new Address(); address1.Equals(null).Should().BeFalse(); }

27 28 29 30 31 32 33 34 35
} } [TestMethod] public void ReferenceEqualsIsEqual() { var address1 = new Address("Street", "City", "ZipCode", "Country", ContactType.Business); Address address2 = address1; address1.Equals(address2).Should().BeTrue();

With the tests added to the Unit Test project, the next step is modelling collections.

Creating Collections
When modelling collections, you have a few different options. For example, its quite common to use a List<T>class to store collections of objects. Using that class, you could give Person access to a collection ofEmailAddress instances like this:

public class Person : DomainEntity<int>

1
{

2 3

public string FirstName { get; set; }

4 5 6 7 8
}

// Other properties here

public List<EmailAddress> EmailAddresses { get; set; }

You can then add instances of EmailAddress to the EmailAddresses collection like this:

1 2 3

var person = new Person(); person.EmailAddresses.Add(new EmailAddress {ContactType = ContactType.Business, EmailAddressText = "someone@example.com"});

While this works great, its generally not recommended to expose List<T> in the public API of a class. List<T>is designed for performance, and not meant for inheritance. This means you cant override any of its members that change the way the class behaves when it comes to adding, finding and removing members. This makes it impossible to add specialized behavior to your collection; something you often want to do. More information about this guideline can be found here:http://msdn.microsoft.com/en-us/library/ms182142%28v=vs.110%29.aspx It is recommended that you implement a class that inherits Collection<T> instead, which is what I have done in the sample project. The downside of inheriting that class is that you miss out on some of the useful functionality that List<T> has. For example, Collection<T> does not have a method to sort the data, or to quickly add a range. However, that behavior is easy to add to a base class, so the other collections in your project can get it for free. In the Spaanjaars.ContactManager application, I have added the followingCollectionBase<T> class:

1 2 3 4 5 6 7 8 9 10 11 12

public abstract class CollectionBase<T> : Collection<T>, IList<T> { protected CollectionBase() : base(new List<T>()) { }

protected CollectionBase(IList<T> initialList) : base(initialList) { }

protected CollectionBase(CollectionBase<T> initialList) : base(initialList) { }

public void Sort(IComparer<T> comparer) { var list = Items as List<T>; if (list != null)

13 14 15 16 17
}

{ list.Sort(comparer); }

public void Sort()

18
{

19 20 21 22 23 24 25 26 27 28
}

var list = Items as List<T>; if (list != null) { list.Sort(); }

public void AddRange(IEnumerable<T> collection) { if (collection == null) {

29 30 31 32 33 34

throw new ArgumentNullException("collection", "Parameter collection is null."); } foreach (var item in collection) { Add(item); }

35 36 37 38
}

The class is marked as abstract which means you cant create instances of it directly. Its sole purpose is to serve as a base class for other collections. It inherits Collection<T> as per the recommendation which gives it virtual members such as InsertItem, RemoveItem, SetItem and ClearItems. Notice

that Collection<T>implements the IList<T> interface so you can pass instances of classes that inherit Collection<T> to any member that expects an IList<T>. The class has three constructors that all call the base constructor with an initial list. Notice how the default constructor calls the base constructor with a new instance of List<T>:

1 2 3

protected CollectionBase() : base(new List<T>()) { }

Although you shouldnt expose members of List<T> in your public API, its perfectly OK to use one internally. Besides the constructors, the class exposes two methods to sort the underlying data and a method to add ranges of instances with a single call:

1 2 3 4 5 6 7 8 9

public void Sort(IComparer<T> comparer) { var list = Items as List<T>; if (list != null) { list.Sort(comparer); } }

public void Sort()

10 11 12 13 14 15 16 17 18 19

{ var list = Items as List<T>; if (list != null) { list.Sort(); } }

public void AddRange(IEnumerable<T> collection) {

20 21 22 23 24 25 26 27 28 29
}

if (collection == null) { throw new ArgumentNullException("collection", "Parameter collection is null."); } foreach (var item in collection) { Add(item); }

This base class is used by all collections in the project: for People, EmailAddresses, and PhoneNumbers. Heres an example of the EmailAddresses collection:

1
namespace Spaanjaars.ContactManager45.Model.Collections

2
{

3 4 5 6 7 8 9 10 11 12 13

public class EmailAddresses : CollectionBase<EmailAddress> { public EmailAddresses() { }

public EmailAddresses(IList<EmailAddress> initialList) : base(initialList) { }

public EmailAddresses(CollectionBase<EmailAddress> initialList) : base(initialList) { } }

14 15

With this class in the project, the Person class can now be rewritten like this:

1 2 3 4 5 6 7 8 9 10 11 12

public class Person : DomainEntity<int> { public Person() { EmailAddresses = new EmailAddresses(); }

public string FirstName { get; set; }

// Other properties here

public EmailAddresses EmailAddresses { get; set; } }

13
Notice how the code for the property now refers to EmailAddresses twice: the first reference is the collections type, the second one the name of the property. I also instantiate a new instance of this class in the Person's constructor so it's ready for use. Adding instances of EmailAddress remains the same:

1 2 3

var person = new Person(); person.EmailAddresses.Add(new EmailAddress {ContactType = ContactType.Business, EmailAddressText = "someone@example.com"});

What I like about this setup is that its now very easy to add specialized behavior to these collections. Rather than forcing users of your API to manually construct and initialize an EmailAddress, you could add a convenience method for Add on the EmailAddresses collection like this:

1 2 3 4

public void Add(string emailAddressText, ContactType contactType) { Add(new EmailAddress { ContactType = contactType, EmailAddressText = emailAddressText }); }

Adding an e-mail address can now be as simple as this:

Person person = new Person();

person.EmailAddresses.Add("imar@spaanjaars.com", ContactType.Business);

Once I added the collection classes to the project, I was able to write tests like the following to verify the behavior of the AddRange and Sort methods:

1 2 3 4 5 6 7 8

using System; using System.Collections.Generic; using System.Linq; using FluentAssertions; using Microsoft.VisualStudio.TestTools.UnitTesting; using Spaanjaars.ContactManager45.Model; using Spaanjaars.ContactManager45.Model.Collections;

namespace Spaanjaars.ContactManager45.Tests.Unit

9 10 11 12 13 14 15 16 17

{ [TestClass] public class CollectionBaseTests { [TestMethod] public void NewCollectionUsingNewListsAddsValues() { var collection = new IntCollection(new List<int> { 1, 2, 3 }); collection.Count.Should().Be(3); }

18 19 20 21 22 23 24 25
} [TestMethod] public void NewCollectionUsingExistingCollectionAddsValues() { var collection1 = new IntCollection(new List<int> { 1, 2, 3 }); var collection2 = new IntCollection(collection1); collection2.Count.Should().Be(3);

26 27 28 29 30 31
collection2.AddRange(collection1); [TestMethod] public void UsingAddRangeAddsValues() { var collection1 = new IntCollection(new List<int> { 1, 2, 3 }); var collection2 = new IntCollection();

32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
} }); }

collection2.Count.Should().Be(3);

[TestMethod] public void SortPeopleWithSpecifiedComparerSortsCorrectly() { var people = new People(); people.Add(new Person { FirstName = "John", LastName = "Doe" }); people.Add(new Person { FirstName = "Imar", LastName = "Spaanjaars"

people.Add(new Person { FirstName = "Jane", LastName = "Doe" });

people.Sort(new PersonComparer());

people[0].FullName.Should().Be("Imar Spaanjaars"); people[1].FullName.Should().Be("Jane Doe"); people[2].FullName.Should().Be("John Doe");

[TestMethod]

50
public void SortIntsSorts()

51 52

{ var ints = new IntCollection { 3, 2, 1 };

53 54 55 56
}

ints.Sort(); ints[0].Should().Be(1); ints[1].Should().Be(2); ints[2].Should().Be(3);

57
}

58 59 60 61 62 63 64 65 66 67 68 69
{ } public IntCollection(CollectionBase<int> initialList) : base(initialList) public IntCollection(IList<int> initialList) : base(initialList) { } internal class IntCollection : CollectionBase<int> { public IntCollection() { }

70 71 72 73 74 75 76 77 78 79
}

public class PersonComparer : IComparer<Person> { public int Compare(Person x, Person y) { return x.FullName.CompareTo(y.FullName); } }

80 81 82 83 84 85
Most of this is pretty straight forward, and by looking at the test name and implementation you should be able to see what the code is testing. I added a helper class called IntCollection to test the Sort behavior for classes that implement IComparable (which makes it possible to sort a collection of a type without specifying a specialComparer classes). The thing that may be new to you is the PersonComparer, a class dedicated to defining how instances of Personshould be sorted. In this implementation, they are sorted on their FullName property, but you could of course change that if you want by changing the implementation of the Compare method or by implementing a completely different Comparer class altogether. Using this implementation of PersonComparer, you can sort a collection of people like this:

1 2 3 4 5

var people = new People(); people.Add(new Person { FirstName = "John", LastName = "Doe" }); people.Add(new Person { FirstName = "Imar", LastName = "Spaanjaars" }); people.Add(new Person { FirstName = "Jane", LastName = "Doe" }); people.Sort(new PersonComparer());

After this code has run, the collection now contains the people ordered by their full name, which means my name is listed first, followed by Jane and Joe. The final thing I like to implement in my model is the ability to automatically keep track of the date and time objects were created and modified. Youll see how I implemented this in the model next, while th e article on building an Entity Framework repository shows how to automatically update these dates and save them in the database.

Automatic Tracking of Creation and Modification Dates


Its common that you want to keep track of the date and time an object was created and last modified. To this end, you could add two DateTime properties to each class that you want to track like this:

1 2 3 4 5 6

public class Person : DomainEntity<int> { // Other properties here. public DateTime DateCreated { get; set; } public DateTime DateModified { get; set; } }

Then whenever you create a new instance of Person, you can fill in the DateCreated using a constructor:

1 2 3 4 5 6 7

public class Person : DomainEntity<int>, IDateTracking { public Person() { DateCreated = DateTime.Now; } }

In addition, whenever youre modifying an instance of Person, you can update the DateModified property:

myPerson.DateModified = DateTime.Now;

However, this gets repetitive and boring after a while and because you need to do this every time you make a change to a person, theres a fair chance you forget to implement this code. I prefer a different solution to the problem that works like this: 1. 2. 3. I create an interface called IDateTracking that defines two read/write properties for the date and time an object was created and last modified. I let each of the objects I want to track implement this interface and add the two properties to the class to satisfy the contract specified by this interface. In my Entity Framework DbContext that saves new and modified objects to the database, I detect objects that implement this interface and then automatically update the correct properties with the current date and time.

Implementing step 1 and 2 is really easy; youll see how to do this next. Step 3 is discussed in the next article in this series when the EF DbContext is discussed. Heres the code for the interface I added to the Model project and namespace:

1 2 3 4 5 6 7 8

using System;

namespace Spaanjaars.ContactManager45.Model { /// <summary> /// Defines an interface for objects whose creation and modified /// dates are kept track of automatically. /// </summary> public interface IDateTracking

9 10 11 12 13 14

{ /// <summary> /// Gets or sets the date the object was created. /// </summary> DateTime DateCreated { get; set; }

/// <summary>

15 16 17 18 19 20 21
} }

/// Gets or sets the date the object was last modified. /// </summary> DateTime DateModified { get; set; }

This interface defines two read/write properties for the creation and modification dates. Implementing this interface in an entity is straightforward as well. Heres the code for the Person class:

1 2 3 4 5 6 7

public class Person : DomainEntity<int>, IDateTracking { // Other code here

public DateTime DateCreated { get; set; } public DateTime DateModified { get; set; } }

You can now assign DateCreated a value in the constructor to keep track of the date an object was created. When an existing data is retrieved from the database, that property is overwritten with the value from the database, giving you the correct date and time. You can now also manually set the DateModified property whenever you change the object. However, as youll se e in the next article, you can let EF automatically manage these two properties for you.

Putting it All Together


So far youve seen the code for some simple classes that mostly consist of just a number of straightforward automatically implemented properties. However, in order to make the model more useful, you should create relationships between the various classes. For example, a Person should be given collection classes for the various contact details such as EmailAddress and PhoneNumber classes. Also, Person needs properties for address details such as HomeAddress and WorkAddress. To make the API easier to work with, all these properties should be instantiated in the constructor so you can access them immediately after you constructed a new Person.

Heres the revised code for the Person class with the new properties and constructor code. Note: the code that comes with the article has full XML comments on all public members.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26

using System; using System.Collections.Generic; using Spaanjaars.ContactManager45.Model.Collections; using Spaanjaars.Infrastructure;

namespace Spaanjaars.ContactManager45.Model { public class Person : DomainEntity<int>, IDateTracking { public Person() { EmailAddresses = new EmailAddresses(); PhoneNumbers = new PhoneNumbers(); HomeAddress = new Address(null, null, null, null, ContactType.Personal); WorkAddress = new Address(null, null, null, null, ContactType.Business); }

[Required] public string FirstName { get; set; } [Required] public string LastName { get; set; } public DateTime DateOfBirth { get; set; } public PersonType Type { get; set; } public Address HomeAddress { get; set; } public Address WorkAddress { get; set; } public EmailAddresses EmailAddresses { get; set; } public PhoneNumbers PhoneNumbers { get; set; }

27 28 29 30 31 32
if (!string.IsNullOrEmpty(LastName)) public string FullName { get { string temp = FirstName ?? string.Empty;

33 34 35 36 37 38 39 40
}

{ if (temp.Length > 0) { temp += " "; } temp += LastName; } return temp;

41
}

42 43 44 45 46
}

With this setup, you can now write tests that confirm the properties have been set up correctly (and that demonstrate the usage of the API quite nicely):

1 2 3 4 5 6

[TestMethod] public void CanAddEmailAddressToNewPerson() { var person = new Person(); person.EmailAddresses.Add(new EmailAddress()); person.EmailAddresses.Count.Should().Be(1);

7 8 9 10 11 12

[TestMethod] public void CanAddPhoneNumberToNewPerson() { var person = new Person(); person.PhoneNumbers.Add(new PhoneNumber());

13 14 15 16 17 18 19 20 21 22
} }

person.PhoneNumbers.Count.Should().Be(1);

[TestMethod] public void NewPersonHasInstantiatedWorkAddress() { var person = new Person(); person.WorkAddress.Should().NotBeNull();

[TestMethod]

23
public void NewPersonHasInstantiatedHomeAddress()

24 25 26 27 28 29

{ var person = new Person(); person.HomeAddress.Should().NotBeNull(); }

Defining Repository Interfaces


The final code that needs to be added to the Model project is the definition of the interfaces for the repositories. In Part 1 of this series I briefly introduced the IRepository<T, K> interface that defines the contract that a repository class should implement to enable CRUD (Create, Read, Update and Delete) behavior. In my project, I placed the IRepository<T, K> in the Spaanjaars.Infrastructure project, so I can easily reuse it across multiple applications. I then added the following code;

using System;

2 3 4 5 6 7

using System.Linq; using System.Linq.Expressions;

namespace Spaanjaars.Infrastructure { public interface IRepository<T, K> where T : class {

8 9 10 11 12 13 14 15 16 17

T FindById(K id, params Expression<Func<T, object>>[] includeProperties); IQueryable<T> FindAll(params Expression<Func<T, object>>[] includeProperties); IEnumerable<T> FindAll(Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties); void Add(T entity); void Remove(T entity); void Remove(K id); } }

Notice how this interface uses generics with two type parameters: T and K. T is used for the actual entity type (such as Person) while K is used for its key. The key is usually an int or a Guid. These types are then used in the interface members to define the parameter or return type of each method. Youll see a more concrete example shortly. The interface defines the following methods: Member name Add (returns void) Description Adds an object to the underlying data source. How this is done depends on the underlying framework. The EF implementation adds it to the EF DbContext so its added to the SQL Server database whenever the changes are saved. Returns all requested objects in the underlying source. One of its overloads enables you to define a search expression. Both overloads accept a parameter to define which properties you want to eager load, as youll see later. Returns an instance of T by its unique ID in case its found, or null otherwise. Removes an object from the underlying data source. How this is done depends on the underlying framework. The EF implementation removes it from the EF DbContext so its also removed from the SQL Server database whenever the changes are saved.

FindAll (returns an IQueryable of T or anIEnumerable of T)

FindById (returns an instance of T) Remove (returns void)

By implementing the Add and Remove methods of this interface you can add and remove items from the underlying data source. The Remove method has an overload that accepts the unique ID of the object to make it easy to remove an entity without having a full instance at hand. Selecting is done using FindById (that returns a single instance) and FindAll (that returns a collection). Both methods accept a params array calledincludeProperties. This is used to dynamically include related entities (such as PhoneNumbers when accessing a person.) You see how this works in the next part in this series when the EF repository is explored. The overload of FindAll that returns an IEnumerable<T> has a parameter called predicate that looks like this:Expression<Func<Person, bool>>. Although it looks pretty scary with the nested generics, using it is pretty simple. As an example, heres how you could search for all contact people of a specific type:

var colleagues = repository.FindAll(x => x.Type == PersonType.Colleague);

You can also use multiple criteria at the same time. For example:

1 2

var friendsNameMaryJane = repository.FindAll( x => x.FirstName == "Mary Jane" && x.Type == PersonType.Friend);

Youll see more of the repository implementation later. For now all thats important to realize is that the FindAllmethod lets you specify complex search criteria. Finally, updating is done by retrieving one or more existing items, and then updating the objects properties. When saving the changes using an EF DbContext, EF will automatically persist the changes into the database. For the ContactManager application, I have one class that implements this interface: a PersonRepository to manage contact people. Rather than implementing this interface directly in my repositories, I created another interface that inherits IRepository<T, K>, like this:

1 2 3

public interface IPeopleRepository : IRepository<Person, int> { }

Although I havent added any members to this interface yet (other than those it inherits from the generic repository interface), it lays a nice foundation for future updates. Imagine I want to add a FindByLastNamemethod to the PeopleRepository. I could add that member to IRepository instead, forcing my concrete implementations to implement this member as well. However, that method would have no meaning to other repositories you may add to your system. So by adding an intermediate interface you get the best of both worlds: IPeopleRepository can do anything IRepository can, but its still open to be expanded with methods that only make sense to a PeopleRepository. My concrete PeopleRepository implements this interface as youll see in Part 5. Note that I am closing the generic type by explicitly specifying an int for the K type parameter. The Person class has been set up to use an int for the Id property as well (public class Person : DomainEntity<int>, IDateTracking) so it makes sense to make the repositories specific for an int as well. With these interfaces, a method on an actual concrete repository to manage people in the system could look like this:

1 2 3 4

public Person FindById(int id, params Expression<Func<Person, object>>[] includeProperties) { // Implementation here

The method accepts an int for the ID (as specified by the int type on the IPeopleRepository) and returns aPerson because IPeopleRepository specifies Person as the type of the T type parameter which is used as the return type of the FindById method in the generic IRepository interface. As youll see in the next article, the actual implementation is slightly different because FindById is implemented in a generic repository. The actual code (such as an MVC controller, a Web Forms page, or a Unit Test) would work with instances of theIPeopleRepository interface to get and update data in the database. Heres an example of the Delete method of a controller in an MVC application that accepts the ID of the object and deletes it by calling Remove on the concrete repository:

1 2 3 4 5 6 7 8

[HttpDelete] public ActionResult Delete(int id) { using (_unitOfWorkFactory.Create()) { _peopleRepository.Remove(id); } return RedirectToAction("Index"); }

9
Here, _peopleRepository is an object that implements the IPeopleRepository interface. In the MVC project, this instance is injected using StructureMap but you can of course also instantiate an object yourself. The UnitOfWorkFactory code is explained in the next article in this series, and youll find full details on implementing an MVC frontend in Part 6 and details on a Web Forms implementation in Part 7 of this series.

Stuff I Like to Do
Just as in the previous article in this series, Ill provide a quick list of things I like to do when building a model. Again, I wont be providing a lot of detail, but instead mention a few items I like or consider best practices.

Implement a base class for collections. This way you can centralize the behavior for all your collections. Let your custom collections inherit from the collection base class and dont use List<T> in the public API of your object model. Write extensive unit tests for your model classes. The Model project is now still relatively small, so you should be able to achieve great code coverage. Once you start expanding the model project itll be relatively easy to maintain a high code coverage. However, the lower the coverage, the less inclined youll be to catch up later. Document the public members of your API using XML comments (http://msdn.microsoft.com/en-us/library/b2s063f7.aspx). For example, members in the various interfaces and classes should be documented to make it easier to work with them later in the project. You can force the compiler to generate an XML file with the comments as well as list all items you forgot to document as compilation warnings by checking off the XML documentation file checkbox on the Build category if the projects Properties dialog, shown in Figure 4.7:

Figure 4-7 The Project Properties Dialog (click to enlarge) I typically only do this for the release build so I am not cluttering the list with compile warnings too much.

Summary
In this article you saw how to build up the model for the application. If youre familiar with previous versions of my N-Layer Design article series, youll recognize a lot of stuff. Even if youre unfamiliar with those articles, the code in the Model project should be easy to follow: most of it comes down to simple POCO classes like Person, and a bunch of collection classes to support collections of the POCO classes. The most complex code is probably the equality comparer code in the two base classes in the Infrastructure project. However, this is plumbing code you only need to write once, and not maintain during normal development of your application. In previous versions of this article series targeting .NET 2 and 3.5, the class design part of this setup was pretty easy to implement. All you had to do was creating the class and add the relevant properties for the types to them. However, it was the database part that was really hard to set up and required a lot of manually written code, stored procedures and testing. Fortunately, with EF Code First this is now really easy to implement as youll see in the next installment of this article series.

Where to Next?
Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

Building a Provider Based File Storage System Using .NET


Many moons ago, in January 2007 to be exact, I wrote an article about storing files in the database using ASP.NET 2.0 and SQL Server. One of the features of the application I demonstrated in the article was the ability to switch between storing the actual file in the database, or saving it on disk. In both cases, meta data such as the content type and the original name were saved in the database, but by changing a configuration setting called DataStoreType you could determine if the actual file was saved on disk, or stored in an NText column in the database together with the meta data. In February of the same year, Steven Bey suggested to rewrite the application and base it on the provider model that has become a quite popular design pattern since it was introduced for the ASP.NET Application Services that appeared in ASP.NET 2.0. I added Steven's suggestion to my "Things to do when I have the time for them" list. And today is the day I finally found the time to do it. In this article I'll show you how I changed the application using the provider based model so you can switch between different providers, including various flavors of SQL Server and Microsoft Access. Adding support for other data stores then becomes really simple. If you haven't read the original article, now is a good time to do so as I won't be repeating a whole lot of it. I'll wait here while you read it. Done? Good. It means we're all on the same level now. In the original article I introduced two classes: File andFileInfo. The File class is used to store complete details about a file, while the FileInfo class serves as a summary object for a file, without the actual file bytes. The latter class was used to display a list of files in, say, a GridView, without the overhead of the actual bytes associated with the file stored on disk. Besides being a wrapper for some properties such as Id, OriginalName and FileData, these classes also contained methods such as GetItem and GetList to directly access the database. While convenient to write at that time, it also meant the classes are tightly coupled to the chosen database technology (SQL Server in my case) which made them pretty much impossible to reuse. In the new implementation, I separated the File classes from the actual implementation, and let File inherit FileInfo, leading to the class hierarchy with simple Data Transfer Objects (DTO's) shown in Figure 1:

Figure 1 The DatabaseFile and DatabaseFileInfo classes inherit File and FileInfo respectively, and add a constructor that is able to fill the class's properties based on a DbDataReader. You'll see more of this later. With the File and FileInfo classes separated from the database technology, I was ready to implement a provider to work with them.

Introducing the Provider Model


When ASP.NET was released, it introduced the Provider Model for application services such as Membership and Roles,. According to the Microsoft site, a provider is A software module that provides a uniform interface between a service and a data source. Providers abstract physical storage media, in much the same way that device drivers abstract physical hardware devices. Because virtually all ASP.NET 2.0 state-management services are provider-based, storing session state or membership state in an Oracle database rather than a Microsoft SQL Server database is as simple as plugging in Oracle session state and membership providers. Code outside the provider layer needn't be modified, and a simple configuration change, accomplished declaratively through Web.config, connects the relevant services to the Oracle providers. In short, this means that code in your web application talks to a known interface. Under the hood, the configured provider is instantiated and work is delegated to the underlying provider. So, for example, when you callSystem.Web.Security.Membership.CreateUser( ... ) to create a user, you talk to a

static class (Membership) that delegates work to a provider it has access to (which is theSystem.Web.Security.SqlMembershipProvider class by default, but you can override that). The concrete implementations (SqlMembershipProvider in this example) inherit an abstract base class calledMembershipProvider which in turn inherits an abstract base class called ProviderBase. It's this base class that is part of the key to implementing a provider based model. For the Membership services, the object model looks like this:

Figure 2 This figure shows two classes implementing the provider functionality: the SqlMembershipProvider and theActiveDirectoryMembershipProvider. The code in your own application (such as the CreateUser call shown earlier, but also the built-in controls such as the Login and CreateUserWizard) talks to the static Membershipclass which in turn talks to one of the configured concrete providers. The MembershipSection class also shown in the diagram is used to read configuration information from the application's config file. You'll see more of this later. The beauty of this design is that it's extremely easy to swap a provider. In my article Using the Microsoft Access Providers to Replace the Built-In SQL Server Providers I am doing exactly that: replacing the configured provider with one that's built to target a Microsoft Access database instead of the existing SQL Server or Active Directory data stores. To implement a new provider, all you need to do is inherit from the abstract classMembershipProvider, implement all of the members defined in the contract for MembershipProvider and then configure your application to use your custom provider instead. What I like about this design pattern is that you don't need to deal with lots of implementation details of the API; all you do is provide an implementation for the methods defined in the base class and that's it. For example, while the static Membership class has four overloads of CreateUser, the provider implementation only needs to implement one: the most extensive overload. You can find out more information about the provider model in the following articles:

Beyond Membership: Using the Provider Design Pattern for Custom Features Provider Model Design Pattern and Specification, Part 1 Provider Design Pattern, Part 2

Implementing Your Own Provider Model


To implement your own provider model for an application,you need to carry out a few steps. I'll briefly list them first and mention the class names I'll be using in my application. In a later section, I'll go over the steps in more detail when discussing my implementation of the File Storage Provider. The goal of the implementation of this provider model is to create a public API similar to that presented in the original article. In other words, the application needs to provide a way to get files, save them in the database and on disk, and delete them again when necessary (this last feature wasn't a part of the original application). 1. Create an abstract class that inherits ProviderBase, and that defines the public contract for the functionality you want to build. This typically means adding abstract members that need to be implemented by the concrete providers. My class is called FileStorageProvider and has methods such as GetFile and SaveFile. Create a collection class that inherits ProviderCollection which is used to store the configured provider(s) in the manager class. My collection class is called FileStorageProviderCollection. Create a configuration class (mine is called FileStorageConfiguration) which inheritsConfigurationSection. This class is used to read configuration information from the application's config file. Create a static class (mine is named FileStorageManager) that serves as the main application's entry point. Add static methods that mimic the methods defined in the provider class. In my case, I added static methods such as GetFile and SaveFile. The methods delegate the work to the configured provider. Create concrete implementations that inherit the provider class. In my sample application, I have three classes that inherit FileStorageProvider: SqlFileStorageProvider,SqlAndDiskFileStorageProvider an d AccessFileStorageProvider. The first two target SQL Server, while the latter targets a Microsoft Access database.

2.

3.

4.

5.

Initially this is quite a bit of work. However, adding the next provider to the mix means you just need to execute the last step. So, adding an OracleFileStorageProvider means you just need to inheritFileStorageProvider and implement a few methods. You then need to register the provider in the target application, but you don't have to change a single line of code. To make the first four steps a lot easier, Microsoft provides the Code Template for Building a ProviderBased Feature. You can find more information about this template here:

Direct link to the MSI that installs a number of .cs files The Provider Toolkit homepage (on the French section of MSDN; couldn't find the English edition; the content is in English though)

The download installs 5 .cs files that serve as the code templates for the classes listed earlier. It also contains a readme file that guides you through changing some code in the template files to match your required behavior. With these code templates, you can have a simple provider with a static DoWork method set up in no time. Extending the model is then quite easy. For my File Storage Application I used the same template files to create my provider based model. I then named and modified my classes as follows:

Step 1 - Create the FileStorageProvider


This is the class that inherits from the ProviderBase defined in .NET. As explained earlier, this class defines the contract that all concrete providers need to implement. My FileStorageProvider is pretty simple, and looks like this: public abstract class FileStorageProvider : ProviderBase { public virtual string UploadsFolder { get; protected set; } public abstract File GetFile(Guid id); public abstract List<FileInfo> GetFileInfoList(); public abstract bool SaveFile(File file); public abstract bool DeleteFile(Guid id); } Three of these methods work with the File and FileInfo classes I showed at the beginning of this article.

Step 2 - Create the FileStorageProviderCollection


This code for this class is almost identical to that of the template, except for the FileStorage name and types. public class FileStorageProviderCollection : ProviderCollection { public override void Add(ProviderBase provider) { if (provider == null) { throw new ArgumentNullException("The provider parameter cannot be null."); } if (!(provider is FileStorageProvider)) { throw new ArgumentException("The provider parameter must be of type FileStorageProvider."); } base.Add(provider); } new public FileStorageProvider this[string name] { get { return (FileStorageProvider)base[name]; } } public void CopyTo(FileStorageProvider[] array, int index) { base.CopyTo(array, index); } } This class serves as a simple collection for instantiated provider types. It ensures you only add providers of the correct type (I think this code predates the generics introduced in NET 2) and enables you to retrieve a provider by its index. I haven't seen a reason for the CopyTo method so I am not sure why it's included in the template code.

Step 3 - Create the FileStorageConfiguration


Again, this class is almost identical to that of the template. Check out the download at the end of the article for the complete source. This class is used to read configuration information in the application's config file that looks like this <add name="SqlFileStorageProvider" type="Spaanjaars.FilesProvider.SqlFileStorageProvider, Spaanjaars.FilesProvider" connectionStringName="DefaultConnectionString" description="this came from config" />

Step 4 - Create the FileStorageManager


This is probably the most interesting class from the provider model. This class has two main tasks: first, when instantiated it creates a collection of providers based on the configuration information it finds in the config file for the application. Secondly, it has public and static methods that define the contract your end applications works with. The class contains quite a bit of code, but I'll show it here in its entirety so you know what goes on under the hood. public static class FileStorageManager { //Initialization related variables and logic private static bool isInitialized; private static Exception initializationException; private static FileStorageProvider defaultProvider; private static FileStorageProviderCollection providerCollection; static FileStorageManager() { Initialize(); } private static void Initialize() { if (!isInitialized) { try

{ //Get the feature's configuration info FileStorageConfiguration qc = (FileStorageConfiguration) ConfigurationManager.GetSection("FileStorage"); if (qc.DefaultProvider == null || qc.Providers == null || qc.Providers.Count < 1) { throw new ProviderException("You must specify a valid default provider."); } //Instantiate the providers providerCollection = new FileStorageProviderCollection(); ProvidersHelper.InstantiateProviders(qc.Providers, providerCollection, typeof(FileStorageProvider)); providerCollection.SetReadOnly(); defaultProvider = providerCollection[qc.DefaultProvider]; if (defaultProvider == null) { throw new ConfigurationErrorsException( "You must specify a default provider for the feature.", qc.ElementInformation.Properties["defaultProvider"].Source, qc.ElementInformation.Properties["defaultProvider"].LineNumber); } } catch (Exception ex) { initializationException = ex; isInitialized = true; throw ex; } } isInitialized = true; //error-free initialization } //Public feature API public static FileStorageProvider Provider { get { return defaultProvider; } } public static FileStorageProviderCollection Providers { get { return providerCollection; } } public static File GetFile(Guid id) { return Provider.GetFile(id); } public static bool SaveFile(File file) { return Provider.SaveFile(file); } public static bool DeleteFile(Guid id) { return Provider.DeleteFile(id); } public static List<FileInfo> GetFileList() { return Provider.GetFileInfoList(); } public static string UploadsFolder { get { return Provider.UploadsFolder;

} } } The Initialize method contains pretty much boiler plate code from the template file for this class. It reads the configuration data using an instance of FileStorageConfiguration and then lets the ProvidersHelper class (part of the .NET Framework) do all the hard work. The helper class parses the type attribute from the configuration section and instantiates the relevant concrete providers based on that type. In the example above, that would mean instantiating a Spaanjaars.FilesProvider.SqlFileStorageProvider. If you have multiple providers listed, all of them are instantiated, but only one is the current provider at any given time. Look at theProvidersHelper class with Reflector if you want to see the dirty details of the implementation. The remainder of the code in this class is the public API of the provider. The first two properties, Provider andProviders give access to the currently configured provider, and to all registered providers. Quite often you don't have the need to access them directly in the application that uses the provider model, but they can be useful to carry out some lower level tasks not supported by FileStorageManager directly, or if you want to talk to a provider other than the one configured as the current provider. The final five members are the part of the API that this article is all about: dealing with files. You see four methods to get a single File, a list of FileInfo instances and to save and delete a file. The UploadsFolderproperty returns the path of the folder where the files must be saved, in case the configured provider needs to store them on disk; otherwise it returns null. In order to make use of all this, you need to add the following to your application's .config file: <configuration> <configSections> <section name="FileStorage" type="Spaanjaars.FilesProvider.FileStorageConfiguration, Spaanjaars.FilesProvider" allowDefinition="MachineToApplication" /> </configSections> ... <FileStorage defaultProvider="SqlFileStorageProvider"> <providers> <add name="AccessFileStorageProvider" type="Spaanjaars.FilesProvider.AccessFileStorageProvider, Spaanjaars.FilesProvider" connectionStringName="AccessConnectionString" SaveFileDataInDatabase="true" UploadsFolder="~/Uploads" description="Stores meta data in an Access database and files on disk or in the database" /> <add name="SqlFileStorageProvider" type="Spaanjaars.FilesProvider.SqlFileStorageProvider, Spaanjaars.FilesProvider" connectionStringName="DefaultConnectionString" description="Stores meta data and files in SQL Server" /> <add name="SqlAndDiskFileStorageProvider" type="Spaanjaars.FilesProvider.SqlAndDiskFileStorageProvider, Spaanjaars.FilesProvider" connectionStringName="DefaultConnectionString" description="Stores meta data in SQL Server, and saves the files to disk" UploadsFolder="~/Uploads" /> </providers> </FileStorage> ... </configuration> This code defines three providers: one using Microsoft Access and two targeting SQL Server. The currently active provider is the SqlFileStorageProvider as set by the defaultProvider attribute. With this configuration (and assembly for the File Storage System referenced by the application), you can now access the public API in the final application like this:

// Save a file File myFile = new File( ... Code to instantiate File here ...); FileStorageManager.SaveFile(myFile); // Get a file Guid id = new Guid(Request.QueryString.Get("Id")); File myFile = FileStorageManager.GetFile(id); // Get all files (as FileInfo instances) List<FileInfo> files = FileStorageManager.GetFileList(); // Delete a file Guid id = new Guid(Request.QueryString.Get("Id")); FileStorageManager.DeleteFile(id); While this API is now available as advertised, you still need the concrete implementations ofFileStorageProvider in order to actually work with these files. This is discussed next.

Step 5 - Creating Concrete Implementations of FileStorageProvider


If you look at the source code that comes with this article, you find three concrete implementations of the FileStorageProvider, listed below: Type Description This provider targets SQL Server and stores files and meta data in SQL Server.

SqlFileStorageProvider

SqlAndDiskFileStorageProvider This provider inherits SqlFileStorageProvider and stores the meta data in SQL Server, and the actual files on disk. AccessFileStorageProvider The AccessFileStorageProvider targets a Microsoft Access database and stores the meta data in the database. It has a configuration switch that determines whether to store the files on disk, or in the database as well.

Notice how I separated the behavior of storing files on disk or in the database in two separate providers for SQL Server, while the Access implementation can do both at the same time. This just serves as an example. I could have created two separate providers for Access as well, or extended the SqlFileStorageProvider with a switch to determine where to store the actual file data. Figure 3 shows how the three providers and their base classes are related:

Figure 3 Both SqlFileStorageProvider and AccessFileStorageProvider directly inherit the base provider:FileStorageProvider. SqlAndDiskFileStorageProvider inherits SqlFileStorageProvider a nd only overrides the two methods that deal with files on disk: DeleteFile and SaveFile. You see how this works a little later. Most of the code in these providers is pretty standard .NET and ADO.NET code, and most of it looks like the code from the original article. So, instead of showing and discussing the full code, I'll focus on just a

few interesting bits and pieces. First, take a look at the Initialize method you find in SqlFileStorageProvider: public class SqlFileStorageProvider : FileStorageProvider { public string ConnectionString { get; protected set; } protected bool SaveFileDataInDatabase { get; set; } ... public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config) { SaveFileDataInDatabase = true; if ((config == null) || (config.Count == 0)) { throw new ArgumentNullException( "You must supply a valid configuration dictionary."); } if (string.IsNullOrEmpty(config["description"])) { config.Remove("description"); config.Add("description", "Put a localized description here."); } // Let ProviderBase perform the basic initialization base.Initialize(name, config); //Perform feature-specific provider initialization here //Get the connection string string connectionStringName = config["connectionStringName"]; if (String.IsNullOrEmpty(connectionStringName)) { throw new ProviderException( "You must specify a connectionStringName attribute."); } ConnectionStringsSection cs = (ConnectionStringsSection) ConfigurationManager.GetSection("connectionStrings"); if (cs == null) { throw new ProviderException( "An error occurred retrieving the connection strings section."); } if (cs.ConnectionStrings[connectionStringName] == null) { throw new ProviderException( "The connection string could not be found in the connection strings section."); } else { ConnectionString = cs.ConnectionStrings[connectionStringName].ConnectionString; } if (String.IsNullOrEmpty(ConnectionString)) { throw new ProviderException("The connection string is invalid."); } config.Remove("connectionStringName"); //Check to see if unexpected attributes were set in configuration if (config.Count > 0) { string extraAttribute = config.GetKey(0); if (!String.IsNullOrEmpty(extraAttribute)) { throw new ProviderException(String.Format( "The following unrecognized attribute was found in {0}'s configuration: '{1}'", Name, extraAttribute)); } else {

throw new ProviderException( "An unrecognized attribute was found in the provider's configuration."); } } } } The first thing that Initialize does is setting SaveFileDataInDatabase to true. This is an hard coded implementation which means the provider will always store the file data in the database.This property is markedprotected which means that classes that inherit SqlFileStorageProvider can override it, which happens to be the case with the SqlAndDiskFileStorageProvider class. Once again, most of what goes on in Initialize is boiler plate code coming from the Provider Toolkit samples. Basically, the code parses the config file, looking for config elements it recognizes and assigning them to local variables (such as the ConnectionString). Using a Fail Fast mechanism, the code throws exceptions when it encounters invalid values, or when it encounters attributes it doesn't recognize. I really like this style of config parsing, as it means that when your configuration is not right, you get immediate feedback with a crystal clear exception message. Once Initialize is called, the provider should be in a valid state, after which you can call one of its methods. To see an example, consider this DeleteFile implementation: public override bool DeleteFile(Guid id) { int affectedRecords; using (SqlConnection mySqlConnection = new SqlConnection(ConnectionString)) { using (SqlCommand myCommand = new SqlCommand("sprocFilesDeleteSingleItem", mySqlConnection) { CommandType = CommandType.StoredProcedure }) { myCommand.Parameters.Add(new SqlParameter("@id", SqlDbType.UniqueIdentifier) { Value = id }); mySqlConnection.Open(); affectedRecords = myCommand.ExecuteNonQuery(); } mySqlConnection.Close(); } return affectedRecords == 1; } This code is pretty much identical to the code from the original article: it instantiates a SqlConnection and aSqlCommand object and then executes a stored procedure that deletes the file from the database. The other methods (GetFile, GetFileInfoList, and SaveFile) all pretty much follow the same pattern. There's one thing worth noting and that's how GetFile and GetFileInfoList use custom DatabaseFile andDatabaseFileInfo classes to copy the data from a DbDataReader into the class itself. Here's a snippet from theGetFile method: using (SqlDataReader myReader = myCommand.ExecuteReader()) { if (myReader.Read()) { myFile = new DatabaseFile(myReader); } myReader.Close(); } The DatabaseFile class simply inherits File, but has a constructor that accepts a DbDataReader like this: public DatabaseFile(DbDataReader myReader) { Id = myReader.GetGuid(myReader.GetOrdinal("Id")); DateCreated = myReader.GetDateTime(myReader.GetOrdinal("DateCreated")); // Other properties here } The GetFile method returns a File instance, so calling code never knows they are dealing with aDatabaseFile. I found this a convenient way to load data in the File class based on some data in the database. Instead of a derived class with a constructor, it would have been easy to create some method likeLoad in the SqlFileStorageProvider class to copy the data into a File instance. Both methods

would result in the same thing: a filled instance of File that can be returned to the calling code. In the former scenario, it's actually a DatabaseFile, but no one knows. All of the code in SqlFileStorageProvider is designed to store the actual bytes that make up the file in SQL Server. To see how this works, look at the way the parameter for FileData in SaveFile is set up: myCommand.Parameters.Add( new SqlParameter("@fileData ", SqlDbType.VarBinary) { Value = SaveFileDataInDatabase ? (object)file.FileData : DBNull.Value, Size = SaveFileDataInDatabase ? file.FileData.Length : 0 } ); Because SaveFileDataInDatabase has a hard coded value of true, the FileData is always sent to the database. However, because of the SaveFileDataInDatabase property, this provider is technically capable of ignoring theFileData, and sending DBNull.Value instead. That's what I make use of in the inheritingSqlAndDiskFileStorageProvider class. In that class's Initialize method, SaveFileDataInDatabase is always set to false. The class then overrides SaveFile like this: public override bool SaveFile(File file) { bool result = base.SaveFile(file); if (result) { // Database update is done; now store the file on disk. const int myBufferSize = 1024; using (Stream myInputStream = new MemoryStream(file.FileData)) { using (Stream myOutputStream = System.IO.File.OpenWrite(PhysicalUploadsFolder + file.FileUrl)) { byte[] buffer = new Byte[myBufferSize]; int numbytes; while ((numbytes = myInputStream.Read(buffer, 0, myBufferSize)) > 0) { myOutputStream.Write(buffer, 0, numbytes); } myInputStream.Close(); myOutputStream.Close(); } } } return result; } This method first calls base.SaveFile. That method then stores the meta data in the database. BecauseSaveFileDataInDatabase is set to false for the derived provider, the FileData is skipped. The same FileDatais then stored on disk using a number of Stream classes. The PhysicalUploadsFolder property has been given a value in the Initialize method, based on the configuration element for the configured provider. DeleteItem follows a similar pattern. It deletes the file from the database, and when that succeeds, it also deletes the file from disk. The AccessFileStorageProvider class follows a very similar pattern. However, since it can be used to to store files on disk and in the database, its Initialize method has some extra logic to figure that out, and to make sure the UploadsFolder is present, valid and exists. It then uses the SaveFileDataInDatabase property inSaveFile and DeleteFile to determine if the file must be stored on, or deleted from disk.

Extending the Storage System


With the current implementation, you have a very flexible system. The three available providers make it super easy to store meta data in SQL Server or in an Access database. Additionally, through configuration you can determine where the actual files need to be stored: in the database, or on disk. Since the current implementation is close to the original version, I didn't have to make a whole lot of changes to the actual web site that is used to manage the files. I had to change a few types, changed

the ObjectDataSource control inDefault.aspx and changed a few method calls, but I didn't have to touch any logic. But what's even better is that it's now very easy to introduce a new provider. If, for example, I wanted to store files in the cloud using Azure, I could build a new FileStorageProvider, called AzureFileStorageProviderfor example, register the provider in web.config and be done with it. From then on, files would be stored in, and served from the cloud!

Disclaimer
I have tested most of this code thoroughly enough to know it probably works. However, if you start using this in a real-world application, be sure you know what you're doing and that you understand the code. No warranties whatsoever. If you find a bug or have comments about the current code, please use the Talk Back feature at the end of this article. Also, the database methods could benefit from some extra level of abstraction. To make each method simple to understand, I am instantiating objects such as connections and commands in each data access method. You could abstract them away to some general helper classes, or use another data access technologies such as Entity Framework or NHibernate. The sample database that comes with this article is mostly compatible with the one from the original article. I changed the length of the OriginalName column from an nvarchar(50) to an nvarchar(255). I also changed the length of the associated stored procedure parameter in sprocFilesInsertSingleItem and I created a new stored procedure called sprocFilesDeleteSingleItem in order to delete files from the database.

Downloads
You can download the complete code (C# only) for the provider model and the sample site.

Where to Next?
Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .

Das könnte Ihnen auch gefallen