Archive for the ‘Windows Communication Foundation (WCF)’ Category

Linq to SQL with WCF in a Multi Tiered Action - Part 2

June 2nd, 2008 by Sidar Ok

In the first part of this article, I tried to define a Users & Favorites scenario and the things to keep in mind about Linq to SQL. In this post I’ll continue building that application and show its implementation in different tiers connected with WCF.

Here are the sources for the article.

Service Layer Design (Cont’d from Part 1)

Service Host (Web Service in our case)

This is a host project (a plain Web project) needed to host our web service. It has our .svc files and needed configuration. In .svc file we have the mapping from contract to the implementation:

<%@ ServiceHost Language=”C#” Debug=”true” 
Service=”ServiceImplementations.UsersService” %>

And the endpoint configuration goes as follows:

   1: <system.serviceModel>
   2:         <behaviors>
   3:             <serviceBehaviors>
   4:                 <behavior name=”FavoritesServiceBehavior”>
   5:                     <serviceMetadata httpGetEnabled=”true” />
   6:                     <serviceDebug includeExceptionDetailInFaults=”false” />
   7:                 </behavior>
   8:                 <behavior name=”UsersServiceBehavior”>
   9:                     <serviceMetadata httpGetEnabled=”true” />
  10:                     <serviceDebug includeExceptionDetailInFaults=”false” />
  11:                 </behavior>
  12:             </serviceBehaviors>
  13:         </behaviors>
  14:         <services>
  15:             <service behaviorConfiguration=”FavoritesServiceBehavior”
  16: name=”ServiceImplementations.FavoritesService”>
  17:                 <endpoint address=”" binding=”wsHttpBinding”
  18: name=”IFavoritesService_Endpoint”
  19:                     contract=”ServiceContracts.IFavoritesService”>
  20:                     <identity>
  21:                         <dns value=”localhost” />
  22:                     </identity>
  23:                 </endpoint>
  24:             </service>
  25:             <service behaviorConfiguration=”UsersServiceBehavior”
  26: name=”ServiceImplementations.UsersService”>
  27:                 <endpoint address=”" binding=”wsHttpBinding”
  28: name=”IUsersService_Endpoint”
  29:                     contract=”ServiceContracts.IUsersService”>
  30:                     <identity>
  31:                         <dns value=”localhost” />
  32:                     </identity>
  33:                 </endpoint>
  34:             </service>
  35:         </services>
  36:     </system.serviceModel>

Service Clients (Consumers)

The client layer is a very thin façade to invoke the requested methods from the channel. Clients are meant to be called through controllers if you are using MVC, and in our case our web application will consume the service so the endpoint configurations will live in web tier:

   1: <system.serviceModel>
   2:     <client>
   3:       <endpoint binding=”wsHttpBinding” bindingConfiguration=”"
   4: contract=”ServiceContracts.IFavoritesService”
   5: address=”http://localhost/WebServiceHost/FavoritesService.svc”
   6:         name=”FavoritesClient”>
   7:         <identity>
   8:           <dns value=”localhost” />
   9:           <certificateReference storeName=”My” storeLocation=”LocalMachine”
  10:             x509FindType=”FindBySubjectDistinguishedName” />
  11:         </identity>
  12:       </endpoint>
  13:       <endpoint binding=”wsHttpBinding” bindingConfiguration=”"
  14: contract=”ServiceContracts.IUsersService”
  15: address=”http://localhost/WebServiceHost/UsersService.svc”
  16:         name=”UsersClient”>
  17:         <identity>
  18:           <dns value=”localhost” />
  19:           <certificateReference storeName=”My” storeLocation=”LocalMachine”
  20:             x509FindType=”FindBySubjectDistinguishedName” />
  21:         </identity>
  22:       </endpoint>
  23:     </client>
  24: </system.serviceModel>

Presentation

The challenge in the presentation tier is we need to maintain the state of the each entity according to the user interaction. For this purpose, I put 2 GridViews , one for Users and One for favorites to enable insert, update, delete and select operations.

We will bind strongly typed collections (IList<User> and IList<Favorite>) to our GridViews and we will use the ID fields of the objects to associate with the gridview, and then use them in the code behind:

