Explore the Microsoft Application Blocks
Avoid coding infrastructure requirements by using the Microsoft Application Blocks.
October 30, 2009
asp:feature
TECHNOLOGIES: VS .NET | C# | VB .NET
ASP.NET VERSIONS: 1.0 | 1.1
Explore the Microsoft Application Blocks
Avoid coding infrastructure requirements by using theMicrosoft Application Blocks.
By Brian Noyes
Most real-world applications sharecommon requirements at the infrastructure level. Your apps need to access data,handle exceptions, access configuration data, and so on. Before the .NETFramework came along, a lot of people spent a lot of time writing littleutility classes and subroutines for common coding tasks, such as parsingstrings, doing type conversions, and manipulating paths. The classes in the.NET Framework save you from doing a lot of low-level coding for which you usedto have to spin your own solutions.
But you still end up writing a lotof repetitive and mostly uninteresting code to address those infrastructurerequirements because they exist at a higher level of abstraction than even theindividual classes in the .NET Framework were designed to address. Microsofthas seen the need to address these infrastructure requirements, as well, andhas begun providing mini-frameworks, called Application Blocks, to addresscommon requirements most organizations have for their applications. TheApplication Blocks are quasi-products from Microsoft. They are developed anddelivered as products by Microsoft and are even supported through tech support,but they are free, so you can't beat the price.
The first two Application Blockswere released last year and addressed data access and exception management. Anew version of the Data Access Application Block (DAAB) has been released, ashave a slew of new Application Blocks to add to the mix. In this article, Iwill introduce the Application Blocks as a whole, and I will dive deeper into twoof the blocks: the DAAB and the User Interface Process (UIP) Application Block.In a series of follow-up articles online, I will discuss each of the otherblocks in turn.
Pick from the Menu
I'll skip over the DAAB and UIP fornow because I will cover them in more detail later. Let me quickly introduceyou to the other selections on the menu before I cover today's specials.
First off, the Application Blocksall share some common goals and capabilities. The biggest goal is to make it sothat you can write less code and have consistent and clean interfaces forsatisfying the infrastructure requirements of your applications, allowing youto focus on designing and coding your core logic. Obviously, they need to bereliable and to perform well. To be truly reusable, they also need to be highlyextensible - which the Application Blocks are.
Almost all the Application Blocksare designed to deliver a usable capability as soon as you download the code,but they have numerous extensibility points so you can use them as designedwhile adding to their capabilities without having to modify the code deliveredby Microsoft. They also are configuration-driven, which means that extendingtheir underlying capabilities often requires no new coding in the consumingapplication. So, for example, you can add a new publisher of exceptioninformation without changing any of the code that actually makes calls to theexception manager to publish. Each Application Block comes with full sourcecode, documentation, and samples to help you get started using and extendingthem.
The Application Blocks I will becovering in future articles include:
TheException Management Application Block, which includes capabilities forpublishing exception context information to various forms of storage.
TheConfiguration Management Application Block, which allows you to read and writeapplication-configuration data and settings to and from multiple forms ofstorage providers.
TheUpdater Application Block, which implements a pull mechanism to updateapplications over distributed networks easily and automatically.
Thelast three blocks are focused on Service Oriented Architecture (SOA) and allowyou to make calls to services in an asynchronous manner and to cache andaggregate the data those services return.
Smart Data Accessfor the Masses
ADO.NET is a powerful and flexibleobject-oriented API for data access. However, for most business applications,the ADO.NET API is a little too fine-grained for concise, maintainable code.The DAAB gives you a simplified API for data access that minimizes the amountof repetitive code you need to write for a typical data-access layer. Version 2of the DAAB was released recently and adds some great new capabilities to whatwas released in version 1 more than a year ago. The DAAB classes are designedto work exclusively with the SQL Server managed provider, but if you need towork with other databases, you could implement a custom version of the DAABtargeting other providers. An Oracle implementation based on version 1 of theDAAB is included with the Pet Shop 3 sample application.
The DAAB is composed of only twoclasses, the SqlHelper and SqlHelperParameterCache classes. SqlHelper has abunch of overloaded ExecuteXXX methods (see Figure 1). The parameters for thesemethods include connection, command, and parameter information. The variousoverloads of each method give you a lot of options in terms of how theconnections are constructed, commands are executed, and parameters are passed.Basically, the calling patterns of these methods minimize the amount ofconstruction and population of individual objects that you need to do just toexecute a single command against the database.
Method | Result |
---|---|
ExecuteDataset | Executes a query and returns a new DataSet object containing the result. |
ExecuteReader | Executes a query and returns an open SqlDataReader ready for use in accessing the contained rows. |
ExecuteNonQuery | Executes a query that is not expected to return any result set. The method returns the number of rows affected by the query. You can provide SqlParameters that are out or return value parameters and harvest those after completion of the method calls. |
ExecuteScalar | Executes a query that is expected to return a single-row, single-column type of result set and returns that value as the return value from the function. This saves you from having to reach into a returned result set to extract a single value when you know that is all that will be returned. |
ExecuteXmlReader | Executes a query that is expected to return an XML node set as the result set. The DAAB and ADO.NET wrap those return results in an XmlReader that you can use to iterate through the nodes. |
FillDataset | Executes a query to add a table to an existing data set that you pass in as an argument. This allows you to construct multi-table data sets or work with strongly typed data sets using the DAAB. |
UpdateDataset | Executes an update query to perform updates, insertions, and deletions based on a data set containing modified records. |
CreateCommand | Automatically constructs a command object for performing updates by querying the database for the parameter set for a stored procedure. |
Figure 1. These are thefamilies of query methods of the SqlHelper class. Each of these families hasmultiple overloads to allow variations in the construction of the connection,command, and parameter information required to execute the query.
Version 2 of the DAAB includesseveral significant enhancements compared to what was in version 1. Theseinclude the abilities to work with strongly typed data sets, populate a dataset with multiple tables, and update the database using data sets. There arealso some additional discovery methods available for automatically creatingcommands, and there are some additional ExecuteXXXTypedParams methods that letyou pass your parameters in the form of a populated DataRow. Using thosemethods, if you have parameters for a query already in the form of a DataRow,you don't need to push the parameters into individual SqlParameter objects butcan just pass the DataRow containing the parameter values instead.
The SqlHelperParameterCache classprimarily is used internally by the SqlHelper class, but it has several publicmethods that will allow you to discover and cache parameter sets to reduce thecost of repeatedly reconstructing those parameter sets. You need to be carefulin the way you use these methods, though, because they can introduce a couplingbetween your data-access code and the underlying queries or stored procedures,based on the specific order of the parameters that are returned. Your code willbe more maintainable and easier to understand if parameter matching is based onname rather than on the order in which the parameters appear, because thenparameters can be inserted or removed from the underlying query withoutbreaking the data-access code.
The download code for this articleincludes a sample application that uses the DAAB to perform some queriesagainst a custom database that contains two tables: Files and Folders. See thedownload ReadMe.htm file for details on how to construct and populate thisdatabase on your machine. The FileSystemDataAccess sample application performsa bunch of different query results and presents them in a Windows userinterface to let you experiment with performing queries and updates using theDAAB. For example, to use the DAAB to get all the files as a data set from thedatabase using a stored procedure, and to name the table that is created in thedata set, all that is required are two lines of code:
DataSet ds = SqlHelper.ExecuteDataset(
DataGlobals.ConnectionString,"GetFiles",null);
ds.Tables[0].TableName= "Files";
Tables that are created by theExecuteDataset method use the default ADO.NET naming, so you will have to namethem after they are returned if you desire. You also could pre-create the dataset and pass it into the FillDataset method, which allows you to specify thetable names as arguments. Using this latter method, you also can populate typeddata sets and multi-table data sets.
The SqlHelper class handlesconstruction of the connection object as well as opening it, creating a commandobject for the specified stored procedure, executing the query through a dataadapter to fill a data set, closing the connection, and returning the result.If you were using raw ADO.NET, you would have to do all those things yourselffor every query you made to the database. By using the DAAB, all thoserepetitive and error-prone actions are neatly encapsulated in the SqlHelperclass, which allows you to write much less code and focus on the business logicof your application rather than data-query goo.
As of version 2 of the DAAB, youalso can perform updates using data sets containing modified, inserted, ordeleted rows. Figure 2 shows an example that uses the new CreateCommand methodto construct the command objects for the updates automatically and thenperforms the updates with the UpdateDataset method. The code in Figure 2 alsouses the CreateCommand method to construct the update commands using a storedprocedure name and the names of the parameters to pass to that storedprocedure. CreateCommand will locate those parameters and their types with around-trip to the database and will pre-create the parameters collections forthose commands. Then these parameter collections will be used for each update,insert, or delete operation that is required based on the current records inthe data set that is passed to UpdateDataset.
public staticvoid UpdateFiles(DataSet ds)
{
// Create the connection
SqlConnection conn =
newSqlConnection(DataGlobals.ConnectionString);
// Construct the update commands - allthree are req'd
SqlCommand insertCmd =SqlHelper.CreateCommand
(conn,"AddNewFile","Name","Size","ParentFolderID");
SqlCommandupdateCmd = SqlHelper.CreateCommand
(conn,"UpdateFileName","FileID", "Name");
SqlCommanddeleteCmd = SqlHelper.CreateCommand
(conn,"DeleteFile","FileID");
// perform the update
try
{
SqlHelper.UpdateDataset
(insertCmd, deleteCmd,updateCmd,ds,"Files");
}
finally
{
conn.Close();
}
}
Figure 2. Like otherdata-access operations with the DAAB, performing an update with a data setrequires minimal code that is easy to write and understand.
Decouple YourPresentation Tier
The UIP Application Block targets acommon application requirement for presentation-tier applications - the need toimplement workflow and state management between views, or individual forms, ofyour application. The UIP is designed at a much higher level of abstractionthan the DAAB and constitutes a small presentation-tier framework unto itself.The driving force behind the UIP is that, for maintainability, you want tominimize coupling between the individual views (think forms) of yourapplication.
Consider an application that needsto implement something along the lines of a shopping cart, quiz orquestionnaire, or registration process. All these require that a navigationflow exist between individual views of the application, as well as state thatgets shared between views and may be passed down into the business tier whilethe process is in progress, or at the end when it is complete. You may have astrictly linear flow or one with multiple paths and branching. The problem isthat if you explicitly code individual views to know about every path into andout of their place in the process, along with all state-passing requirementsfor those transitions, you run into significant maintainability problems as thecomplexity of your process grows or when you want to add or remove steps in theprocess.
The UIP addresses this byimplementing a model-view-controller pattern that completely decouples theindividual views of your application, allowing you to add or remove steps inthe process or factor individual views into multiple views without having totouch any of the other views' code.
To use the UIP in yourapplications, you basically need to do several things. First, you need todefine the "use" case that composes the process you are implementing. By doingthis, you can lay out the navigation graph that satisfies that "use" case,including the views that compose it and what the transitions are between views.Next, you need to implement a controller class. This is a class you derive fromthe ControllerBase class in the UIP. This class will contain the navigationmethods called by the views in your application and will be the single point ofcontact for your individual views. Next, you need to design the views of yourapplication and derive them from either WinFormView or WebFormView, dependingon the type of application. Finally, you need to add a bunch of information toyour config file to tell the UIP where to find everything it needs at run time.
The ControllerBase class contains astate bag that the views can place state values into so that they can be sharedacross views without having to pass that state as part of a view transitionexplicitly (see Figure 3). That state also can be persisted through a number ofconfigurable storage providers, allowing you to resume the task wherever it wasabandoned, at a future time.
Figure 3. The UIP lets individual views of a process be ignorant of oneanother. Each view just interacts with the controller, placing information inits state collection and calling methods on the controller that result in theUIP manager displaying the next appropriate view based on configuration data.The state can be persisted to different providers, just by changing config-fileentries.
An example of what the code ends uplooking like from the perspective of the view is shown in Figure 4. You accessthe controller as a protected member of that base class and cast it to thederived controller to access the specific navigation methods that you implementin that derived class. Views also store the ongoing results of the process inthe state collection contained by the controller. Note that there are noreferences to other views, nor is there any explicit passing of state toanother view.
public classWhatIsQuest : WebFormView
{
// Details omitted...
private QuizState GetQuizState()
{
return(QuizState)Controller.State["QuizState"];
}
private void btnNext_Click
(object sender, System.EventArgs e)
{
GetQuizState().Quest = txtQuest.Text;
OnlineQuizController ctrl =
(OnlineQuizController)Controller;
ctrl.MoveNext();
}
private void btnBack_Click
(object sender, System.EventArgs e)
{
GetQuizState().Quest = txtQuest.Text;
OnlineQuizController ctrl =
(OnlineQuizController)Controller;
ctrl.MovePrevious();
}
private void btnSelect_Click
(object sender, System.EventArgs e)
{
GetQuizState().Quest = txtQuest.Text;
OnlineQuizController ctrl =
(OnlineQuizController)Controller;
ctrl.BranchSelectQuest();
}
}
Figure 4. Views in a UIPapplication simply call navigation methods on their controller class and storethe results of their portion of the process in a state collection.
Methods in the derived controllerclass that you implement are usually as simple as setting the NavigateValue onthe state object and calling Navigate on the base class, as shown here:
public void MoveNext()
{
this.State.NavigateValue ="next";
Navigate();
}
This results in the base classdetermining the corresponding view for the NavigateValue, based on which viewwas current and based on what the configuration settings for that NavigateValueare for that view in the config file. This effectively adds a layer ofabstraction between what the view sees as a navigation command on thecontroller class and how the UIP manager interprets that command at run time,all based on config-file entries that can be changed and reorganized withoutrequiring any changes to source code.
There is a lot of complexity goingon under the covers with the UIP to give you a rich, flexible, configurable,and maintainable model for process-oriented user interfaces. The download codefor this article includes an online quiz sample that demonstrates the steps forusing the UIP. The questions in the quiz may look a bit familiar to fans ofMonty Python. See the ReadMe.htm for more details of what the steps were toimplement this sample using the UIP.
The sample code in thisarticle is available for download.
Brian Noyes is a softwarearchitect with IDesign Inc. (http://www.idesign.net),a .NET-focused architecture and design consulting firm. Brian specializes indesigning and building data-driven distributed Windows and Web applications. Hehas more than 12 years of experience in programming, engineering, and projectmanagement and is a contributing editor and writer for C#PRO, asp.netPRO, and other publications. Contacthim at mailto:[email protected].
Read more about:
MicrosoftAbout the Author
You May Also Like