ASP.NET is the technology used in the .NET Framework to build web applications. In this chapter, we’ll analyze the ASP.NET and Entity Framework integration, so a basic knowledge of data-binding techniques in ASP.NET is required. You can find more information on this topic on MSDN, in the “ASP.NET Data-Bound Web Server Controls Overview” article at http://mng.bz/c3k4.
You can use Entity Framework’s features in two different ways: you can use ASP.NET RAD support to directly tie them together; or you can manually manage the ObjectContext lifecycle by writing more code. The first approach has the main advantage of not requiring code, whereas the latter gives you maximum control over what is performed under the hood. Which is the best approach for your application is up to you: typically, the former is indicated in small (or quick-and-dirty) applications, because you can be very productive, whereas the latter is for enterprise applications. We’ll start with the simpler approach and then look at how to directly manage the ObjectContext lifecycle in a typical ASP.NET application.
Before we can move on, it’s useful to note that Entity Framework’s ObjectContext can be instantiated only once per page. If you want to build some kind of layer over Entity Framework (as you did in chapter 14), you’ll have to handle this task manually. If you prefer to let ASP.NET do the magic for you, just sit down and relax: there is a special control, called EntityDataSource that will perform most of the tasks for you. Let’s start by looking at what EntityDataSource can do.
Starting with version 2.0, ASP.NET offered a new approach to data binding, using a new set of web controls named data source controls. Data source controls are, in fact, used to enable a development approach based on Rapid Application Development (RAD) in Visual Studio, providing a drag-and-drop-based development environment.
You can build an entire application based on data source controls with the wizards and RAD tools integrated in Visual Studio. The result is markup code that includes the configuration for extracting data and for binding to the associated data control, such as the GridView or Repeater.
Several data source controls are available for different scenarios. These are the most used:
Every data source has a different set of pros and cons, depending on the approach you want to use in your application architecture.
SqlDataSource is used when you want to couple your database to your web interface. This situation isn’t ideal in common applications, but it may be useful in quick-and-dirty scenarios, when all you want is a GUI to manipulate your data. When you use SqlDataSource, the connection string and SQL query are saved directly in the markup, so this isn’t the best choice in terms of flexibility.
ObjectDataSource provides an alternative method of access in three-tier applications, where you have a separation between the data layer and business logic, and you manipulate data using object representations. This approach is suitable when you want a better architecture and the ability to build the graphical interface using a RAD approach. ObjectDataSource can use an EDM, but you’ll have no benefits: you’re using objects in a simple form.
LinqDataSource and EntityDataSource offer the same functionality against different data sources: LINQ to SQL’s DataContext and Entity Framework’s ObjectContext, respectively. They both use the same approach; they don’t use a tier to separate the data access from the interface, but use the O/RM capabilities directly. You can add your own validation and loading logic to both DataContext and ObjectContext by using partial classes.
Using the LinqDataSource and EntityDataSource controls prevents you from separating your data access strategy from your business rules. It may not be a good idea to directly expose the data access in the page. Putting the data access in the business logic tier is a better choice in terms of modularity and maintenance, resulting in a better application architecture. But if keeping the data access separate from the business rules isn’t a problem for you and your application, the EntityDataSource control is a very practical and productive way to go.
Using a data source control has the advantage of avoiding code in your pages, because the DataBind method is performed automatically, during the PreRender event, by the data control itself. If you have a Repeater control on your page, you simply have to set the DataSourceID property to the ID of your data source control. The magic behind the scenes is done by ASP.NET: the resulting page will print data out of your data source.
From a technical perspective, the EntityDataSource control is very similar to Linq-DataSource, because they’re both based on the System.Web.Extensions.IDynamic-DataSource interface. This interface is primarily used to ensure compatibility in applications based on Dynamic Data controls (which will be discussed in section 15.2).
In order to use EntityDataSource with ASP.NET 3.5, you need to reference the System.Web.Entity assembly, located in the Global Assembly Cache (GAC) and installed by .NET Framework 3.5 Service Pack 1. Entity Framework was added with Service Pack 1 and isn’t directly available with ASP.NET 3.5.
ASP.NET 4.0 directly supports this control.
To explore EntityDataSource’s capabilities, let’s build a simple application to show its features. You’ll build a simple web page that will show the products available from OrderIT. You’ll use this database in all the examples presented in this chapter.
To begin this little project, you need to locate the EntityDataSource control. You can find the EntityDataSource control in your toolbox, as shown in figure 15.1.
You can start by adding a data control, like a Repeater or ListView. Select the New Data Source option from the Choose Data Source smart task, as shown in figure 15.2. This smart task will appear when the editor is in design view.
The Data Source Configuration Wizard will guide you through a series of options. The most important step is the selection of your EDM and the entity that you want to display.
The first wizard step is shown in figure 15.3.
In this example, you’re using the OrderIT database hosted in the local SQL Server instance: choose Products as the EntitySetName in order to display all the products in the database. This step is shown in figure 15.4.
If you want to automatically let EntityDataSource handle inserts, updates, and deletes, all you have to do is select the corresponding check boxes in the wizard screen shown in figure 15.4. Given the common nature of ObjectContext, Entity-DataSource knows how to manipulate entities: the control uses the ObjectContext to persist your actions in the corresponding database, using the previously defined model. When you click the Finish button, the wizard exits, and the corresponding markup is generated in the page.
If you look at the resulting ASP.NET page markup, you’ll see what the EntityData-Source control needs to make things work. The markup is shown in this listing, with the key properties in bold.
<asp:ListView ID="ListView1" runat="server" DataKeyNames="ProductId" DataSourceID="EntityDataSource1"> ... </asp:ListView> <asp:EntityDataSource ID="EntityDataSource1" runat="server" ConnectionString="name=OrderITEntities" DefaultContainerName=" OrderITEntities" EntitySetName="Products"> </asp:EntityDataSource>
As you can see, ListView’s DataSourceID property is used to configure the corresponding data source control, so it can get the data from the source and display the value.
Speaking of EntityDataSource, the ConnectionString property is used to refer to the EDM previously defined, whereas DefaultContainerName is used to identify the ObjectContext. Finally, EntitySetName contains the entity set from which to get objects (and data).
In listing 15.1, you’re taking all the data from a table named Products, located in the OrderIT database, mapped on an EntitySet named Products, using the ObjectContext named OrderITEntities.
All you need to do to display the value is run the page shown in figure 15.5.
You don’t need to write any code to get this result: all the magic is done by the EntityDataSource and the associated data control, which in this example is a ListView.
Your mileage with this approach may vary. As already mentioned, if you want more control over what happens under the hood, don’t worry. We’ll soon look at a more powerful approach to integrating ASP.NET and Entity Framework. First, though, we need to look at Dynamic Data controls, because their features are interesting if you simply need to manipulate data using a nice looking interface.
ASP.NET Dynamic Data is a feature initially introduced in ASP.NET 3.5 Service Pack 1 and further enhanced in version 4. The idea behind this technology is to simplify the typical actions related to working with data: displaying, filtering, and altering data.
Dynamic Data controls ship with ASP.NET, and they support both Entity Framework and LINQ to SQL, using the LinqDataSource and EntityDataSource controls discussed previously. Dynamic Data is based on a simple assumption: because the ObjectContext has a fixed set of features that won’t change, even for different mappings, its calls can be generically created. Using generics and reflection, the typical operations performed by the ObjectContext can be standardized. The same principles are valid for LINQ to SQL.
Dynamic Data controls work with a special kind of project—the Dynamic Data Entities Web Application, which can be found with the other ASP.NET projects. You can see it highlighted in figure 15.6.
Dynamic Data controls are composed of a set of templates and pages, located in the DynamicData directory. In this directory, you can find the templates used to represent different types, such as strings, integers, Booleans, and so on.
To start with Dynamic Data, you define the model you’re going to work against, and the rest of the work will be performed by using the information already present in it. The model contains the list of entities, and each entity describes itself, so each set of entities can be represented and edited automatically.
The model and routes are registered in listing 15.2. The necessary code is partially generated by the wizard, but you need to add your context in order to use it with Dynamic Data.
This code explicitly sets the scaffold feature , so every entity is automatically displayed in the start page. If you prefer to control this list, you must turn it off. If you use the routing features from ASP.NET 4.0, the resulting URL will be similar to /Custom-ers/List.aspx, where Customers is the entity set to be managed, and List is the action. As you can see in listing 15.2, the Details, Edit, and Insert actions can be used to manage the respective statuses.
In figure 15.7, you can see the default results you’ll get when you display the Customer list from the model.
By default, the display template is inferred from the column’s type, but it can be specified too. Generally, you specify templates by creating a new class, specifically for this scenario, that extends the entity using the MetadataTypeAttribute attribute. Dynamic Data controls work with data annotations, a feature introduced in .NET Framework 3.5 SP1 and further enhanced in version 4. In this example, we’re using POCO entities, so the annotations are directly generated using the T4 engine (which was introduced in chapter 13). If you’re using the default entity-generation engine, you can use a partial class and the aforementioned MetadataTypeAttribute. More information on this topic is available from MSDN in the “MetadataTypeAttribute Class” article: http://mng.bz/q9hA.
In this example, we added some custom logic to the default generation engine by altering the CDSL inside the EDMX file to generate the exact code used to represent the additional properties required by data annotations. Data annotations work with attributes, as you can see in the following listing, which contains an entity generated with these annotations.
The annotations influence the way the property is displayed and how its value is validated:
You can see how Dynamic Data controls handles these attributes in figure 15.8. Data annotations are a very important way of using Entity Framework in ASP.NET. Their use isn’t limited to working with Dynamic Data controls but can be expanded to ASP.NET MVC model validation. You can find more information on the available attributes in the “System.ComponentModel.DataAnnotations Namespace” article on MSDN: http://mng.bz/2cWi.
We’re now finished with Dynamic Data controls. It’s time to learn how to directly manage the ObjectContext’s lifecycle in a typical ASP.NET application, how to handle it properly, and what the main aspects to consider are.
EntityDataSource and Dynamic Data controls are interesting if you want to be very productive, or if you just need a simple interface to display and manipulate your data. In real-world applications, though, where enterprise techniques are needed, this approach won’t work.
As you learned in chapter 14, it’s possible to isolate Entity Framework’s dependency from the application, using a different approach from the one already introduced in this chapter. By using repositories, you can avoid coupling and maintain better control over what is performed under the hood. The examples provided in chapter 14 introduced you to the basics of this subject. The purpose of using a repository is to simplify testability, and, at the same time, to provide flexibility. By using a clean approach, primarily based on interfaces, the use of repositories also avoids coupling, generally thanks to an Inversion of Control (IoC) container that wraps the complexity.
The example provided in this section is based on Unity, an IoC container that’s part of the Enterprise Library, created by the Microsoft Pattern & Practice team. The configuration is performed in the web.config file.
By using an IoC container, you can reuse part of the code already presented in chapter 14, which didn’t incorporate ASP.NET. We can reuse it here because we designed the application with great flexibility in mind.
To make sure your strategy-based repositories can be implemented, you need to build a set of classes that will encapsulate the logic, as illustrated in figure 15.9.
There are different ways to handle the ObjectContext’s lifecycle, but the best in web applications, in terms of flexibility and functionality, is to handle it per-request (as in the Context-per-Request pattern). Every request will have its own ObjectContext instance, shared by different repositories, with there generally being one instance of the ObjectContext per entity set.
This simplifies the problem in many ways, because different parts of the page can access the same context, and multiple actions can be completed at the same time. Thanks to the IQueryable interface, the real query to the database will be performed only when the entity set is effectively enumerated, so no tangible overhead is associated with this approach.
In order to support this scenario, you first need to create a basic implementation that gets the ObjectContext. We previously prepared an interface called IObjectContext that can support more scenarios, like unit testing, or Windows applications. The implementation is shown in the following listing.
The repositories were created in chapter 14, so we won’t address that topic here. The next step is to create the module to handle the per-request instance. This can easily be accomplished by writing an HttpModule.
You’ve handled the context, so now you need to build the module to manage the ObjectContext instance using the Context-per-Request pattern. The code is very simple, as you can see here.
The code speaks for itself: at the beginning of every request, the context is created , and then it’s destroyed at the end . Note that you must dispose of the ObjectContext, or memory leaks may occur. Remember also to register the module, which is an ASP.NET HttpModule, under the appropriate section in the web.config file; otherwise, you’ll receive an error informing you that the module isn’t configured.
In order to use the repository to display customers in the page, you need to use this code in a Web Form page:
C#
Products.DataSource = ApplicationContext.Current.Companies.OfType<Customer>(); Products.DataBind();
VB
Products.DataSource = ApplicationContext.Current.Companies.OfType(Of Customer); Products.DataBind()
As you can see, the access to repositories is wrapped in a singleton class, named ApplicationContext, which holds the reference to the repositories. The rest of the code you have already seen.
This approach, with POCO entities, gives you the freedom to change the implementation at any given time, because there’s no deep coupling between ASP.NET and Entity Framework. The approach based on repositories and the Context-per-Request patterns gives you good control over the ObjectContext lifecycle, too. The resulting web page is shown in figure 15.10, where an ASP.NET MVC view is used.
If you need more advanced features in your repositories, you can easily add more complexity to them using this design. Each piece is interchangeable, thanks to the IoC container.
Now we need to look at some common ASP.NET and Entity Framework scenarios and see what needs to be addressed when they’re used together.
You have to know a few things when working with Entity Framework in an ASP.NET application:
Now you know how to create web sites using ASP.NET WebForm technology.
In this chapter, we discussed the two main options offered by ASP.NET for handling Entity Framework’s ObjectContext. You can easily integrate them either automatically or manually.
Both EntityDataSource and Dynamic Data controls can make you very productive. In particular, Dynamic Data controls can work with the custom T4 template to generate rich data-editing interfaces, using data annotations to further enhance the generated interface. This approach has some limits in terms of controlling the ObjectContext creation, and it can’t be used to wrap the ObjectContext behind a domain model.
If you prefer to isolate Entity Framework, you can manually manage the ObjectContext. Doing so gives you great flexibility; but ObjectContext’s lifecycle needs to be carefully managed in web applications, where multiple instance of the same object may occur per request—this situation must be resolved. You can address this scenario by writing a specific set of classes that automatically instantiate the ObjectContext at the beginning of every request and destroy it when the request is completed. In this scenario, using an IoC container gives you the flexibility to control what happens when common tasks related to your entities are performed.
ASP.NET is the most common way to use Entity Framework; but as a part of the .NET Framework, Entity Framework isn’t limited to web pages: you can use Entity Framework in virtually any kind of application. The following chapters will look at using Entity Framework in n-tier and Windows-based applications.
3.15.151.32