Here is the definition for Users GridView:

   1: <asp:GridView ID=”usersGrid” runat=”server”
   2:     AutoGenerateColumns=”False” CellPadding=”4″
   3:     ForeColor=”#333333″ GridLines=”None”
   4:     DataKeyNames=”UserId”
   5:     OnRowDeleting=”usersGrid_RowDeleting”
   6:     OnRowUpdating=”usersGrid_RowUpdating”
   7:     OnSelectedIndexChanged=”usersGrid_SelectedIndexChanged”
   8:     OnSelectedIndexChanging=”usersGrid_SelectedIndexChanging”
   9:     OnRowCancelingEdit=”usersGrid_RowCancelingEdit”
  10:     OnRowEditing=”usersGrid_RowEditing”>
  11:     <RowStyle BackColor=”#F7F6F3″ ForeColor=”#333333″ />
  12:     <Columns>
  13:         <asp:CommandField ShowDeleteButton=”True” />
  14:         <asp:TemplateField HeaderText=”First Name”>
  15:             <ItemTemplate>
  16:                 <asp:Label ID=”firstNameLabel” runat=”server”
  17: Text=’<%# Bind(”FirstName”) %>’></asp:Label>
  18:             </ItemTemplate>
  19:             <EditItemTemplate>
  20:                 <asp:TextBox ID=”firstNameTextBox” runat=”server”
  21: Text=’<%# Bind(”FirstName”) %>’></asp:TextBox>
  22:             </EditItemTemplate>
  23:         </asp:TemplateField>
  24:         <asp:TemplateField HeaderText=”Last Name”>
  25:             <ItemTemplate>
  26:                 <asp:Label ID=”lastNameLabel” runat=”server”
  27: Text=’<%# Bind(”LastName”) %>’></asp:Label>
  28:             </ItemTemplate>
  29:             <EditItemTemplate>
  30:                 <asp:TextBox ID=”lastNameTextBox” runat=”server”
  31: Text=’<%# Bind(”LastName”) %>’></asp:TextBox>
  32:             </EditItemTemplate>
  33:         </asp:TemplateField>
  34:         <asp:CommandField ShowEditButton=”True” />
  35:         <asp:CommandField ShowSelectButton=”True” />
  36:     </Columns>
  37:     <FooterStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />
  38:     <PagerStyle BackColor=”#284775″ ForeColor=”White” HorizontalAlign=”Center” />
  39:     <SelectedRowStyle BackColor=”#E2DED6″ Font-Bold=”True” ForeColor=”#333333″ />
  40:     <HeaderStyle BackColor=”#5D7B9D” Font-Bold=”True” ForeColor=”White” />
  41:     <EditRowStyle BackColor=”#999999″ />
  42:     <AlternatingRowStyle BackColor=”White” ForeColor=”#284775″ />
  43:     </asp:GridView>

The one for Favorites is pretty much the same so I’ll go over Users grid.

Let’s go to code behind which is more important to us. We are going to do a batch update and send List of Users, and each user in the list will have their favorites. All the entities will have their latest status in their Status field.

Here is a sequence diagram to make things easier and more clearer to understand :

image

Picture 1. Sequence diagram of what’s happening

Now, in the page load, we are going to populate the Users GridView:

   1: if (!IsPostBack)
   2: {
   3:    try
   4:    {
   5:        if (SessionStateUtility.Users == null)
   6:        {
   7:            // error may occur during disposal, not caring for the time being
   8:            using (UsersClient client = new UsersClient())
   9:            {
  10:                SessionStateUtility.Users = client.GetAllUsers().ToList<User>();
  11:            }
  12:        }
  13:        BindUsersGrid(SessionStateUtility.Users, -1);
  14:    }
  15:    catch (Exception ex)
  16:    {
  17:        Response.Write(ex.ToString());
  18:    }
  19: }

