WCF Related Posts by ThinqLinq

Using Rx to consume a Task based WCF service

Among the many changes that Dev 11 brings is the new default when adding a service reference to generate Task based proxy methods rather than using the APM flavor (using the BeginXXX – EndXXX model). In this post, we’ll look at creating a simple service and then consuming it using the Reactive Extensions. Let’s start by defining the service interface and implementation:

Imports System.ServiceModel
Imports System.Threading 

<ServiceContract()>
Public Interface ISimpleServicesvc

    <OperationContract()>
    Function DoSomethingCool(input As String) As String

End Interface

Public Class SimpleServicesvc
    Implements ISimpleServicesvc

    Public Function DoSomethingCool(input As String) As String Implements ISimpleServicesvc.DoSomethingCool
        Return (String.Join("", From letter In input.ToCharArray()
               Order By letter
               Distinct))
    End Function

End Class

Essentially here we are just taking a string input and returning the distinct characters sorted. The details of the service in this case are trivial. Our focus here is how to implement the service client. We start by adding a service reference in our client application by right clicking on the project and selecting Add Service Reference. (Alternatively, you can now press Ctrl-Q and request to “Add Service Reference” from there. From the dialog, you can still use the “Discover” button to locate the service as long as it is in your solution.

image

One thing to note is that the proxy classes are now by default generated using Task based methods rather than the previous IAsyncResult AMP method.

image

As a result, the definition of the proxy class is as follows:

Public Function DoSomethingCoolAsync(ByVal input As String) 
                 As System.Threading.Tasks.Task(Of String) 
                 Implements SimpleService.ISimpleServicesvc.DoSomethingCoolAsync
    Return MyBase.Channel.DoSomethingCoolAsync(input)
End Function

If we wanted to consume this using the new Async/Await, we could do it as follows:

Private Async Sub SubmitClicked() Handles SubmitButton.Click
   Dim svc = New SimpleService.SimpleServicesvcClient()
   Dim req = Await svc.DoSomethingCoolAsync(InputText.Text)
   OutputText.Text = req
End Sub

Of course, to put the LINQ spin on this, let’s see the Rx version to do the same thing:

Private Async Sub SubmitClicked() Handles SubmitButton.Click
    Dim svc = New SimpleService.SimpleServicesvcClient()
    Dim req = svc.DoSomethingCoolAsync(InputText.Text).ToObservable()
    req.ObserveOnDispatcher().Subscribe(Sub(val) OutputText.Text = val)
End Sub

We start by turning the Task into an Observable producer using the ToObservable extension method. We then subscribe to the observable making sure to return back to the dispatcher thread because the task based service is run on a taskpool thread. Of course in this case, we are subscribing on every button click. With Rx, we could wire the button click and service request up on form navigate and unwire it when navigating from the form as follows:

Private requestDisposable As IDisposable
Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
    Dim svc = New SimpleService.SimpleServicesvcClient

    requestDisposable = (From click In Observable.FromEventPattern(Of RoutedEventArgs)(SubmitButton, "Click")
                        From req In svc.DoSomethingCoolAsync(InputText.Text).ToObservable()
                        Select req).
                        ObserveOnDispatcher().
                        Subscribe(Sub(val) OutputText.Text = val)
End Sub
Protected Overrides Sub OnNavigatedFrom(e As Navigation.NavigationEventArgs)
    MyBase.OnNavigatedFrom(e)
    requestDisposable.Dispose()
    requestDisposable = Nothing
End Sub
Posted on - Comment
Categories: WCF - Rx - VB Dev Center -

Paging with AJAX WCF and LINQ

These days, it seems that every web site needs to have some use of gratuitous AJAX in order to stay on the bleeding edge. Since we didn't have any here yet, I thought I would throw some in for good measure. I liked the lazy loading of records instead of paging found on some sites, including the Google RSS reader and thought I would see what it would take to add something like that here.

If you're not familiar with this paging option, instead of loading a new page of records each time the user gets to the end, they simply add to the end of the list via an AJAX (Asynchronous JavaScript and XML) call to get more records. My implementation is not nearly as fancy, but it gets the job done.

To try out the AJAX implementation we're going to discuss, browse to the AjaxPosts.aspx page. The implementation consists of three parts:

  • The web page that hosts the AJAX ScriptManager and provides the foundation of the page itself.
  • A JavaScript file which performs the client side paging functionality.
  • A WCF service which fetches the data and formats it for the client.

We'll start with the hosting page. The page itself is very simple. We'll make it easy to handle the formatting by continuing to use the same MasterPage that we use elsewhere on this site. That makes the content section rather concise.

The content section includes a ScriptManager which serves to push the AJAX bits down to the client. It also contains knowledge of our service using the asp:ServiceReference tag, and the client side JavaScript using the asp:ScriptReference tag. In addition, we include a blank div element which we will use to insert the content fetched from our service, and a button which is used to initiate requests for more posts from our service.

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="AjaxPosts.aspx.vb" 
Inherits="AjaxPosts" MasterPageFile="~/Blog.master" Title="ThinqLinq" %> <%@ Register
Assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" Namespace="System.Web.UI" TagPrefix="asp" %> <asp:Content ID="content" runat="server" ContentPlaceHolderID="ContentPlaceHolder1"> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="~/API/AjaxServices.svc" /> </Services> <Scripts> <asp:ScriptReference Path="~/AjaxServiceClient.js" /> </Scripts> </asp:ScriptManager> <div id="Posts"> </div> <button id="More" onclick="FetchPosts(); return false;">More Posts</button> </asp:Content>

With the plumbing out of the way, we can start to focus on the meat of the AJAX implementation. First off, we need to have a way to access our data. My first inclination was to use ADO.Net Data Services to serve up dynamic data from our LINQ sources. However in this case, I decided that the functionality was quite limited in scope and a dedicated service would be the better option. A dedicated service would also offer some additional level of caching should scalability become an issue on the site. Also, I wasn't sure my JavaScript skills would be quite suited to doing the necessary client side string parsing that would be necessary to build dynamic HTML content from the raw data. Thus in this case I decided to use a more standard WCF service.

Our WCF service takes as parameters the page number that we want to retrieve and the number of records that make up a page. We'll have our JavaScript pass these values. In response, it will send back a string containing the already formatted HTML that we will display. First we need to set up our class and method and decorate them with the necessary WCF attributes. When adding services that you want to AJAX enable, make sure to use the  "AJAX Enabled WCF Service" template from the Add New Item dialog box rather than the standard "WCF Service". This will set up the web.config differently to allow the service to expose a way to access a JavaScript client proxy. (Thanks goes to Wally for helping me figure that one out. For our service, we'll put it in the ThinqLinq namespace and call it AjaxServices. It will have one service method (indicated by the OperationContract attribute) called LoadFormattedPosts.


Namespace ThinqLinq
    <ServiceContract(Namespace:="ThinqLinq")> _
    <AspNetCompatibilityRequirements(RequirementsMode:=AspNetCompatibilityRequirementsMode.Allowed)> _
    Public Class AjaxServices

        <OperationContract()> _
       Public Function LoadFormattedPosts(ByVal page As Integer, ByVal pagesize As Integer) As String
       End Function
    End Class
End Namespace

Inside the LoadFormattedPosts we'll get to use our LINQy goodness. In this case, we know that we are going to need our posts with their associated categories and comments. As an optimization, we'll add the appropriate load options to fetch all of those at the same time. We'll also include the appropriate Skip and Take methods to do the paging. Our resulting LINQ to SQL query is fairly standard.


Using dc As New LinqBlogDataContext
    Dim LoadOptions As New DataLoadOptions
    LoadOptions.LoadWith(Of PostItem)(Function(p) p.Comments)
    LoadOptions.LoadWith(Of PostItem)(Function(p) p.CategoryPosts)
    LoadOptions.LoadWith(Of CategoryPost)(Function(cp) cp.Category)
    dc.LoadOptions = LoadOptions

    Dim posts = From p In dc.PostItems _
                Order By p.PublicationDate Descending _
                Skip pagesize * page _
                Take pagesize

    Dim response As String = FormatPosts(posts)
    Return HttpUtility.HtmlDecode(response)
End Using

This query would be fine if we only wanted to send the raw data back to the AJAX client. However, we'll take an extra step in this implementation and do the formatting in a separate FormatPosts method. We'll actually add a separate method to format the Categories as well.


Private Function FormatPosts(ByVal posts As IEnumerable(Of PostItem)) As String
  Dim response = _
      From p In posts _
      Select val = <div class="post">
                     <h2>
                        <a href=<%= "Default/" & p.TitleUrlRewrite %>><%= p.Title %></a>
                     </h2>
                     <div class="story"><%= p.Description %></div>
                     <div class="meta">Posted on <%= p.PublicationDate %> - 
                        <a href=<%= "Default/" & p.TitleUrlRewrite %>>
                        Comments (<%= p.Comments.Where(Function(c) c.IsApproved).Count() %>)</a>
                        <br/>
                        <%= If(p.CategoryPosts.Count > 0, _                               "Categories:" & FormatCategories(p), _                               "") %>
                     </div>
                   </div>.ToString() _
        Select val  Return "<div class='posts'>" & String.Join("", response.ToArray) & "</div>"
End Function
Private Function FormatCategories(ByVal post As PostItem) As String
  If post.CategoryPosts.Count > 0 Then
    Dim response = _
       From catPost In post.CategoryPosts _
       Select val = <span>
                      <a href=<%= "http://www.ThinqLinq.com/Default.aspx?CategoryId=" & _                              catPost.Category.CategoryId %>>
                         <%= catPost.Category.Description.Trim %></a>
                    </span>.ToString()

    Return String.Join(", ", response.ToArray())
  Else
    Return ""
  End If
End Function

I'm not going to take the time to explain all of the LINQ to XML implementation here. I've discussed LINQ to XML in past posts. I do want to point out here a couple extra steps that need to be taken with this implementation.

First, we need to be careful in cases where we have posts without associated comments or categories. If we don't, we will run into issues with null results and the query will fail. Second, we have to watch how and when we are casting to strings and arrays. The easiest way to make sure that we are casting properly is to make sure you have Option Strict turned On at the file or project level.

Now that we have our service set-up, we can write the client side JavaScript code. Because we're using the AJAX ScriptManager and an AJAX enabled WCF service, we don't have to write any fancy plumbing code to access this service. To test this, we can browse to the service passing a /js or /jsdebug flag as follows: http://ThinqLinq.com/Api/AjaxServices.svc/js. That leaves just the task of writing the client side to access the service and place it in the AjaxServiceClient.js file for the ScriptManager to find.


var svcProxy;
var currentPage;
function pageLoad() {
    currentPage = 0;
    svcProxy = new ThinqLinq.AjaxServices();
    svcProxy.set_defaultSucceededCallback(SucceededCallback);
  
    FetchPosts();
}

function FetchPosts() {
    svcProxy.LoadFormattedPosts(currentPage, 5);
}

function SucceededCallback(result) {
    var postTag = document.getElementById("Posts");
    postTag.innerHTML += result;
    currentPage += 1;
}

if (typeof (Sys) !== "undefined") Sys.Application.notifyScriptLoaded();

In this JavaScript, we set up two global variables: currentPage to manage the paging functionality and svcProxy to act as the instance of the proxy that accesses our service. In the pageLoad function, we initialize these values. Once initialized, we then set the asynchronous callback function for when values are retrieved. Finally, we invoke the method to fetch the posts for the first time that the page is loaded.

To fetch the posts, we simply call the LoadFormattedPosts method of our proxy which sends the request to our WCF service. Because this is performed asynchronously, we will just fire the request and let the callback handle the response.

In the SucceededCallback method, we grab the return value from the WCF service in the result parameter. Once we have that, we get a reference to the placeholder "Posts" div in the AjaxPosts.aspx document. To add the new results to the client, we concatenate the current contents with the new result value using +=. Finally, we increment the currentPage number so that the next request will fetch the next page of posts.

That's it. We're done. Jump over to http://ThinqLinq.com/AjaxPosts.aspx to see the result in action. There are a number of things that can be improved on this implementation, but it is a start. One definite drawback on this implementation is that it is not SEO friendly. You can see this by viewing the source to the resulting page. Notice that none of the post contents are included in the source.

I don't claim to be a JavaScript or AJAX expert and I'm sure there are other more elegant solutions. I'd love to learn from your experience, so feel free to post your recommendations and we'll see what we can do to improve this.

Posted on - Comment
Categories: VB Dev Center - LINQ - VB - Ajax - WCF -

WCF with the LINQ to SQL designer

A frequent question on the LINQ forums regards how to combine LINQ with a service oriented application. The main issue is that the DataContext which sits at the core of LINQ to SQL in managing the connection and change tracking is not intended to be remoted. In addition, the DataContext should be rather short lived in a disconnected environment (including ASP). With the addition of WCF in the 3.0 framework, the question of how to enable LINQ to SQL entity definitions to participate in a WCF DataContract is not unexpected.

If you are unfamiliar with WCF, the core of it relies on a simple concept of ABC, or Address, Binding and Contract. The Address is the location that hosts the service. This is typically a URI. The Binding indicates how we connect to the address (HTTP/TCP/etc). The Contract indicates what you are going to connect to. This represents a set of method calls that are accessible to the outside world.

The WCF ServiceContract can consist of methods and functions which take or return primitive types (strings, integers, etc). It can also accept or return complex object types (objects) as long as they are configured with the necessary System.Runtime.Serialization.DataContract and DataMember attributes.

LINQ to SQL also operates based on decorating classes with System.Data.Linq.Table and Column attributes to indicate the mappings (assuming you are not using the XML mapping mechanisms). If you add your attributes manually, you can add both of the necessary sets of attributes with no problem. If, on the other hand, you use the LINQ to SQL designer, managing the WCF attributes can be a bit trickier as you can't modify the class file natively without risking any of your custom code being removed as the classes are regenerated as changes are made to the designer. Thus any changes you make should only be done through the property window or directly with the XML in the .dbml file.

Today, we'll extend the ThinqLinq.com sample website that is available for download in the file section here. This sample is a proof of concept site that manages blog posts. For the purposes of this article, we will extend the support for a post to be able to fetch and update them using WCF services rather than native LINQ to SQL calls. To begin the WCF implementation, we will define our contract in an Interface as follows:

Imports System.ServiceModel
Imports LinqBlog.BO

<ServiceContract()> _
Public Interface IWcfItems

    <OperationContract()> _
    Function GetPosts(ByVal skipPosts As Integer, ByVal fetchPostCount As Integer) As PostItem()
    <OperationContract()> _
    Function GetSinglePost(ByVal id As Integer) As PostItem
    <OperationContract()> _
    Sub UpdatePost(ByVal item As PostItem)
    <OperationContract()> _
    Sub InsertPost(ByVal item As PostItem)
    <OperationContract()> _
    Sub DeletePost(ByVal item As PostItem)

End Interface

In this code, we set up a ServiceContract for the class definition. Each method is assigned an OperationContract to define the method signatures that will be available outside of our code. The function of each method should be self-evident from their names. What may not be apparent is the use of more complex types (the PostItem).

Since PostItem is an object, we need to decorate it with additional attributes to define how the WCF serializer will handle marshaling the object across the wire. At its simplest, our PostItem object consists of 5 properties: an auto-incrementing integer called Id, a Title, Author, PublicationDate and Description (which holds the content of the post). To enable the PostItem object to participate in a WCF method, we need to decorate the object with the System.Runtime.Serialization.DataContract and each of the properties with a System.Runtime.Serialization.DataMember attribute. The figure below shows the PostItem object in the LinqToSql designer in the Orcas Beta 1 release.

 

In this example, I'm showing not only the PostItem object, but also the relevant parts of the property window and Attribute window which we can use to declare the DataContract and DataMember attributes. To begin, select the PostItem class and locate the Custom Attributes property in the property window. Click on the ellipsis button to open the Attribute Editor window. Add the DataContext attribute by clicking the Add button and supplying the fully qualified name of the DataContext attribute as shown in the example. By using the property windows to maintain the attributes, they will be retained as the system generated class libraries are regenerated.

In addition to declaring the attribute for the class definition, we also need to declare them for the constituent properties as well. Follow the same process for each property of the PostItem object to set their CustomAttribute to DataMember. Remember to fully qualify the declaration.

At this point, our class should be set to participate in the WCF implementation. Below is the beginning of the implementation to fetch a list of PostItems:

Imports System.Data.Linq

Public Class WcfItems
    Implements IWcfItems

    Public Function GetPosts(ByVal skipPosts As Integer, ByVal fetchPostCount As Integer) As LinqBlog.BO.PostItem() Implements IWcfItems.GetPosts
        Dim dc As New LinqBlogDataContext
        Dim query = (From p In dc.PostItems _
                     Order By p.PublicationDate Descending).Skip(skipPosts).Take(fetchPostCount)
        Return query.ToArray()
    End Function

The GetPosts method takes as parameters the number of posts we are going to retrieve and the number that we will skip. It returns an array of PostItems. For friends of this blog, the internal implementation should be self explanatory as it uses a LINQ query to fetch post items ordered by the publication date. It also passes the input parameters using the .Skip and .Take methods to support paging options. Since we can't transmit the DataContext or the IQueryable definition over the wire, we need to immediately fetch the results ToArray and return them. Once we leave the method, the DataContext will be disposed.

Client applications can now consume our WCF method as it would any other service. Unlike the attached LINQ to SQL implementation, we need to manually manage the return values as the change tracking service is no longer attached to the context. Thus we need to take a bit more effort to support subsequent updates inserts and deletes.

Inserting values does not require the change tracking mechanisms. However, we can't just Add the object natively. Not shown in the above class definition, we have a child collection object of categories. In order to instantiate the collection,  We need to get a new object by  and then setting the appropriate values manually. We can then call the .Add method to add it to the table and SubmitChanges to commit the insert.

    Public Sub InsertPost(ByVal item As LinqBlog.BO.PostItem) Implements IWcfItems.InsertPost
        Dim dc As New LinqBlogDataContext
        'We need to map the returned type on a native new item in order to wire-up the child collections
        Dim newItem As New PostItem
        newItem.Author = item.Author
        newItem.Description = item.Description
        newItem.PublicationDate = item.PublicationDate
        newItem.Title = item.Title
        dc.PostItems.Add(newItem)
        dc.SubmitChanges()
    End Sub

To update an existing post item, we need to attach a returned post with the existing instance implementation. The standard recommendation is to use the Attach method to re-connect an existing record with the underlying object store. Unfortunately, the change tracking mechanism does not start until after the attach method is called. Thus, it does not know how to handle changes that were done remotely. As a result, we will re-fetch the instance from the database and then re-apply the changes from the returned PostItem from the service.

    Public Sub UpdatePost(ByVal item As LinqBlog.BO.PostItem) Implements IWcfItems.UpdatePost
        Dim dc As New LinqBlogDataContext
        Dim oldItem As PostItem = (From p In dc.PostItems Where p.Id = item.Id).FirstOrDefault()
        oldItem.Author = item.Author
        oldItem.Description = item.Description
        oldItem.PublicationDate = item.PublicationDate
        oldItem.Title = item.Title

        dc.SubmitChanges()
    End Sub

The remaining portion of the CRUD operation is the Delete. To delete an object from a table, we need to attach to an instance of the underlying object and then call the delete method on it as well. Here's a sample delete implementation:

    Public Sub DeletePost(ByVal item As LinqBlog.BO.PostItem) Implements IWcfItems.DeletePost
        Dim dc As New LinqBlogDataContext
        'Must attach before we can remove it
        Dim PostItem = (From p In dc.PostItems _
                Where p.Id = item.Id).FirstOrDefault()
        dc.PostItems.Remove(PostItem)
        dc.SubmitChanges()
    End Sub

Using LINQ to SQL in a disconnected environment such as WCF currently takes a bit more care and effort. The code in this post serves as a sample implementation. It is by no means the only possible implementation, but it hopefully shows that LINQ to SQL can have a positive impact on our application development. The most obvious enhancement is that we still don't need to worry about much of the ADO plumbing API's that we would have to include otherwise.

NOTE: The ability to add the attributes was dropped in Beta 2. If you want to add the WCF attributes, mark the Context's Serialization mode as Unidirectional.

Posted on - Comment
Categories: LINQ - WCF -