The Repository Pattern in ASP.NET – Part 2
This is the conclusion of Paul Cociuba’s 12-part series on ASP.NET 4.5. It has been a long journey, and for those who’ve missed out on previous parts, we’ve also linked the entire series at the end of this post.
To finish the implementation of the application and the video series, this video will demonstrate how to add the capacity to select single records, insert, update and delete entities using the Repository Pattern (thus implementing CRUD).
0:50 – during part 1 of the Repository Pattern implementation, we added a class called ControlExtenders to the application. This class exposed extension methods (methods that can be called on an object without having the object explicitly define the method on the class).
1:25 – one of the extension methods defined by the class is the SetDataMethodObjects and is set to work with DataBoundControl objects (which is a superclass of the FormView, GridView and DropDown classes). It allows us (through the use of an anonymous delegate) to position the target control’s DataMethodsObject to the instance of the repository that is passed into the method via the dataMethodObject (small case) parameter
1:50 - the extension method allows the application to pass in an instance of IToyCategoryRepository interface to the ToyCategories GridView in the Categories.aspx page, and allows the GridView to use the repository instance to call select methods and extract the data it needs to display on the page.
2:10 – the ControlExtenders class is augmented with a couple of more methods allowing it to supply extension methods which will tell the FormView control how to react when the ItemInserted, ItemDeleted and ItemCommand events are fired.
2:40 – the application we built up to this point would redirect the user back to the categories listings after the insertion or deletion of a category object, or if the user clicked the ‘Cancel’ button while inserting or editing a category. This was done by event handling code for the ItemInserted, ItemDeleted and ItemCommand events.
3:00 – inspecting the code for the new methods more closely, the RedirectToRouteOnItemInserted and RedirectToRouteOnItemDeleted methods will add an anonymous delegate to the ItemInserted or ItemDeleted event invocation list. The delegate will check if the model state is valid, and if so, it will redirect to the route whose name is indicated via the string parameter called RouteName.
3:40 – the RedirectToRouteOnItemCommand extension method appends another anonymous delegate to the ItemCommand event of the FormView. This delegate checks if the command’s name is ‘cancel’ – once the event is fired – and if so, it will also redirect to the route which is specified by the string RouteName parameter.
4:00 – the next step is to augment the definitions of the IToyCategoryRepository and IProductRepository interfaces with new method definitions for methods to select, insert, update and delete data. Notice that the IProductRepository interface will also be provided with a method signature for GetCategories. This method will be called by a DropDown control when the end user is either inserting or editing a product and we need to display the entire list of categories to the user so that he / she may decide which category to associate with the product.
5:10 – to adhere to the new interface definitions, I bring in the code for the new methods inside the ToyCategoryRepository class which implements the interface.
5:26 – Reviewing the code for the new methods, GetCategory has exactly the same code as the method present in the code-behind of the CategoryDetails.aspx page. The InsertCategory method takes in an object of type ModelMethodContext. This object exposes a ModelState property as well as a TryUpdateContext and an UpdateContext methods which will be used by the code. This object allows us to perform execution of the code as if we were in the context of the executing page (in the code-behind) but has no WebForms related data or imports required. Hence the ModelMethodContext object can be mocked easily and the methods that make use of it can be unit-tested.
7:26 – Inspecting the UpdateCategory method, we see that it too takes an object of type ModelMethodContext as a parameter, together with the CategoryID. The CategoryID parameter is passed in by the calling control (in this case the FormView) via the DataKeyNames attribute.
7:50 – When attempting to locate the appropriate category object to update inside the UpdateCategory method, we may have a situation where the search by CategoryID returns null, since the category might not exist anymore. At this point we make use of the modelMethodContext instance passed into the method using its ModelState property- which allows us to call a method called AddModelError to signal a custom error on the model. The error has a key and a description and is a quick and simple way to bubble an error up from the model to the UI layer of the application without generating an exception.
8:40 – we bring in the five method implementations into the ProductRepositoy class to keep with the definition of the IProductRepository. The GetCategories and GetProduct methods have the same code as their predecessors from the code-behind of the ProductDetails.aspx page. The InsertProduct and UpdateProduct methods now make use of the ModelMethodContext parameter as well to be able to call the TryUpdateModel and UpdateModel methods and signal back any possible validation errors that may occur.
9:40 – after having compiled the solution. It is time to add the new user interface pages that will make use of the new methods exposed by the repository classes and interfaces. These pages are copies of the original CategoryDetails.aspx and ProductDetails.aspx pages.
10:07 – the markup of the new pages is identical to the one in the old pages. The only changes to be performed are in the code behind. The methods used to select / insert / update or delete a product or category have been removed since the are no longer needed. They have been replaced with functionality directly inside the repository.
10:45 - a new class variable of type IToyCategoryRepository has been added to the code-behind of both pages.
11:20 – to instruct the data control on the page to use the new instance of the repository, we add code to the Page_Init event handler. Using the extension methods we defined earlier, we can indicate to the control to use the methods provided by the repository to select / insert / update / delete data – using the call to SetDataMethodObjects extension methd. We can also specify to which routes to redirect when an insert or delete has occurred, or when the user cancels an insert or an update.
12:09 – on the page, we remove the markup that wired the control’s event handlers through the OnItemInserted, OnItemDeleted and OnItemCommand attributes, since these events are already wired up through the code in the Page_Init event.
12:26 – the same changes will be performed on the ProductDetailsRepository.aspx page as well.
13:35 – After declaring the new instance of the repository in the code-behind of the page and hooking up the control to the repository and to the event handlers in the Page_Init code, we will also need to handle the Init events of the two DropDown controls found in the Insert and Update templates of the FormView. Using the Init event of each of the DropDown controls, we call the SetDataMethodObjects extension method to tell the controls to populate themselves with data coming from the repository.
14:10 – we also need to modify the markup of the two controls to point the control to their respective event handler implementations for the Init event handlers – note that Visual Studio will provide intellisence when performing this modification.
15:35 – to complete the project, we will modify the routes in the Global.asax file to use the new pages to display category and product details by changing the ProductDetails and CategoryDetails routes as well as the NewProduct and NewCategory routes.
16:05 – after having compiled the solution again, we run the completed project to test the new interface that makes use of the repository.
16:45 – to see the code in action, we set a breakpoint on the GetProduct method of the ProductRepository class which will be called when the ProductDetailsRep.aspx page is called to display the details for an existing product.
Conclusion
This chapter concludes the video series. The code for the series can be downloaded as a Visual Studio 2012 project directly from here and will contain the entire project. I also suggest visiting my links page to find more useful resources on ASP.net and IIS.
Here’s a complete listing of the entire series:
- A first look at Visual Studio 2012 and the ASP.net 4.5 project template for WebForms
- Authentication and Authorization with ASP.net Webforms
- Building the Business Logic Layer classes with Entity Framework and Code First
- Linking the Business Logic Layer with DataControls to display data coming from the Database
- Strongly Typed Data Binding
- Strongly Typed Data Binding (continued…)
- ASP.NET MVC – URL routing
- Dynamic Data
- Unobtrusive JavaScript Validation in ASP.NET
- Sorting and Pagination in ASP.NET 4.5
- The Repository Pattern in ASP.NET – Part 1
- The Repository Pattern in ASP.NET – Part 2
References
Original content from Paul Cociuba; posted by MSPFE Editor Arvind Shyamsundar