In the grid, user can update and delete users from session. For insert, there is a separate panel included at the bottom with an add button. In the add button what we are doing is quite simple, just adding a new user to the session:

   1: protected void addUserButton_Click(object sender, EventArgs e)
   2: {
   3:     Debug.Assert(sender != null);
   4:     Debug.Assert(e != null);
   5: 
   6:     User u = new User()
   7:     {
   8:         FirstName = firstNameTextBox.Text,
   9:         LastName = lastNameTextBox.Text,
  10:         EMail = emailTextBox.Text,
  11:         Status = EntityStatus.New,
  12:         UserId = SessionStateUtility.NextUserId,
  13:     };
  14: 
  15:     SessionStateUtility.Users.Add(u);
  16: 
  17:     BindUsersGrid(SessionStateUtility.Users, -1);
  18: }

You’ll notice 2 things here, one of them is the Status is set to Entity Status.New . The other one is the SessionStateUtility class. This acts as a provider and a helper for User lists. The Users list that it provides is the below:

   1: /// <summary>
   2: /// Gets or sets the users.
   3: /// </summary>
   4: /// <value>The users.</value>
   5: public static List<User> Users
   6: {
   7:     get
   8:     {
   9:         Debug.Assert(HttpContext.Current != null);
  10:         Debug.Assert(HttpContext.Current.Session != null);
  11:
  12:         return HttpContext.Current.Session[“Users”] as List<User>;
  13:     }
  14:     set
  15:     {
  16:         Debug.Assert(HttpContext.Current != null);
  17:         Debug.Assert(HttpContext.Current.Session != null);
  18: 
  19:         HttpContext.Current.Session[“Users”] = value;
  20:     }
  21: }

And it provides another method to get NextUserId. This is necessary because since there can be multiple new records in the screen, we will need to identify them. Next User Id brings the next highest negative number that is available:

   1: /// <summary>
   2: /// Gets the next id.
   3: /// </summary>
   4: /// <value>The next id.</value>
   5: public static int NextUserId
   6: {
   7:    get
   8:    {
   9:        if (SessionStateUtility.Users.Count == 0)
  10:        {
  11:            return -1;
  12:        }
  13:        int minId = SessionStateUtility.Users.Min<User>(user => user.UserId);
  14:
  15:        if (minId > 0)
  16:        {
  17:            return -1;
  18:        }
  19: 
  20:        return –minId;
  21:    }
  22: }

And then we need to handle the grid events. I wrote a helper function to Get the User object from Selected row index in the grid (it retrieves from session)”

   1: private User GetUserFromRowIndex(int index)
   2: {
   3:     int userId = usersGrid.DataKeys[index].Value as int? ?? 0;
   4: 
   5:     //retrieve the instance in the session
   6:     User user = SessionStateUtility.Users.Single<User>(usr => usr.UserId == userId);
   7:     return user;
   8: }

Another helper function is there for just to get user’s full name formatted:

   1: private string GetFullNameForUser(User u)
   2: {
   3:     return String.Format(CultureInfo.InvariantCulture, “{0} {1}”, u.FirstName, u.LastName);
   4: }

And this one updates the UI fields for a selected user:

   1: private void UpdateUiForUser(User u)
   2: {
   3:    if (u != null)
   4:    {
   5:        favoritesPanel.Visible = true;
   6:        userNameLabel.Text = GetFullNameForUser(u);
   7:        BindFavoritesGrid(u.Favorites.ToList<Favorite>(), -1);
   8:    }
   9: }

And of course one method for binding the grid:

   1: private void BindUsersGrid(IList<User> users, int editIndex)
   2: {
   3:     usersGrid.DataSource = users
   4:     .Where<User>(usr=>usr.Status != EntityStatus.Deleted);// only bind non deleted ones
   5:     usersGrid.EditIndex = editIndex;
   6:     usersGrid.DataBind();
   7: }

As you can see we are not binding the deleted ones but we are still keeping them in the session because we need to know what is deleted when we send them back to the data tier.

Then within the light of these methods, here goes the SelectedIndex_Changing event handler. It updates the favorite’s grid for the selected user:

   1: protected void usersGrid_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
   2: {
   3:     Debug.Assert(sender != null);
   4:     Debug.Assert(e != null);
   5:     usersGrid.SelectedIndex = e.NewSelectedIndex;
   6: 
   7:     User u = GetUserFromRowIndex(e.NewSelectedIndex);
   8:     UpdateUiForUser(u);
   9: }

