ptg 994 CHAPTER 20 Data Access with LINQ to SQL from the ObjectDataSource control and provides default values for several ObjectDataSource control properties. For example, you could swap the ObjectDataSource control in Listing 20.33 with the follow- ing EntityDataSource control: <custom:EntityDataSource id=”srcMovies” TypeName=”Movie” EnablePaging=”true” SortParameterName=”orderBy” Runat=”Server” /> Why use the EntityDataSource control? Less typing. I don’t want to program all day; I want to see a movie. Performing Validation with the EntityBase Class One complaint I’ve always had about ASP.NET Framework is that validation happens at the wrong place. When building ASP.NET pages, you write the vast majority of your vali- dation code in the user interface layer instead of your business logic layer where your vali- dation code properly belongs. Performing validation in your user interface layer is bad for two main reasons. First, it means that if you switch user interfaces for your application, you must rewrite all your validation logic. For example, you might want to create a cool Silverlight interface for your application. In that case, you have to write all your validation logic again from scratch. Validation logic should be user interface-independent. Also, placing your validation logic in your user interface layer means that you have to rewrite the exact same validation logic on each page that you use an entity. This is an extraordinary time waster. I want to write my validation logic for an entity once and use the same logic everywhere. The EntityBase class includes a Validate() method that you can use to incorporate validation logic into your entities (and thus, your business logic layer). Listing 20.34 illustrates how you can write the Movie class so that it validates the Title, Director, and DateReleased properties. LISTING 20.34 ShowEntityBase\App_Code\Movie.cs using System; public partial class Movie : EntityBase<Movie> { From the Library of Wow! eBook ptg 995 Creating a Custom LINQ Entity Base Class 20 protected override void Validate() { // Title is required if (!ValidationUtility.SatisfiesRequired(Title)) ValidationErrors.Add(“Title”, “Required”); // Director is required if (!ValidationUtility.SatisfiesRequired(Director)) ValidationErrors.Add(“Director”, “Required”); // DateReleased is required if (DateReleased == DateTime.MinValue) ValidationErrors.Add(“DateReleased”, “Required”); // DateReleased can’t be more than 10 years ago if ((DateTime.Now.Year - DateReleased.Year) > 10) ValidationErrors.AddIfNotAlready(“DateReleased”, “Movie too old”); } } The Validate() method validates the properties of the Movie entity. The method takes advantage of the ValidationUtility class. The ValidationUtility class contains a set of methods to make it easier to perform standard types of validation: . SatisfiesRequired()—Enables you to check whether an expression has a value. . SatisfiesType()—Enables you to validate against a regular expression defined in the Web.config file. . SatisfiesExpression()—Enables you to validate against a regular expression. . IsInRole()—Enables you to check whether the current user is in a particular role. . IsUserName()—Enables you to check whether the current user has a particular username. . ShowValidationErrors()—Displays validation errors on a page. The ASP.NET page in Listing 20.35 demonstrates how you take advantage of entity valida- tion when inserting new movie records into the database (see Figure 20.3). From the Library of Wow! eBook ptg 996 CHAPTER 20 Data Access with LINQ to SQL LISTING 20.35 ShowEntityBase\InsertMovie.aspx <%@ Page Language=”C#” Trace=”true” %> <%@ Register TagPrefix=”custom” Namespace=”Superexpert.Controls” %> <!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected void frmMovie_ItemInserted ( object sender, FormViewInsertedEventArgs e ) { if (e.Exception != null) { e.ExceptionHandled = true; e.KeepInInsertMode = true; ValidationUtility.ShowValidationErrors(this, e.Exception); } } </script> FIGURE 20.3 Performing entity validation. From the Library of Wow! eBook ptg 997 Creating a Custom LINQ Entity Base Class 20 <html xmlns=”http://www.w3.org/1999/xhtml”> <head id=”Head1” runat=”server”> <title>Insert Movie</title> </head> <body> <form id=”form1” runat=”server”> <div> <asp:FormView id=”frmMovie” DataSourceID=”srcMovies” DefaultMode=”Insert” OnItemInserted=”frmMovie_ItemInserted” Runat=”Server”> <InsertItemTemplate> <asp:Label id=”lblTitle” Text=”Title:” AssociatedControlID=”txtTitle” Runat=”server” /> <br /> <asp:TextBox id=”txtTitle” Text=’<%# Bind(“Title”) %>’ Runat=”server” /> <custom:EntityCallOutValidator id=”valTitle” PropertyName=”Title” Runat=”Server” /> <br /><br /> <asp:Label id=”lblCategory” Text=”Category:” AssociatedControlID=”ddlCategory” Runat=”server” /> <br /> <asp:DropDownList id=”ddlCategory” DataSourceId=”srcMovieCategories” SelectedValue=’<%# Bind(“CategoryId”) %>’ DataTextField=”Name” DataValueField=”Id” Runat=”server” /> <asp:ObjectDataSource id=”srcMovieCategories” From the Library of Wow! eBook ptg 998 CHAPTER 20 Data Access with LINQ to SQL TypeName=”MovieCategory” SelectMethod=”Select” Runat=”Server” /> <br /><br / > <asp:Label id=”lblDirector” Text=”Director:” AssociatedControlID=”txtDirector” Runat=”server” /> <br /> <asp:TextBox id=”txtDirector” Text=’<%# Bind(“Director”) %>’ Runat=”server” /> <custom:EntityCallOutValidator id=”valDirector” PropertyName=”Director” Runat=”Server” /> <br /><br /> <asp:Label id=”lblDescription” Text=”Description:” AssociatedControlID=”txtDescription” Runat=”server” /> <br /> <asp:TextBox id=”txtDescription” Text=’<%# Bind(“Description”) %>’ TextMode=”MultiLine” Columns=”60” Rows=”3” Runat=”server” /> <br /><br /> <asp:Label id=”lblDateReleased” Text=”Date Released:” AssociatedControlID=”txtDateReleased” Runat=”server” /> <br /> <asp:TextBox id=”txtDateReleased” From the Library of Wow! eBook ptg 999 Creating a Custom LINQ Entity Base Class 20 Text=’<%# Bind(“DateReleased”) %>’ Runat=”server” /> <custom:EntityCallOutValidator id=”valDateReleased” PropertyName=”DateReleased” ControlToValidate=”txtDateReleased” TypeName=”date” Runat=”Server” /> <br /><br /> <asp:Button id=”btnInsert” Text=”Insert” CommandName=”Insert” Runat=”server” /> </InsertItemTemplate> </asp:FormView> <hr /> <asp:GridView id=”grdMovies” DataSourceID=”srcMovies” Runat=”server” /> <custom:EntityDataSource id=”srcMovies” TypeName=”Movie” Runat=”server” /> </div> </form> </body> </html> You should notice several things about the page in Listing 20.35. First, the page includes a method for handling the FormView control’s ItemInserted event. This handler checks for an exception. If Movie.Validate() creates one or more validation errors, the Movie entity throws a ValidationException when inserting or updating automatically. If there is an exception, the exception is passed to the ValidationUtility.ShowValidationErrors() method. The ShowValidationErrors() method finds the EntityCallOutValidator that corresponds to each validation error and displays the correct error message. From the Library of Wow! eBook ptg 1000 CHAPTER 20 Data Access with LINQ to SQL The Validate() method executes only if a Movie entity can be created. If someone enters the wrong type of value into a field, the ObjectDataSource can’t even create the entity and the Validate() method never executes. The EntityCallOutValidator associated with the DateReleased property includes ControlToValidate and TypeName properties. This validation control checks whether the value entered into the DateReleased TextBox is a valid date even before the Movie entity is created. Summary We covered a lot of material over the course of this chapter. In the first part, we discussed all the features of C# and VB.NET used to support LINQ, such as anonymous types, exten- sion methods, and lambda expressions. Next, we discussed LINQ to SQL entities. You learned how to build entities that represent your database objects both by hand and by using the LINQ to SQL Designer. We also briefly examined the LinqDataSource control. In the following part, we discussed how you can perform basic database operations with LINQ to SQL. For example, you learned how to select records, page through records, and cache records. You also learned how to insert, update, and delete database records with LINQ to SQL. In the final part of this chapter, you learned how to build a custom LINQ to SQL base class. You learned how to use this class to support selecting, inserting, deleting, and updat- ing entities without writing any code. You also learned how to add validation logic to your entities. From the Library of Wow! eBook ptg CHAPTER 21 Data Access with WCF Data Services IN THIS CHAPTER . Overview of WCF Data Services . Using Data Services with a Service Reference . Using Data Services with a Data Context . Summary Throughout this section of the book, we covered a wide variety of ways to get data to and from your web forms. In a standard n-tier model, the web application would talk to a middle tier containing business logic, which would in turn talk to a data tier responsible for communicating with the database. Although this is a perfectly adequate model, to handle the scalability and performance demands of modern distributed applications, we need something a bit more flexible. In large organizations we might have dozens of services exposed by multiple departments and multiple web applica- tions that need to consume those services. In this case, we can’t just add a reference to the Business Logic Layer (BLL) and start invoking methods. This chapter shows you how to use WCF Data Services to facilitate high-performance, scalable, distributed applica- tions by exposing entity models as RESTful web services that can be reused by many applications on many plat- forms. We provide an overview of the WCF Data Services technology and provide samples of some of the ways your ASP.NET application can consume these services. Overview of WCF Data Services When you see data access samples, most of them illustrate making a direct database connection from the web server (even if it’s from a data tier) to the database. Although this is fine for illustrative purposes, it’s not that practical. In many production environments, firewalls and other secu- rity systems prevent direct database connections of any From the Library of Wow! eBook ptg 1002 CHAPTER 21 Data Access with WCF Data Services kind. As previously mentioned, in many service-oriented, distributed systems, client code must go through a service to read or write any data. In the past, developers had to manually create their own service-based facades in front of the database, generally creating headaches and extra work. WCF Data Services aims to solve some of these problems. A WCF Data Service is a standardized service that exposes underlying relational data as a RESTful Web Service. This means that there’s no WSDL, no ASMX, just a convention for building URL-based queries and using the AtomPub or JSON protocols for sending data over the wire. It is beyond the scope of this book to go into too much detail on how to build WCF Data Services or create the underlying Entity Models exposed by WCF Data Services. For more information on these services, read the MSDN documentation at http://msdn.microsoft.com/en-us/data/bb931106.aspx. The following two sections show you how to allow your ASP.NET application to commu- nicate with a WCF Data Service, either by using a Service Reference or by using the client- side DataServiceContext class directly. Using Data Services with a Service Reference If you’ve used Visual Studio for any length of time, you’re probably familiar with the ability to add service references to existing projects. These either discover services in the current solution, or you can enter the URL of a WCF service and the service reference creates a client-side proxy for you. Up until now, this has worked only for regular web services. With Visual Studio 2010 and WCF Data Services, you can add a Service Reference to a WCF Data Service. This Service Reference can create a special client proxy for you, one that exposes all the entities for the service and handles all the change tracking and other heavy lifting that, as a service consumer, you just don’t want to have to deal with manually. Figure 21.1 shows the screen you see when attempting to add a service reference to a WCF Data Service. Each of the entities exposed by the data service appear as properties on the client proxy generated. To illustrate how we might consume a WCF Data Service from an ASP.NET application, let’s use an example that is a little bit more fun than the typical “Hello World” sample. Let’s say that you work for a fabulously successful video game company and your most popular game, Zombie Killa, has an incredible multiplayer mode. You’ve been asked to make the kill list and scores available on the web. The team that keeps that information won’t let you access its database directly for many (very good) reasons. Instead, it set up a WCF Data Service that exposes some of the key entities that you need to create your high scores website. From the Library of Wow! eBook ptg 1003 Using Data Services with a Service Reference FIGURE 21.1 Adding a service reference to a WCF Data Service. The first thing to do is add a service reference to its service, which you can see in Figure 21.1. This creates a client-side proxy that enables your code to treat the entities like regular LINQ data sources. Your LINQ queries convert into the WCF Data Services URL syntax, and the data coming back from the service converts into instances of the classes generated when you added the service reference. Now that you have your service reference, you’re ready to access the data service. For this sample, we’ve been asked to create a My Kills page that shows all the zombies a particular player has killed and the weapons she used. We created a MyKills.aspx page and then added the code from Listing 21.1 to the Page_Load() method. In addition to enabling us to write LINQ queries against specific entities, we can also invoke custom methods made available on the service. The game team didn’t want us to try to create the My Kills filter on our own because it might change over time, so it provided a method on the service called “GetMyKills” that we can execute. The amazing thing is that the result of this custom method execution is still queryable, enabling us to further filter, page, and sort the results. LISTING 21.1 Page_Load for MyKills.aspx.cs protected void Page_Load(object sender, EventArgs e) { ZombieKillaService.ZombieKillaContainer svc = new ZombieKillaService.ZombieKillaContainer( new Uri(“http://localhost:5000/ZombieKilla.svc”)); var q = from Kill kill in svc.CreateQuery<Kill>(“GetMyKills”) 21 From the Library of Wow! eBook . can be reused by many applications on many plat- forms. We provide an overview of the WCF Data Services technology and provide samples of some of the ways your ASP. NET application can consume. services, read the MSDN documentation at http://msdn.microsoft.com/en-us/data/bb931106.aspx. The following two sections show you how to allow your ASP. NET application to commu- nicate with a WCF. Namespace=”Superexpert.Controls” %> <!DOCTYPE html PUBLIC -/ /W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”> <script runat=”server”> protected