Creating a Service with Windows Communication Foundation and LINQ to SQL, Page 2
Breaking down the LINQ query, the From clause defines a range cust and the searchable collection, customers. The Where predicate filters the query, and the Select clause builds the result collection. The parentheses means to treat the LINQ query result as an object and call First on it. The return type of the LINQ query in this example is IEnumerable(Of Customer) and the extension method First is defined for IEnumerable(Of T). For all intents and purposes, this means any class that implements IEnumerable(Of T) can return from a LINQ query, which is basically any collection. (For more on LINQ, LINQ to SQL, and extension methods check out my new book LINQ Unleashed for C# from Sams, August 2008.)
The remaining two steps are to define the DataContract and entity Table representing Customer objects and implement the DataContext to work with LINQ to SQL. All of these elements are implemented in the WCF service. Listing 3 implements the DataContext.
Listing 3: The DataContext, which represents all of the SQL and ADO.NET plumbing you no longer need to write if you use LINQ to SQL.
Public Class Northwind Inherits DataContext Private Shared ReadOnly connectionString As String = _ "Data Source=BUTLER;Initial Catalog=Northwind; _ Integrated Security=True" Public Sub New() MyBase.New(connectionString) End Sub End Class
It doesn't look like much, but if you assign Console.Out to Northwind.Log you will see that the LINQ to SQL plumbing handles connections to the database and conversions of LINQ queries to SQL queries. You are not required to write the code that uses command, adapter, or connection objects.
Listing 4 defines the DataContract for WCF and the entity Table for LINQ to SQL in a single class, Customer.
Listing 4: The DataContract and LINQ to SQL entity class are defined as a basic custom class with a few additional attributes.
<DataContract()> _ <Table(Name:="Customers")> _ Class Customer Private _customerID As String <DataMember()> _ <Column()> _ Public Property CustomerID() As String Get Return _customerID End Get Set(ByVal Value As String) _customerID = Value End Set End Property Private _customerName As String <DataMember()> _ <Column(Name:="CompanyName")> _ Public Property CustomerName() As String Get Return _customerName End Get Set(ByVal Value As String) _customerName = Value End Set End Property End Class
Listing 4 contains a basic class that maps two properties to two columns in the Northwind Customers table. The TableAttribute on the class tells LINQ to SQL which table (or view or stored procedure) to get the data from. The ColumnAttribute maps properties to columns in that table. If the property types and names match the columns, no named arguments are needed for the ColumnAttribute. The DataContract on the class and DataMember on the properties are present for WCF. These tell WCF that this type needs to be represented when clients consume this web service.
This is all you need to do to get data from a SQL database and return it from a service.
Consuming the LINQ to SQL and WCF Service
Now, create a console application. You can, of course, consume a service with any application, but keep it simple for now.
In your console application, add a reference to the CustomerService using Project|Add Service Reference in Visual Studio (see Figure 1). (Your port will change, but that doesn't matter.)
Figure 1: Add as Service reference to your client application.
|If you want to debug from your client into your service, set debug=true in the WCF service web.config file.|