And when the row is being edited, following event handler will get executed:

   1: protected void usersGrid_RowEditing(object sender, GridViewEditEventArgs e)
   2: {
   3:     Debug.Assert(sender != null);
   4:     Debug.Assert(e != null);
   5:
   6:     usersGrid.SelectedIndex = e.NewEditIndex;
   7: 
   8:     BindUsersGrid(SessionStateUtility.Users, e.NewEditIndex);
   9: }

And after user clicks edit, when he/she clicks update following handler will run:

   1: protected void usersGrid_RowUpdating(object sender, GridViewUpdateEventArgs e)
   2: {
   3:     Debug.Assert(sender != null);
   4:     Debug.Assert(e != null);
   5: 
   6:     int userId = usersGrid.DataKeys[e.RowIndex].Value as int? ?? 0;
   7:     //retrieve the instance in the session
   8:     User user = SessionStateUtility.Users.Single<User>(usr => usr.UserId == userId);
   9:     user.FirstName = (usersGrid.Rows[e.RowIndex].FindControl(“firstNameTextBox”)
  10: as TextBox).Text;
  11:     user.LastName = (usersGrid.Rows[e.RowIndex].FindControl(“lastNameTextBox”)
  12: as TextBox).Text;
  13:
  14:     user.Status = user.Status == EntityStatus.New ?
  15: EntityStatus.New :EntityStatus.Updated; // manage the state
  16: 
  17:     BindUsersGrid(SessionStateUtility.Users, -1);// back to plain mode
  18: }

As you see if the edited users’ current status is already new, then we are not modifying it. But else, the state is changed to the updated.

A similar situation also exists for deletion. Have a look at the handler below:

   1: protected void usersGrid_RowDeleting(object sender, GridViewDeleteEventArgs e)
   2: {
   3:     Debug.Assert(sender != null);
   4:     Debug.Assert(e != null);
   5: 
   6:     User user = GetUserFromRowIndex(e.RowIndex);
   7:     // If user is new and deleted now, we shouldnt send it over the wire again
   8:     if (user.Status == EntityStatus.New)
   9:     {
  10:         SessionStateUtility.Users.Remove(user);
  11:     }
  12:     else
  13:     {
  14:         user.Status = EntityStatus.Deleted;
  15:     }
  16: 
  17:     BindUsersGrid(SessionStateUtility.Users, -1);// back to plain mode
  18: }

We have done our work as a presentation layer, and we are now sending all the data through the service to data layer along with all the information needed for it to manage the generation of the SQL Statements (fingers crossed)

Data Layer Design

Since we are going to implement the IUsersDataAccess contract, we need to implement 4 methods: But I’ll focus on 2 of them especially. First one is GetAllUsers:

   1: /// <summary>
   2: /// Gets all users.
   3: /// </summary>
   4: /// <returns>The list of all users along with their favorites.</returns>
   5: public IList<User> GetAllUsers()
   6: {
   7:     using (FavoritesEntitiesDataContext context = new FavoritesEntitiesDataContext())
   8:     {
   9:         DataLoadOptions options = new DataLoadOptions();
  10:         options.LoadWith<User>(u => u.Favorites);
  11: 
  12:         context.LoadOptions = options; // load with favorites
  13:         context.ObjectTrackingEnabled = false; // retrieving data read only
  14: 
  15:         return context.Users.ToList<User>();
  16:     }
  17: }

As you see, we are telling the context to load every user with their favorites. This can cause some damage if these tables are very big, and there are methods to enhance this experience.

The UpdateUsers(IList) method is a bit more complicated. Here are the list of things that we are going to do:

  • Attach the users to the context who have their status “Updated’ – obvious one

  • Attach the users to the context who have their status “Deleted’ – since the context does not know about an object that is not attached, we need to attach them too.

  • We aren’t going to attach the objects to insert, because Data Context doesn’t need to know about the objects those are being added.

  • Call the relevant of one of those by looking at their status: InsertAllOnSubmit, DeleteAllOnSubmit

  • Do the same for the child entities of each. (Keep in mind that we need to delete all children regardless of their status if their parent is deleted)

So now hopefully the following implementation will be more understandable:

   1: /// <summary>
   2: /// Updates the users list.
   3: /// </summary>
   4: /// <param name=”updateList”>The list of users to perform the operations.</param>
   5: public void UpdateUsers(IList<User> updateList)
   6: {
   7:     using(FavoritesEntitiesDataContext context = new FavoritesEntitiesDataContext())
   8:     {
   9:         context.Users.AttachAll<User>(
  10: updateList.Where<User>(
  11:   usr=>usr.Status == EntityStatus.Updated ||
  12:   usr.Status == EntityStatus.Deleted), true);
  13:         context.Users.InsertAllOnSubmit<User>(
  14: updateList.Where<User>(
  15:   usr=>usr.Status == EntityStatus.New));
  16:         context.Users.DeleteAllOnSubmit<User>
  17: (updateList.Where<User>(usr => usr.Status == EntityStatus.Deleted));
  18: 
  19:         // do the same for the children
  20:         // If the parent is deleted, to prevent orphan records we need to delete
  21:         // children too
  22:         foreach (User user in updateList)
  23:         {
  24:             context.Favorites.AttachAll<Favorite>
  25: (user.Favorites.Where<Favorite>
  26:   (fav=>fav.Status == EntityStatus.Updated
  27:   || fav.Status == EntityStatus.Deleted
  28:   || fav.User.Status == EntityStatus.Deleted
  29:   || fav.User.Status == EntityStatus.Updated));
  30:             //we shouldnt insert the new child records of deleted entities
  31:             context.Favorites.InsertAllOnSubmit<Favorite>
  32: (user.Favorites.Where<Favorite>
  33:   (fav => fav.Status == EntityStatus.New
  34:   && fav.User.Status != EntityStatus.Deleted));
  35:             context.Favorites.DeleteAllOnSubmit<Favorite>
  36: (user.Favorites.Where<Favorite>
  37: (fav => fav.Status == EntityStatus.Deleted ||
  38: fav.User.Status == EntityStatus.Deleted));
  39:         }
  40: 
  41:         context.SubmitChanges();
  42:     }
  43: }

That’s the end of fun(!) folks. As you have seen already, there is some work involved with making Linq to SQL work in Multi Tiered architecture, but it is doable still. Again, download the sources and please don’t hesitate to post any comments, criticisms or crossword puzzles via here or sidarok@sidarok.com, they are all welcome.

kick it on DotNetKicks.com

Share it on: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • Blogosphere News
  • e-mail
  • YahooMyWeb
  • DotNetKicks
  • DZone

Linq to SQL with WCF in a Multi Tiered Action – Part 1

May 26th, 2008 by Sidar Ok

In many places, forums, blogs, or techy talks with some colleagues I hear some ongoing urban legends about Linq to SQL I came across:

  • You can not implement multi tiered applications with Linq to SQL

  • Linq to SQL can not be used for enterprise level applications

I can’t say that both of these statements are particularly wrong or right, of course Linq to SQL can not handle every scenario but in fairness it handles most of the scenarios sometimes even better than some other RAD oriented ORM s. In this post I will create a simulation of an enterprise web application, having its Data Access, Services, and Presentation Layers separated and let them communicate with each other (err.., at least from service to UI) through WCF – Windows Communication Foundation.

This will be a couple of (may be more) posts, and this is the first part of it. I’ll post the sample code with the next post.

I have to say that this article is neither an introduction to Linq to SQL nor to WCF, so you need basic knowledge of both worlds in order to benefit from this mash up. We will develop an application step by step with an easy scenario but will have the most important characteristics of a disconnected (from DataContext perspective), multi layered enterprise architecture.

Since this architecture is more scalable and reliable, implementing it with Linq to SQL has also some tricks to keep in mind:

  • Our DataContext will be dead most of the time. So we won’t be able to benefit Object Tracking to generate our SQL statements out of the box.

  • This also brings to the table that we have to know what entities to delete, what to insert, and what to update. We can not just “do it” and submit changes as we are doing it in connected mode. This means that we have to maintain the state of the objects manually (sorry folks, I feel the same pain).

  • The transport of the data over the wire is another problem, since we don’t write the entities on our own(and in the case of an amend to them the designer of Linq to SQL can be very aggressive) so it brings us into 2 common situation

  • We can create our own entities, and write translators to convert from Linq Entities to our very own ones.

  • We can try to customize Linq Entities in the ways we are able to.

Since the first one is obvious and the straight forward to implement, we will go down the second route to explore the boundaries of this customization.

To make it clearer that what I will do, here is a basic but a functional schema of the resulting n-tier application

s

Picture 1 – Architectural schema of the sample app.

In our example, we are going to use Linq to SQL as an ORM Mapper. So as you see in the schema, Linq to SQL doesn’t give us the heaven of not writing a DAL Layer at all. But it reduces both stored queries/procedures and amount of mapping that we had to do manually before.

Developing the Application

Scenario

The scenario I came up with is a favorites web site, that consist of 2 simple pages enabling its users to Insert, Delete, Update and Retrieve users and their favorites when requested. 1 user can have many favorites.

We will simply place 2 Grid Views in the page and handle their events to make the necessary modifications on the model itself. This will also demonstrate a common usage.

Design

Entities

Here is the object diagram of the entities; they are the same as the DB tables:

clip_image004

Picture 2.Entity Diagram

See the additional “Version” fields in the entities; they are type of Binary in .NET and TimeStamps in SQL Server 2005. We will use them to let Linq to SQL handle the concurrency issues for us.

Since we are going to employ a web service by the help of WCF, we need to mark our entities as DataContract to make it available for serialization through DataContractSerializer. We can do that by right clicking on the designer and going to properties, and changing Serialization property to unidirectional as in the picture follows:

clip_image006

Picture 3. Properties window

After doing and saving this we will see in the designer.cs file, we have our Entities marked as DataContract and members as DataMember s.

As mentioned earlier before, we need to maintain our entites state – to know whether they are deleted, inserted, or updated. To do this I am going to define an enumeration as follows:

   1: /// <summary>
   2:     /// The enum helps to identify what is the latest state of the entity.
   3:     /// </summary>
   4:     public enum EntityStatus
   5:     {
   6:         /// <summary>
   7:         /// The entity mode is not set.
   8:         /// </summary>
   9:         None = 0,
  10:         /// <summary>
  11:         /// The entity is brand new.
  12:         /// </summary>
  13:         New = 1,
  14:         /// <summary>
  15:         /// Entity is updated. 
  16:         /// </summary>
  17:         Updated = 2,
  18:         /// <summary>
  19:         /// Entity is deleted. 
  20:         /// </summary>
  21:         Deleted = 3,
  22:     }

We are going to have this field in every entity, so let’s define a Base Entity with this field in it:

   1: [DataContract]
   2: public class BaseEntity
   3: {
   4:   /// <summary>
   5:   /// Gets or sets the status of the entity.
   6:   /// </summary>
   7:   /// <value>The status.</value>
   8: 
   9:   [DataMember]
  10:   public EntityStatus Status { get; set; }
  11: }

 

And then, all we need to do is to create partial classes for our Entities and extend them from base entity:

   1: public partial class User : BaseEntity
   2: {
   3: 
   4: }
   5: 
   6: public partial class Favorite : BaseEntity
   7: {
   8: 
   9: }
  10: 

Now our entities are ready to travel safely along with their arsenal.

Service Layer Design

As we are going to use WCF, we need to have our:

  • Service Contracts (Interfaces)
  • Service Implementations (Concrete classes)
  • Service Clients (Consumers)
  • Service Host (Web service in our case)

Service Contracts

We will have 2 services: Favorites Service and Users Service. It will have 4 methods: 2 Gets and 2 Updates. We will do the insertion, update, and deletion depending on the status so there is no need to determine separate functions for all. Here is the contract for User:

   1: /// <summary>
   2: /// Contract for user operations 
   3: /// </summary>
   4: 
   5: [ServiceContract]
   6: public interface IUsersService
   7: {
   8: /// <summary>
   9: /// Gets all users.
  10: /// </summary>
  11: /// <returns></returns>
  12: 
  13:   [OperationContract]
  14:   IList<User> GetAllUsers();
  15: 
  16: /// <summary>
  17: /// Updates the user.
  18: /// </summary>
  19: /// <param name=”user”>The user.</param>
  20: 
  21:   [OperationContract]
  22:   void UpdateUser(User user);
  23: 
  24: /// <summary>
  25: /// Gets the user by id.
  26: /// </summary>
  27: /// <param name=”id”>The id.</param>
  28: /// <returns></returns>
  29: 
  30:   [OperationContract]
  31:   User GetUserById(int id);
  32: 
  33: /// <summary>
  34: /// Updates the users in the list according to their state.
  35: /// </summary>
  36: /// <param name=”updateList”>The update list.</param>
  37: 
  38:   [OperationContract]
  39:   void UpdateUsers(IList<User> updateList);
  40: }

And here is the contract for Favorites Service:

   1: /// <summary>
   2: /// Contract for favorites service
   3: /// </summary>
   4: [ServiceContract]
   5: public interface IFavoritesService
   6: {
   7:   /// <summary>
   8:   /// Gets the favorites for user.
   9:   /// </summary>
  10:   /// <param name=”user”>The user.</param>
  11:   /// <returns></returns>
  12:   [OperationContract]
  13:   IList<Favorite> GetFavoritesForUser(User user);
  14: 
  15:   /// <summary>
  16:   /// Updates the favorites for user.
  17:   /// </summary>
  18:   /// <param name=”user”>The user.</param>
  19:   [OperationContract]
  20:   void UpdateFavoritesForUser(User user);
  21: }

Service Implementations (Concrete classes)

Since we are developing a db application with no business logic at all, the service layer implementors are pretty lean & mean. Here is the Service implementation for UserService

   1: [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
   2: public class UsersService : IUsersService
   3: {
   4:     IUsersDataAccess DataAccess { get; set; }
   5: 
   6:     public UsersService()
   7:     {
   8:         DataAccess = new UsersDataAccess();
   9:
  10:     }
  11: 
  12:     #region IUsersService Members
  13: 
  14:     /// <summary>
  15:     /// Gets all users.
  16:     /// </summary>
  17:     /// <returns></returns>
  18:     [OperationBehavior]
  19:     public IList<User> GetAllUsers()
  20:     {
  21:         return DataAccess.GetAllUsers();
  22:     }
  23: 
  24:     /// <summary>
  25:     /// Updates the user.
  26:     /// </summary>
  27:     /// <param name=”user”>The user.</param>
  28:     [OperationBehavior]
  29:     public void UpdateUser(User user)
  30:     {
  31:         DataAccess.UpdateUser(user);
  32:     }
  33: 
  34:     /// <summary>
  35:     /// Gets the user by id.
  36:     /// </summary>
  37:     /// <param name=”id”>The id.</param>
  38:     /// <returns></returns>
  39:     [OperationBehavior]
  40:     public User GetUserById(int id)
  41:     {
  42:         return DataAccess.GetUserById(id);
  43:     }
  44: 
  45:     /// <summary>
  46:     /// Updates the users in the list according to their state.
  47:     /// </summary>
  48:     /// <param name=”updateList”>The update list.</param>
  49:     [OperationBehavior]
  50:     public void UpdateUsers(IList<User> updateList)
  51:     {
  52:         DataAccess.UpdateUsers(updateList);
  53:     }
  54: 
  55:     #endregion
  56: }

And as you can imagine the favorite service implementation is pretty much the same.

This has been long enough, so let’s cut it here. In the next post, I will talk about the presentation, service and data layer implementations. By that, we will see how to best approach to modifying these entities in a data grid, pass them through the WCF Proxy and commit the changes (insert, update, delete) to the SQL 2005 database. I will also provide the source codes with the next post. Stay tuned until then.

For part 2 : http://www.sidarok.com/web/blog/content/2008/06/02/linq-to-sql-with-wcf-in-a-multi-tiered-action-part-2.html .

kick it on DotNetKicks.com


Share it on: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • Sphinn
  • del.icio.us
  • Facebook
  • Mixx
  • Google
  • Blogosphere News
  • e-mail
  • YahooMyWeb
  • DotNetKicks
  • DZone