Skip to content
Archive of posts filed under the WCF category.

Creating WCF Service with SOAP/REST Endpoints

In this post I am going to describe a solution to the following problem.  I would like to create a single WCF Service and expose it via a standard SOAP endpoint and REST endpoint using Entity Framework, WCF and WCF REST.  Then I would like to consume it from WinRT from two different view models working against the same view.  This is an exercise of research into data options in WinRT.

First of, let’s create a service.  I am going to use the following data class:

    public class Session
    {
        public int SessionID { get; set; }
        public string Title { get; set; }
        public string Description { get; set; }
        public string Speaker { get; set; }
        public DateTime When { get; set; }
    }

My data context for EF Code First is just as simple:

    public class Context : DbContext
    {
        public Context() :
            base("Name=VSLive")
        {
        }
        public DbSet<Session> Sessions { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Session>().Property(p => p.Title).HasMaxLength(100).IsRequired();
            modelBuilder.Entity<Session>().Property(p => p.Speaker).HasMaxLength(50).IsRequired();
            modelBuilder.Entity<Session>().Property(p => p.Description).IsRequired();
            modelBuilder.Entity<Session>().Property(p => p.When).IsRequired();
        }
    }

Now, the service.  I am just going to perform basis CRUD opertions.  The key to the service is my interface that I am going to decorate with both SOAP(OperationContract) and REST(WebGet or WebInvoke) attributes.

    [ServiceContract]

    public interface IVSLiveService
    {
        [OperationContract]
        [WebGet(UriTemplate = "/GetList", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Session[] GetList();

        [OperationContract]
        [WebInvoke(UriTemplate = "/Create", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Session Create(Session session);

        [OperationContract]
        [WebInvoke(UriTemplate = "/Update", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        Session Update(Session session);

        [OperationContract]
        [WebInvoke(UriTemplate = "/Delete?sessionId={sessionId}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        void Delete(int sessionId);

    }

The implementation is not quite as interesting, but for the same of completeness of this post, here it goes:

using System.Data.Entity;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Activation;
using WinRT.Data;
using WinRT.DataAccess;

namespace WcfService
{
    [AspNetCompatibilityRequirements(
      RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    public class VSLiveService : IVSLiveService
    {
        public VSLiveService()
        {
            Database.SetInitializer(new Initializer());
        }

        public Session[] GetList()
        {
            using (var context = new Context())
            {
                context.Configuration.LazyLoadingEnabled = false;
                context.Configuration.ProxyCreationEnabled = false;
                return context.Sessions.ToArray();
            }
        }

        public Session Create(Session session)
        {
            using (var context = new Context())
            {
                context.Sessions.Add(session);
                context.SaveChanges();
            }
            return session;
        }

        public Session Update(Session session)
        {
            using (var context = new Context())
            {
                context.Entry(session).State = System.Data.EntityState.Modified;
                context.SaveChanges();
            }
            return session;
        }

        public void Delete(int sessionID)
        {
            using (var context = new Context())
            {
                var session = new Session { SessionID = sessionID };
                context.Entry(session).State = System.Data.EntityState.Deleted;
                context.SaveChanges();
            }
        }
    }
}

Now, the part that took me the longest to figure out: web.config.

I have single service node, and I have two endpoints for it, using the same contract, but two different bindings and behaviors.  I am putting entire web.config:

<?xml version="1.0"?>
<configuration>
  <connectionStrings>
    <add
          name="VSLive"
          connectionString="Server=.;Database=VSLive;Trusted_Connection=True;"
          providerName="System.Data.SqlClient"/>
  </connectionStrings>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <endpointBehaviors>
        <behavior name="jsonBehavior">
          <webHttp/>
        </behavior>
      </endpointBehaviors>

      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!—To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
      <basicHttpBinding>
        <binding
          name="VSLiveService_BasicHttpBinding"
          maxBufferSize="1000000"
          maxReceivedMessageSize="1000000">
          <readerQuotas
            maxBytesPerRead="1000000"
            maxArrayLength="1000000"
            maxDepth="1024"
            maxStringContentLength="1000000"/>
        </binding>
      </basicHttpBinding>
      <webHttpBinding>
        <binding
           name="VSLiveService_WebHttpBinding"
           maxBufferSize="1000000"
           maxReceivedMessageSize="1000000">
          <readerQuotas
            maxBytesPerRead="1000000"
            maxArrayLength="1000000"
            maxDepth="1024"
            maxStringContentLength="1000000"/>
        </binding>
      </webHttpBinding>

    </bindings>
    <services>
      <service name="WcfService.VSLiveService">
        <endpoint
          address="soap"
          binding="basicHttpBinding"
          bindingConfiguration="VSLiveService_BasicHttpBinding"
          contract="WcfService.IVSLiveService"/>
        <endpoint
            address="rest"
            binding="webHttpBinding"
            behaviorConfiguration="jsonBehavior"
            bindingConfiguration="VSLiveService_WebHttpBinding"
            contract="WcfService.IVSLiveService"/>
      </service>
    </services>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel"
              switchValue="Information, ActivityTracing"
              propagateActivity="true">
        <listeners>
          <add name="traceListener"
              type="System.Diagnostics.XmlWriterTraceListener"
              initializeData= "c:\Traces.svclog" />
        </listeners>
      </source>
    </sources>
  </system.diagnostics>
</configuration>

As you can see above, SOAP endpoint comes first, and it is using basicHttpBinding.  My REST endpoint is second, and it is using webHttpBinding  I am asing a behavior configuration to the latter one, enabling webHttp get/post methods.

This is all nice and simple, and you can now test it in browser.  I an now add service reference to my WinRT project to support WCF.  You can find more details about that in my previous post http://dotnetspeak.com/index.php/2011/12/getting-started-with-wcf-services-in-winrt/

Today, I am documenting REST consumption.

I am using HttpClient class to accomplish this task.  For example, here is how I am going to get the list of sessions.

        public async Task LoadData()
        {
            IsBusy = true;
            _client = new HttpClient();
            _client.MaxResponseContentBufferSize = int.MaxValue;
            var response = await _client.SendAsync(new HttpRequestMessage(HttpMethod.Get, new Uri(_serviceUri + "GetList")));

            var data = response.Content.ReadAsString();

            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Session>));
            using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
            {
                var list = serializer.ReadObject(stream) as List<Session>;
                Sessions = new ExtendedObservableCollection<Session>(list);
            }
            IsBusy = false;
        }

A few points about the code above.  I should have wrapped the call inside Try/Catch, I am just skipping it for the sake of a demo and to minimize the code I am showing.  I am using standard serializer to convert my JSON message into an object.  I also have a little progress ring that is playing while server communication is going on, and that is what my IsBusy property above is bound to. 

Now, let’s take a look at Create/Update call.  It is just as simple, but I am using Post method of HttpClient and I am creating a string content to post by converting Session object to JSON, again using the same serializer.

        public async void OnSave(object parameter)
        {
            if (SelectedSession != null)
            {
                IsBusy = true;
                string method = "Update";
                if (selectedSession.SessionID == 0)
                {
                    method = "Create";
                }
                _client = new HttpClient();
                _client.MaxResponseContentBufferSize = int.MaxValue;
                var content = new StringContent(ConvertSessionToJson());
                content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                var response = await _client.PostAsync(new Uri(_serviceUri + method), content);

                var data = response.Content.ReadAsString();

                var session = ConvertJsonToSession(data);
                Sessions[Sessions.IndexOf(selectedSession)] = session;
                SelectedSession = session;
                IsBusy = false;
            }
        }

For delete method I am also using Post method, just my content is blank and my ID is passed to the server as query string parameter

        public async void OnDelete(Session parameter)
        {
            if (parameter != null)
            {
                if (parameter.SessionID > 0)
                {
                    IsBusy = true;
                    _client = new HttpClient();
                    _client.MaxResponseContentBufferSize = int.MaxValue;
                    var content = new StringContent(string.Empty);
                    content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
                    var response = await _client.PostAsync(new Uri(_serviceUri + "Delete?sessionId=" + parameter.SessionID.ToString()), content);

                    var data = response.Content.ReadAsString();
                    Sessions.Remove(parameter);
                    IsBusy = false;
                }
                else
                {
                    Sessions.Remove(parameter);
                    IsBusy = false;
                }
            }
        }

Please let me know your questions.

Thanks.

Post to Twitter

Securing WCF with Forms Authentication

In this post I will describe how to secure a WCF RESTful service with Forms Authentication.  I blogged on WCF many a times, but usually skipped right over security aspects of the service.  I will go into sufficient (hopefully) level of details now.

The idea of having an un-secured service on the internet is not an appealing one.  This means that anyone can connect to it and consume the data exposed by the service.  Yes, granted, that person would have to discover your service somehow, but still the aspects of security cannot be ignored.  As a result, we must authenticate and authorize every consumer of the service.  For authentication I will use forms authentication.  One of primary reasons why I want to do that is because I do not have to litter my API with user Id and password for every method.  Instead I will rely on built-in functionality in ASP.NET to do a bulk of heavy lifting for me.  Once ASP.NET established the user, I will generate an authorization cookie, and that cookie will be consumed by the client, and then re-submitted with requests.

So, here is my solution at a high level.

  • Create authentication WCF Service
  • Create Data WCF RESTful service, which has actual API I am exposing.
  • Secure the site with forms authentication.
  • Client will first call authentication service, get a cookie, then submit it with requests to RESTful service.

Let’s start by creating a RESTful service.  Just use built-in template in Visual Studio 2010

image

Now because I want a real service, I am going to use Entity Framework Code First to create some basic functionality to perform CRUD operations on a Person object.

 

namespace CustomWcfRestService
{
    public class Person
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set;}
    }
}

I am also going to have a users table I am going to use for authentication.

namespace CustomWcfRestService
{
    public class User
    {
        public int UserID { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
    }
}

Here is sample code for my operational RESTful service.  I am using json format for everything.

using System.Collections.Generic;
using
System.Data;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
System.Web.Script.Services;
 

namespace
CustomWcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode
.Required)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class CustomService

    {
        [
WebGet(UriTemplate = "/GetPeople", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
       
public List<Person
> GetPeople()
        {
           
using(var ctx = new Context
())
            {
                ctx.Configuration.LazyLoadingEnabled =
false
;
                ctx.Configuration.ProxyCreationEnabled =
false
;
               
return
ctx.People.OrderBy(one => one.LastName).ThenBy(two => two.FirstName).ToList();
            }
        }
 
        [
WebInvoke(UriTemplate = "/Create", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat
.Json)]
       
public Person Create(Person
person)
        {
           
using (var ctx = new Context
())
            {
                ctx.Entry(person).State =
EntityState
.Added;
                ctx.SaveChanges();
               
return
person;
            }
        }
 
        [
WebGet(UriTemplate = "/GetPerson?id={id}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat
.Json)]
       
public Person Get(int
id)
        {
           
using (var ctx = new Context
())
            {
                ctx.Configuration.LazyLoadingEnabled =
false
;
                ctx.Configuration.ProxyCreationEnabled =
false
;
               
return
ctx.People.Find(id);
            }
        }
 
        [
WebInvoke(UriTemplate = "/UpdatePerson", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat
.Json)]
       
public Person Update(Person
person)
        {
           
using (var ctx = new Context
())
            {
                ctx.Entry(person).State =
EntityState
.Modified;
                ctx.SaveChanges();
               
return
person;
            }
        }
 
        [
WebInvoke(UriTemplate = "/GetPerson?id={id}", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat
.Json)]
       
public void Delete(int
id)
        {
           
using (var ctx = new Context
())
            {
               
var person = new Person
{ID = id};
                ctx.Entry(person).State =
EntityState
.Deleted;
                ctx.SaveChanges();
            }
        }
 
    }
}

 

I am now going to add a new service, called LoginService that I will use for authentication.  It will use the same Users table to validate user name and password.

using System;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.Web.Security;
using
System.Web;
 

namespace
CustomWcfRestService
{
    [
AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode
.Required)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class LoginService : ILoginService

    {
 
       
public bool Login(string userName, string password)
        {
           
bool returnValue = false
;
           
User
user;
           
using (var ctx = new Context
())
            {
                user = ctx.Users.Where(one => one.UserName == userName).FirstOrDefault();
               
if (user != null
)
                {
                    returnValue = (user.Password == password);
                }
            }
           
if
(returnValue)
            {
               
var ticket = new FormsAuthenticationTicket
(
                        1,
                        userName,
                       
DateTime
.Now,
                       
DateTime
.Now.AddDays(1),
                       
true
,
                        user.UserID.ToString()
                    );
               
string encryptedTicket = FormsAuthentication
.Encrypt(ticket);
               
var cookie = new HttpCookie(FormsAuthentication
.FormsCookieName, encryptedTicket);
               
HttpContext
.Current.Response.Cookies.Add(cookie);
 
            }
           
return
returnValue;
        }
    }
}

 

As you can see, I validate credentials against database, then I am creating custom cookie, encrypting it and sending back to the client.  I have to use ASP.NET compatibility mode to enable HttpContext and related functionality.

Now, I need to enable actual security.  I am doing this entirely in Web.Config by enabling forms authentication, denying requests from un-authenticated users, then adding a Location exception just for my login service.

<?xml version="1.0"?>
<configuration>
    <connectionStrings>
        <add name="SecuredServiceDemo"
           connectionString="Server=.;Integrated Security=SSPI;Database=SecuredServiceDemo
"
           providerName="System.Data.SqlClient" />

    </connectionStrings>
    <system.web>
        <compilation debug="true" targetFramework="4.0" />
        <authentication mode="Forms">
        </authentication>
        <authorization>
            <deny users="?"/>
        </authorization>
    </system.web>
 
    <location path="LoginService.svc">
        <system.web>
            <authorization>
                <allow users="?"/>
            </authorization>
        </system.web>
    </location>

 

 

And that is it.  Now just create a test client as in following:

using System.Net;
using
System.ServiceModel;
using
System.ServiceModel.Channels;
using
TestServiceApp.LoginService;
using
System.IO;
 

namespace
TestServiceApp
{
   
class Program

    {
       
static void Main(string[] args)
        {
           
var sharedCookie = string
.Empty;
           
bool
isValid;
           
string data = string
.Empty;
 
           
var authClient = new LoginServiceClient
();
           
using (new OperationContextScope
(authClient.InnerChannel))
            {
                isValid = authClient.Login(
"me@you.com", "pw"
);
               
if
(isValid)
                {
                   
var response = (HttpResponseMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpResponseMessageProperty
.Name];
                    sharedCookie = response.Headers[
"Set-Cookie"
];
                }
            }
 
           
if
(isValid)
            {
 
               
var request = (HttpWebRequest)WebRequest.Create("http://localhost:48090/CustomService/GetPeople"
);
                request.Headers[
"Cookie"
] = sharedCookie;
               
var
responce = request.GetResponse();
               
using (var
stream = responce.GetResponseStream())
                {
                   
using (var reader = new StreamReader
(stream))
                    {
                        data = reader.ReadToEnd();
                    }
                }
            }
 
        }
    }
}

 

Just to confirm that everything is working, I can just comment out the part that authenticates and gets a cookie, and I get 404 as expected.

You can download the complete solution here and try yourself.

Post to Twitter

Getting Started with WCF Services in WinRT

I have been learning WInRT in my “spare time” since for a while now. My big interest is working with data in Metro style applications for Windows 8. In this post I will describe step-by-step instructions of creating a WinRT application that is using WCF Service. I am going to use XAML application. To get started, just create a brand new XAML based application in Visual Studio 11. Then I am going to create a WCF Service that is using Entity Framework code first.

I created just on table/class, data context and a WCF host web application.

public class Session

{

    public int SessionID { get; set; }

    public string Title { get; set; }

    public string Description { get; set; }

    public string Speaker { get; set; }

    public DateTime When { get; set; }

}

using System.Data.Entity;

using WinRT.Data;

namespace WinRT.DataAccess

{

    public class Context : DbContext

    {

         public Context() :

           base("Name=VSLive")

         {

         }

         public DbSet<Session> Sessions { get; set; }

         protected override void OnModelCreating(DbModelBuilder modelBuilder)

         {

             base.OnModelCreating(modelBuilder);

             modelBuilder.Entity<Session>().

                     Property(p => p.Title).HasMaxLength(100).IsRequired();

             modelBuilder.Entity<Session>().

                     Property(p => p.Speaker).HasMaxLength(50).IsRequired();

             modelBuilder.Entity<Session>().

                     Property(p => p.Description).IsRequired();

             modelBuilder.Entity<Session>().

                     Property(p => p.When).IsRequired();

           }

      }

}

Service class is not very complicated either, here is get method:

public Session[] GetList()

{

      using (var context = new Context())

      {

           context.Configuration.LazyLoadingEnabled = false;

           context.Configuration.ProxyCreationEnabled = false;

           return context.Sessions.ToArray();

       }

}

Now, I am going to configure service to use IIS and setup AppPool to have enough rights to create a database.

Now in my XAML Metro application I right click on references and choose Add Service Reference. I will clock on button in the next dialog to discover services in the solution and click OK to add a reference. This will create a proxy class to communicate with my service. One interesting thing about this class in comparison with the same proxy in .NET or Silverlight is that it is using new async / await keywords and Tasks to simplify the code on the client.

Now, I am going to add a view model class that will have all the communication with the service. First of all, it has to create proxy instance with proper configuration.

private VSLiveServiceClient _client;

private void SetupClient()

{

      BasicHttpBinding binding =
           new BasicHttpBinding(BasicHttpSecurityMode.None);

      binding.AllowCookies = true;

      binding.MaxBufferSize = int.MaxValue;

      binding.MaxReceivedMessageSize = int.MaxValue;

      binding.OpenTimeout = TimeSpan.FromSeconds(10);

      EndpointAddress address = new EndpointAddress(_serviceUri);

      _client = new VSLiveServiceClient(binding, address);

}

Now I can invoke the service by calling the proxy:

public async Task LoadData()

{

      var sessions = await _client.GetListAsync();

      Sessions = new ExtendedObservableCollection<Session>(sessions);

}

You can read a bit more about my ExtendedObservableCollection in one of my previous posts at http://dotnetspeak.com/index.php/2011/11/observablecollectiont-in-winrt/. Now I am ready run. But what I am getting is “There was no endpoint listening at ….” The issue is that I have to add an exemption to allow WinRT application to communicate with a service at localhost. The tool is called CheckNetIsolation. You can get to it by running Visual Studio Command prompt. But you have to find the application ID for that. To do so you have to run RegEdit and find your application. Here is path you are looking for:

HKEY_CURRENT_USER\Software\Classes\Local Settings\Software\Microsoft\Windows\CurrentVersion\AppContainer\Mappings

Once you find the path, just go through all nodes and look for you application by looking at DisplayName entry node. Once you find it, click on a node name(starts with S-1-…), select Rename and hit Ctrl+C to copy node name to the clipboard.

image

Mine was S-1-15-2-4269264600-3040727888-3229327272-2989798893-2153435301-719469956-2341848450.

Now in VS Command prompt type :

CheckNetIsolation LoopbackExempt -a -p=S-1-15-2-4269264600-3

040727888-3229327272-2989798893-2153435301-719469956-2341848450

and hit enter. Make sure you spell everything correctly, the command line is case-sensitive.

Now, run your application. You should be ready to go. If you still get an error, edit the manifest file (double-click on Package.appxmanifest file in your WinRT project, go to capabilities tab and check home networking and Internet Client.

image

You will also need to turn off (or configure) Windows Firewall.

You are now ready to go.

Thanks.

Post to Twitter

VS Live Orlando 2011

As I mentioned before, I presented at VS Live conference in Orlando, FL Thursday, 12/08/2011. I presented the following two talks

Working with Data on Windows Phone 7
I will talk about various approaches to work with data on Windows Phone 7. I will cover all major concepts, such as local storage, OData/WCF Data Services and custom WCF services. I will demonstrate how to retrieve data and save changes locally or to a remove web server. I will build demos for all technologies step-by-step.

You will learn:
• About options to persist the data on Windows Phone 7
• About pros and cons of each technologies
• Knowledge to build a Windows Phone application that publishes and/or consumes data

You can download the materials for this presentation here.

Using Code First (Code Only) Approach with Entity Framework
Session will include high level overview of Entity Framework and how various approaches to use it fit into application development lifecycle. Then I will build POCO classes that entity framework can use to create database as well as perform CRUD operations against the database. Various attributes that are included out of the box will be covered. This will include columns constraints, relationships, etc. I will show you how ASP.ENT MVC 3 can utilize entity framework code first metadata to build automatic validation of user input.
You will learn:
• How to build data access layer with Entity Framework Code First
• About validation approaches using POCO classes
• Fluent API and attribute based configuration option

You can download the materials for this presentation here.  I spent a lot of time answering questions, which I really enjoy, so I ran a bit short on time covering MVC.  On a positive note, you can still see the project in the download zip file.

Feel free to ask any questions related to the presentations in the comments or email me directly.  You can find my email address on Contact Me page on this blog.

Post to Twitter

How to Improve Performance of CSLA for Silverlight

CSLA for Silverlight is using MobileFormatter class to serialize and de-0serialize the data that if sent across the wire during client/server communications.  General flow of the serialization process is as follows.  Each object that implements IMobileObject is being asked by mobile formatter to serialize its data into a list of SerializationInfo objects.  That list maintains the state of each object as well as the relationships between objects.  Ultimately, the data consist of simple properties serialized into FieldData objects and relationships between objects into ChildData objects.  The formatter then is using DataContactSerializer and XML Reader/Writer combination in order to create byte arrays from object data.  These byte arrays are just XML blobs when all said and done of SerializationInfo objects.  DataContractSerializer is doing the best job it can in order to specify enough information in the XML to make it possible to reconstruct the data on the other end of the wire.  As a result, it drops hints from XML standards that specify what primate type should be used for each property value of each objects.  This results in extremely verbose XML, where each property may take additional 20-30 bytes to specify the type to be used.  On top of that, CSLA is using descriptive names inside Serialization Info object as well as generic dictionaries to store ChildData and FIeldData objects.  Turns out, serializer puts enough metadata around generic collections as well that makes them larger.

So, we took a few steps to provide some optimization around the code that should work with any version of CSLA that has MobileFormatter.  First of all, we changed DataMember and DataContract attributes to provider shorter names.  For example, instead of Value property we will just have VU in the XML.  We also created helper dictionaries instead of using generic dictionaries in order to be able to specify names for items and keys, all consisting of 2 letter instead of 4-10 letter.  Also, we eliminated XML type hints by injecting a xmlns namespace into XML header containing the root namespace of XML standards with one letter alias, which will eliminate 20-30 bytes from each serialized property.

Your particular results may vary, but we saw overall improvements of 2-50 percent depending on the objects.  Since Mobile Formatter is also used to take snapshots of objects to support Cancel button (undo) functionality, you will also see memory improvements in your Silverlight application as well.

Please read the warning message at the end of the article before you decide to use this code.

You can download attached SerializationInfo and make changes to your version of CSLA.  You will also need to find the following method in MobileFormatter

public void Serialize(XmlWriter writer, object graph)

 

and replace it with the code below:

    public void Serialize(XmlWriter writer, object graph)

    {

      List<SerializationInfo> serialized = SerializeAsDTO(graph);

 

      DataContractSerializer dc = GetDataContractSerializer();

 

      dc.WriteStartObject(writer, serialized);

      writer.WriteAttributeString("xmlns", "z", null, "http://www.w3.org/2001/XMLSchema");

      dc.WriteObjectContent(writer, serialized);

      dc.WriteEndObject(writer);

    }

 

WARNING – the byte arrays are not going to be compatible with previous CSLA version.  So, if you are serializing objects using MobileFormatter and storing them somewhere, you will not be able to de-serialize them after you make the change.

You can also download SerializationInfo file here.

 

Post to Twitter

Silverlight and Self-Hosted WCF

I have been working on a project that is based on Silverlight.  It is a large application that performs a variety of tasks, but also needs local access.  Basically, it needs access to scanner in order to scan and upload documents up to the data store.  I had an idea to create a WPF tray application that hosts a WCF Service that Silverlight application can talk to.  Because of WCF restrictions in Silverlight, you have to enable cross domain access in self-hosted WCF service.  There is a variety of posts on the subject, so I am not going to rehash the steps.  You can for example ready about that here.

I thought I came up with a pretty clean solution, and it got tested and worked great.  However, when we deployed it to a customer computers, we had intermittent problems with it.  It worked on soma machines, but did not on others.  We were trapping the errors, and it was reported as cross domain error even though we had all the correct code there to make it work.  Quite a puzzle.  One specific client was running IE 6, and our application was using https.  I pondered on the topic for a while, and on a hunch I added our site to the list of trusted sites in IE.  Voila, the error went away.

I wanted to blog about it, because I could not find anything on the internet that reports the same issue and the same fix.

Thanks.

Post to Twitter

Consuming WCF REST Service from WP 7

In this post I will explore a possibility of talking to a WCF REST Service from a Windows Phone 7 device.  This should complete my posts related to consuming and working with data on Windows Phone 7.

I am going to start with creating a WCF REST Service.  First of all, I am going to create data using Entity Framework Code First.  I am going to re-use classes with my previous posts.  I am going to define a handful : Attendee, Session and Session Category.  Here is what Attendee class looks like as it will be the class I will use in my services.

using System.Collections.Generic;
using
System.ComponentModel.DataAnnotations;
 

namespace
VSLiveData.EF
{
   
public class Attendee

    {
        [
Key]
       
public int AttendeeID { get; set
; }
 
        [
StringLength(50), Required
]
       
public string FirstName { get; set
; }
 
        [
StringLength(50), Required
]
       
public string LastName { get; set
; }
 
        [
StringLength(int
.MaxValue)]
       
public string Notes { get; set
; }
 
       
public virtual ICollection<Session> Sessions { get; set
; }
    }
}

 

Nest step is to define a service.  .NET 4 comes with a template for RESTfull WCF Service, and I am going to use it to get a head start on my code.  I am going to right click on my solution, and in Add New Item dialog I will select WCF REST Service Applications.

image

In next step I will rename and update created service.  I am going to rename it to JSONDataService.  I am going to start with a method that get list of attendees sorted by last name:

 

using System.Collections.Generic;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
VSLiveData.EF;
 

namespace
WcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements
(
        RequirementsMode =
AspNetCompatibilityRequirementsMode
.Allowed)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class JSONDataService

    {
 
        [
WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }

 

A couple of important things to notice here.  I am turning off proxy creation.  I have to do this, otherwise I will get serialization problems.  I am also turning off lazy loading because I do not want to populate navigation properties, plus I will get an exception if I touch that property if my code is outside of using statement.  You will see that I specify uri template as well.  I want to use meaningful path for it.  I also specify JSON format for returned data.  Let’s take a look at create method next

        [WebInvoke(UriTemplate = "/Attendee/Create", Method = "POST"
            ResponseFormat =
WebMessageFormat
.Json, 
            RequestFormat =
WebMessageFormat
.Json)]
       
public Attendee Create(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Add(attendee);
                context.SaveChanges();
            }
           
return
attendee;
        }

 

 

The code to actually save attendee is pretty easy – I am utilizing entity framework code first API to add new attendee to the collection, save and return new attendee.  Entity framework will populate ID for me as part of Save method.  I also specify JSON as my format for incoming and outgoing data.  The rest of the methods are very similar, so here is entire class:

using System.Collections.Generic;
using
System.Linq;
using
System.ServiceModel;
using
System.ServiceModel.Activation;
using
System.ServiceModel.Web;
using
VSLiveData.EF;
 

namespace
WcfRestService
{
    [
ServiceContract
]
    [
AspNetCompatibilityRequirements
(
        RequirementsMode =
AspNetCompatibilityRequirementsMode
.Allowed)]
    [
ServiceBehavior(InstanceContextMode = InstanceContextMode
.PerCall)]
   
public class JSONDataService

    {
 
        [
WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Create", Method = "POST"

            ResponseFormat =
WebMessageFormat
.Json, 
            RequestFormat =
WebMessageFormat
.Json)]
       
public Attendee Create(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Add(attendee);
                context.SaveChanges();
            }
           
return
attendee;
        }
 
        [
WebGet(UriTemplate = "/Attendee/Get/{id}"

            ResponseFormat =
WebMessageFormat
.Json)]
       
public Attendee Get(string
id)
        {
           
Attendee attendee = null
;
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
int attendeeID = int
.Parse(id);
                attendee = context.Attendees.Where(one => one.AttendeeID == attendeeID).FirstOrDefault();
            }
           
return
attendee;
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Update", Method = "PUT"

            ResponseFormat =
WebMessageFormat.Json, RequestFormat = WebMessageFormat
.Json)]
       
public Attendee Update(Attendee
attendee)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Attendees.Attach(attendee);
                context.Entry(attendee).State = System.Data.
EntityState
.Modified;
                context.SaveChanges();
            }
           
return
attendee;
        }
 
        [
WebInvoke(UriTemplate = "/Attendee/Delete/{id}", Method = "DELETE"
)]
       
public void Delete(string
id)
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
               
var attendee = new Attendee() { AttendeeID = int
.Parse(id) };
                context.Attendees.Attach(attendee);
                context.Entry(attendee).State = System.Data.
EntityState
.Deleted;
                context.SaveChanges();
            }
        }
 
    }
}

 

I have to register routes for my service in Global.asax.cs file:

using System;
using
System.ServiceModel.Activation;
using
System.Web;
using
System.Web.Routing;
 

namespace
WcfRestService
{
   
public class Global : HttpApplication

    {
       
void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes();
        }
 
       
private void
RegisterRoutes()
        {
           
RouteTable.Routes.Add(new ServiceRoute("JSONDataService", new WebServiceHostFactory(), typeof(JSONDataService
)));
        }
    }
}

 

In my web.config I just need to set my connection string for my data context and specify routing engine

 

<?xml version="1.0"?>
<configuration>
 
           <connectionStrings>
                      <add
                        name="VSLive"
                        connectionString="Server=.;Database=VSLive;Trusted_Connection=True;
"
                        providerName="System.Data.SqlClient"/>

           </connectionStrings>
 
           <system.web>
                      <compilation debug="true" targetFramework="4.0" />
           </system.web>
 
           <system.webServer>
                      <modules runAllManagedModulesForAllRequests="true">
                                 <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web, Version=4.0.0.0,

Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
                      </modules>
           </system.webServer>
 
           <system.serviceModel>
                      <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
                      <standardEndpoints>
                                 <webHttpEndpoint>
                                            <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
                                 </webHttpEndpoint>
                      </standardEndpoints>
           </system.serviceModel>

 

 

Now, it is time to get to windows phone 7 app.  Just add new project and select Windows Phone 7 application.  The most interesting part is my view model that talks to my WCF service.  First of all, I am going to add a property to hold collection of attendees:

        public ObservableCollection<Attendee> Items { get; private set; }

 

Next, I am going to use WebClient to get the data.  I could also use HTTPRequest.  The difference between the two is that callbacks from WebClient are automatically marshaled to UI thread.  Here is how I would get the list of attendees:

        /// <summary>
       
/// Creates and adds a few ItemViewModel objects into the Items collection.
       
/// </summary>
       
public void LoadData()
        {
           
WebClient client = new WebClient
();
            client.OpenReadCompleted +=
new OpenReadCompletedEventHandler
(client_OpenReadCompleted);
            client.OpenReadAsync(
new Uri(@"http://localhost/WcfRestService/JSONDataService/Attendee/List"
));
 
   

        }
 
       
void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        {
           
ObservableCollection<Attendee> data = new ObservableCollection<Attendee
>();
           
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<Attendee
>));
           
List<Attendee> attendees = (List<Attendee
>)serializer.ReadObject(e.Result);
            attendees.ForEach(one => Items.Add(one));
 

        }

 

Let me explain what this code does.  I am creating a web client, then I am subscribing to completed event, then I am calling OpenRead.  Because of the URL I am using, this call will eventually end up in the method that matches my URL based on UriTemplate attribute for the method:

        [WebGet(UriTemplate = "/Attendee/List", ResponseFormat = WebMessageFormat.Json)]
       
public List<Attendee
> GetList()
        {
           
using (VSLiveContext context = new VSLiveContext
())
            {
                context.Configuration.LazyLoadingEnabled =
false
;
                context.Configuration.ProxyCreationEnabled =
false
;
               
return
context.Attendees.ToList();
            }
        }

 

In completed handler for read, I am using DataContractJsonSerializer to de-serialize downloaded data into List of attendees.  Then I am adding them to the items collection, which in turn is exposed to UI as following:

                <ListBox x:Name="FirstListBox" Margin="0,0,-12,0" ItemsSource="{Binding Items}" >
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432" Height="78">
                                <TextBlock Text="{Binding FirstName}" TextWrapping="Wrap" 
                                         
Style="{StaticResource PhoneTextExtraLargeStyle}"/>

                                <TextBlock Text="{Binding LastName}" TextWrapping="Wrap" 
                                         
Margin="12,-6,12,0" Style="{StaticResource PhoneTextSubtleStyle}"/>

                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>

 

Next, Let’s look at the Create (Insert) method, as it demonstrates how to post data to the service.

        public void OnSaveAttendee(object parameter)
        {
           
string json = null
;
           
WebClient client = new WebClient
();
            client.Headers[
"Content-Type"] = "application/json"
;
 
           
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Attendee
));
           
using (MemoryStream stream = new MemoryStream
())
            {
                serializer.WriteObject(stream, CurrentAttendee);
                stream.Flush();
                json =
Encoding.UTF8.GetString(stream.ToArray(), 0, (int
)stream.Length);
 
            }
            client.UploadStringCompleted +=
new UploadStringCompletedEventHandler
(client_UploadStringCompleted);
            client.UploadStringAsync(
new Uri("http://localhost/WcfRestService/JSONDataService/Attendee/Create"), "POST"
, json);
        }
 
       
void client_UploadStringCompleted(object sender, UploadStringCompletedEventArgs
e)
        {
           
if (e.Error == null
)
            {
               
MessageBox.Show("OK"
);
            }
           
else

            {
               
MessageBox
.Show(e.Error.Message);
            }
 
        }

 

Now, I am reversing the order of operations.  I am serializing Attendee instance to Json, then using UTF8 encoding to convert the data to a string.  One important part to remember is to set content type on the request to JSON, otherwise you will get 404 Not Found.  In completed handler I am just checking for errors.  Again, I will end up eventually in my service’s Create method based on URI Template.

You can download entire solution here.  You will also notice that even though my classes on the client, such as Attendee:

using System.Collections.Generic;
using
System.ComponentModel;
 

namespace
VSLiveData.EF
{
   
public class Attendee : INotifyPropertyChanged

    {
       
public int AttendeeID { get; set; }
 
       
public string FirstName { get; set
; }
 
       
public string LastName { get; set
; }
 
       
public string Notes { get; set
; }
 
       
public virtual ICollection<Session> Sessions { get; set
; }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
 
       
private void NotifyPropertyChanged(string
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs
(propertyName));
            }
        }
    }
}

 

I am not calling NotifyPropertyChanged anywhere.  This is because I am using NotifyPropertyChangedWeaver, which is awesome!

Thanks.

Post to Twitter

Using WinDbg to Troubleshoot WCF Performance Issues

Yesterday I was working on a very interesting problem.  I am involved in developing a Silverlight application that is using WCF Services to communicate with a server to perform CRUD and business logic related operations.  All of a sudden QA started experiencing very slow performance testing application at random times.  Once we took a look, we noticed that CPU utilization kept hovering around 100 % at those times.  I was trying to figure out what is causing high CPU utilization.  Typically, those issues would be linked to tight loops of sorts, that tend to peg CPU at near maximum.  In our case, once CPU got to 100 %, it stayed there until app pool was recycled.  Give the tight loop hunch, I was guessing that somehow a service process was getting stuck in an infinite loop or some heavy processing loop. 

I blogged previously on using WinDbg to debug memory leaks in Silverlight applications.  It was time to find out if WinDbg would help me in this case as well.  The following describes the steps I took to troubleshoot the problem.

First of all, use steps in the previous post to install debugging tools for Windows.

Then, you need to catch the IIS process when it is in high SPU utilization mode.  You should let the system sit there for a little while to ensure you will capture the procedures that cause the trouble.  At that time open command window and switch to debugging tools directory.  In 64 bit Windows it is C:\Program Files\Debugging Tools for Windows (x64).  At the command prompt type “adplus -hang -o c:\dump\ -IIS”.  This will create process dump in c:\dump folder for all IIS related processes.

This you can reset IIS.

Next step is to run WinDbg and open a dump file using File->Open Crash Dump menu.  You will have multiple files with “dmp” extension in C:\Dump\<Time-Stamp> folder that was just created.  I’d pick the largest one, since this is likely to belong to your process.

Now, load debug symbols by typing the following into command window (one line high windows in the bottom of the WinDbg windows.).  Your cursor should be blinking there.  .load C:\Windows\Microsoft.NET\Framework64\v4.0.30319\sos.dll.  If you use 32 bit framework, adjust location accordingly.

image

Then, type “!runaway” command to get the list of running threads sorted by CPU time, starting the longest running thread.  If you suspect a hang, it is likely that your problem causing threads will be listed first.

image

Then, we will “select” a thread by using thread command – “~XXs”, where XX is the thread number from !runaway command.  In my case those are threads 18 and 30, sot the command would be ~18s

Now, we can look at the thread stack by using the following command – “!clrstack”.

 

image

What we are interested in is the very first line that points to PerfDemoWcfService.Service1.GetData method.  This is the method that causes the issue.  In my sample case methods…

  public class Service1 : IService1

  {

    public string GetData(int value)

    {

      Int64 variable = 0;

      while (true)

      {

        if (variable > 1000000000)

        {

          variable = 0;

        }

        else

        {

          variable++;

        }

      }

      return string.Format("You entered: {0}", value);

    }

 

 

… looks ridiculous.  In my real case it was a lot more complicated, but I did know what method is causing troubles for me.

 

Thanks.

Post to Twitter

Hosting WCF Data Services on Third Party Hosting Provider

Today I am going to talk about how to create a WCF Data Service and host it using a hosting provider.  My specific example will be using GoDaddy (www.GoDaddy.com).  This is the site where I host my blog.  I already posted on this topic, but was using Azure instead.  If you have a subscription to SQL Azure, you can sign up for WCF Data Service option with a single click (https://www.sqlazurelabs.com/).

The reason I decided to write this post was the fact that I got a question from one of the users of my Windows Phone database CodePlex project.  This developer was trying to speed up a query that was doing full-text search on 30,000 + records on Windows Phone.  My suggestion was to host this data in the cloud instead because then you can use full power of the SQL Server (or other RDBMS) to speed up the data retrieval.

First step is to sign up for the database on GoDaddy.  Most packages they sell offer a database.  My package came up with 1 SQL Server database and 10 MySql databases.  Also, I configured my web site on GoDaddy to use ASP.NET 4.0.  I need to use .NET 4 to get support for Data Services.  I could use either SQL Server of MySql, but will illustrate SQL Server in this post.  Once I created database, I was able to use SSQM (SQL Server Management Studio) to connect to the DB server and add tables to my database. Then, I am going to start on WCF Data Service. 

First of all, I am going to create new empty web application project by going to New Project in VS 2010.

image

Then, I am going to use Entity Framework to create a new model.  To do so I am going to add new item and select ADO.NET Entity Data model.

image

I am going to choose the option to generate from the existing database in the wizard, and I am going to select only the tables I need in the mode.  To connect to SQL Server on GoDaddy I needed to write down server name in the control panel on hosting option on GoDaddy.  I input all the settings into the data model wizard after clicking on New Connection button.

image

Then I am presented with my brand spanking new entity model.

image

Now I need to create WCF Data Service.  To do so, I am going to add new item to my web project and select WCF Data Service this time.  Then I put my simple rule into the service definition, allowing all access only to the tables in my model of course.

namespace CompanyWeb
{
   
public class CompanyWcfDataService : DataService<CompanyEntities
>
    {
       
public static void InitializeService(DataServiceConfiguration
config)
        {
            config.SetEntitySetAccessRule(
"*", EntitySetRights
.All);
            config.SetServiceOperationAccessRule(
"*", ServiceOperationRights
.All);
            config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
        }
    }
}

 

So far so good.  Now am I am going to test my setup locally by browsing to /CompanyWcfDataService.svc/ file in my project.  Just right click on it and select Browse.  Then I am going to add ContactRoles to the end of the Url and test that.I am getting the data.  I will get Atom Pub page similar to any RSS feed.  I am just looking for number of records those, since I

Now I need to deploy the web project.  First, use content –> IIS menu to create new folder and mark it as application root as well as enable Anonymous authentication. I am going then to use file manager in GoDaddy control panel to create a folder on my web site and copy all the files for my web project there.  Alternatively you can use FTP.  All I would need is to transfer bin folder, .SVC file and web.config.  Here is the final version of web.config:

<?xml version="1.0" encoding="utf-8"?>
<!–

  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
 
–>
<
configuration
>
    <
system.web
>
        <
customErrors mode="Off"
/>
        <
compilation debug="true"
/>
    </
system.web
>
    <
system.webServer
>
        <
httpErrors errorMode="Detailed"
/>
        <
asp scriptErrorSentToBrowser="true"
/>
    </
system.webServer
>
    <
connectionStrings
>
        <
add name="CompanyEntities" connectionString="metadata=res://*/CompanyModel.csdl|res://*/CompanyModel.ssdl|res://*/CompanyModel.msl;provider=System.Data.SqlClient;provider connection string=&quot;Data Source=serverIP;Initial Catalog=DBName;Persist Security Info=True;User ID=UserID;Password=Password;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient"
/>
    </
connectionStrings
>
    <
system.serviceModel
>
        <
serviceHostingEnvironment aspNetCompatibilityEnabled="true"
>
            <
baseAddressPrefixFilters
>
                <
clear
/>
                <
add prefix="http://www.yoursite.com/yourservicefolder/"/>
            </
baseAddressPrefixFilters
>
        </
serviceHostingEnvironment
>
        <
behaviors
>
            <
serviceBehaviors
>
                <
behavior
>
                    <
serviceDebug includeExceptionDetailInFaults="true"
/>
                </
behavior
>
            </
serviceBehaviors
>
        </
behaviors
>
    </
system.serviceModel
>
</
configuration
>

 

A couple of things to point out.  I am using configuration under system.web to troubleshoot errors.  I have to update service hosting environment to configure prefix to filter out requests I need.  Behavior is also setup to easy in troubleshooting. 

When all said and done, I am testing the service in IQ using the address of my service http://www.yoursite.com/yourservicefolder/CompanyWcfDataService.svc/ContactRoles

Then I got an error – IIS specified authentication schemes ‘Basic, Anonymous’, but the binding only supports specification of exactly one authentication scheme. Valid authentication schemes are Digest, Negotiate, NTLM, Basic, or Anonymous. Change the IIS settings so that only a single authentication scheme is used. To solve this I had to call GoDaddy support to ask them to turn off basic authentication on my site.  That was the last step.

Now, you can simply add a reference to the new service in your Silverlight or phone application.  See my previous posts for details on the process.

A couple of final thoughts.

  • If you are transferring sensitive data, consider buying SSL certificate.
  • Use error configuration to troubleshoot deployment issues.
  • You can use MySQL database with entity framework, you just need to download appropriate provider.
  • Almost exact same process applies to traditional WCF Service.

Please let me know if you have any questions.

Post to Twitter

Working with Data on Windows Phone 7 – Part 2

In this part I am going to use WCF Data Services (formerly known as project Astoria and ADO.NET Data Services) to accomplish the same couple of tasks I did in WCF custom service.  I am going to get a list of people and add a person.

I will use exact same project as I did the last time.  As you recall, I created a database with one table using EF Code First.  This is where I am going to start.  In first step I am going to create an Entity Framework model from that database.  To do so, I am going to add new item to my web project and select Entity Framework model.

image

I will then walk through EF model wizard to generate the model from my database:

image

image

 

image

This will generate my model with my person class.

WCF Data Service will expose my model via web RESTful interfaces.  To add the service, I am going to add new item again, but now select WCF Data Service as item type:

 

image

Next step is to configure WCF Data Service to use my entity model.  This step is pretty easy, since service is a generic type with a parameter that takes entity model

    public class PersonWcfDataService : DataService<PersonsDbEntities>
    {
       
public static void InitializeService(DataServiceConfiguration
config)
        {
            config.SetEntitySetAccessRule(
"*", EntitySetRights
.All);
            config.DataServiceBehavior.MaxProtocolVersion =
DataServiceProtocolVersion.V2;
        }
    }

 

In the code above I am setting rights to all entities to everyone.  In production I would not do this, but it works as illustration.  In my next step I am going to test the service.  I am going to right click on PersonWcfDataService.svc file that was generated in the step above and select View In Browser.

image

Next, I want to make sure I can get the list of people.  I am going to change my Url and test that.  You can see the address and result below:

image

Of course the results look like Atom feed since OData that WCF Data Service implement extends AtomPub protocol.  I can look at the data by selecting view source.  The data looks as following:

image

Next I need to generate proxy for my Phone application.  Unfortunately, add service reference does not work for phone Silverlight applications.  So, I am going to download necessary files from CodePlex to proceed.

Visit http://odata.codeplex.com and download ODataClient_BinariesAndCodeGenToolForWinPhone.zip.  Once it is on your local machine, unblock the zip file in windows properties, otherwise you will get compilation errors later.  Unzip it into a blank folder to make it easy to find later.

Here is the content of the folder:

image

Add a reference to System.Data.Services.Client.dll to your windows phone project.  Now, we need to generate proxy and related classes.  To do so we will use DataSvcUtil.exe from the same folder.  Here is the command line I am using:

 

datasvcutil /uri:http://localhost:50406/PersonWcfDataService.svc/ /out:.\PersonModel.cs /DataServiceCollection /Version:2.0

As you can see I am providing my svc file’s url.  I am using version 2 of the data services.  I am outputting the proxy into PersonModel.cs file.  DataServiceCollection parameter instructs the utility to generate collections that derive from DataSericeCollection.  Next I am include this file in my project.

Next I am going to create an instance of the client in my view model as following:

PersonsDbEntities odataClient;

odataClient =

         new PersonsDbEntities(new Uri(@"http://localhost:50406/PersonWcfDataService.svc"));

 

Of course in production you need to give correct Url.  Next, I am going to query the data.  First I am going to define a property to hold my collection


        private DataServiceCollection<PersonsDbModel.Person> oDataPeople;
 
       
public DataServiceCollection<PersonsDbModel.Person
> ODataPeople
        {
           
get { return
oDataPeople; }
           
set
            {
                oDataPeople =
value
;
                NotifyPropertyChanged(
"ODataPeople");
            }
        }

 

Then I am going to query the data as following

            ODataPeople = new DataServiceCollection<PersonsDbModel.Person>(odataClient);
            ODataPeople.LoadCompleted += ODataPeople_LoadCompleted;
 
           
try
            {
                ODataPeople.LoadAsync(peopleUri);
            }
           
catch (DataServiceClientException
ex)
            {
               
MessageBox.Show(ex.ToString());
            }

 

So, first I create a collection and tie it to my client.  Without that I can query the collection.  In the callback I check for errors:

        void ODataPeople_LoadCompleted(object sender, LoadCompletedEventArgs e)
        {
           
if (e.QueryOperationResponse.Error != null
)
            {
               
MessageBox.Show(e.QueryOperationResponse.Error.ToString());
            }
        }

 

That I it.  Now I just add a listbox to my UI and bind it to this collection:

            <controls:PivotItem Header="oData">
                <!–Double line list with text wrapping–>
                <ListBox x:Name="ODataListBox" Margin="0,0,-12,0"
 
                       
ItemsSource="{Binding ODataPeople}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432">
                                <TextBlock
 
                                
Text="{Binding FirstName}"
 
                                
TextWrapping="Wrap"
 
                                
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                                <TextBlock
 
                                
Text="{Binding LastName}"
 
                                
TextWrapping="Wrap"
 
                                
Margin="12,-6,12,0"
 
                                
Style="{StaticResource PhoneTextSubtleStyle}"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </controls:PivotItem
>

 

Next, adding a person via OData.  It is really simple.  I just add new person to my collection and start the save process.  DataSericeCollection  objects are smart to keep track of the changes that occur during operation on the server.


        public void InsertPersonOdata()
        {
            ODataPeople.Add(
new PersonsDbModel.Person() { FirstName = "James", LastName = "Homer", PersonID = Guid
.NewGuid() });
            odataClient.BeginSaveChanges(
SaveChangesOptions
.Batch, (ar) =>
            {
               
Deployment
.Current.Dispatcher.BeginInvoke(() =>
                {
                    odataClient = ar.AsyncState
as PersonsDbModel.PersonsDbEntities
;
                   
DataServiceResponse
response = odataClient.EndSaveChanges(ar);
                   
if
(response.IsBatchResponse)
                    {
                       
StringBuilder errors = new StringBuilder
();
                       
foreach (ChangeOperationResponse change in
response)
                        {
                           
if (change.Error != null
)
                            {
                                errors.Append(change.Error.ToString());
                            }
                        }
                       
if
(errors.Length == 0)
                        {
                           
MessageBox.Show("Success"
);
                        }
                       
else
                        {
                           
MessageBox.Show(errors.ToString());
                        }
                    }
                });
            }, odataClient);
        }

 

You can download the entire solution for both parts 1 and 2 here.  There does seem to be some flakiness in running both services from one solution, so you may have to comment WCF Service or OData service calls to test each portion.

Post to Twitter

Working with Data on Windows Phone 7 – Part 1

I am starting a short series of blog posts that will go over various techniques of working with data on Windows Phone 7.  I am going to create a Silverlight application for the phone that gets local and remote data in a number of ways.

I this first post I will build a WCF service and connect to it from phone application.  I am going to use Entity Framework Code Frist approach to expose the data through my WCF Service.

Let’s get started.

Step 1

I am going to create new phone application.  Start Visual Studio 2010 and create new project.  Select a project template for Windows Phone Pivot Application.

image

Now, I forget about pre-generated code and create a WCF service.  To do so, add new project to created solution.  To give you a head start, select template for WCF Service Application.

image

Now, it is time to get Entity Framework code first CTP 5 up and going to create database and access it.  I am going to use NuGet (install it first if you do not have it).  Right click on references in your WCF project and select add Package References.  Choose to search on line and first the CTP 5.

image

I am installing the package which will download the DLL and add references to my project.  I am also adding a reference to System.ComponentModel.DataAnnotations.

Now I am going to add my EF classes, which are POCO classes.  I am going to go for something simple, so I am creating new single object called Person along with my data context.  Person class is very simple and here is the code for it.

using System;
using System.ComponentModel.DataAnnotations;
using
System.Runtime.Serialization;
 

namespace
WcfPhoneService
{
    [
DataContract
]
   
public class Person
    {
        [
Key
]
        [
Required
]
        [
DataMember
]
       
public Guid PersonID { get; set
; }
 
        [
MaxLength
(30)]
        [
Required
]
        [
DataMember
]
       
public string FirstName { get; set
; }
 
        [
MaxLength
(30)]
        [
Required
]
        [
DataMember
]
       
public string LastName { get; set; }
    }
}

 

There are a couple of points worth noticing.  I am using data annotation attributes to denote the requirement of all my future columns in the table.  I am setting the maximum length as well as the key for the table.  I am also setting the WCF required attributes as I am going to be eventually transferring these classes to/from the phone application.  I also need to create the data context, akin to database that will contain my list of persons.  It inherits from base class in EF CTP 5 and contains the list (set) of persons.  Again. code is pretty simple:

using System.Configuration;
using System.Data.Entity;
using
System.Data.Entity.Database;
 

namespace
WcfPhoneService
{
   
public class PersonContext : DbContext
    {
       
public
PersonContext()
        {
           
//Set initializer to handle model changes
            DbDatabase.SetInitializer<PersonContext>(new PersonContextConfig
());
 
           
this
.Database.Connection.ConnectionString =
                   
ConfigurationManager.ConnectionStrings["PersonConnectionString"
]
                    .ConnectionString;
        }
 
       
/// <summary>
        /// List of persons
        /// </summary>
        public IDbSet<Person> Persons { get; set
; }
 
       
/// <summary>
        /// Add custom configurations if necessary
        /// </summary>
        /// <param name="modelBuilder">Model builder</param>
        protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder
modelBuilder)
        {
           
base.OnModelCreating(modelBuilder);
 
        }
    }
}

 

You can see an extra class in the constructor called PersonContextConfig.  This class simply controls the default database behavior of the context when the model changes.  I am setting it to recreating of the database in my case.  I also added a couple of rows of data just for the demo by overriding Seed method.

using System.Data.Entity.Database;
using
System;
 

namespace
WcfPhoneService
{
   
public class PersonContextConfig : DropCreateDatabaseIfModelChanges<PersonContext
>
    {
       
protected override void Seed(PersonContext
context)
        {
           
base
.Seed(context);
            context.Persons.Add(
new Person() { PersonID = Guid.NewGuid(), FirstName = "John", LastName = "Doe"
});
            context.Persons.Add(
new Person() { PersonID = Guid.NewGuid(), FirstName = "Jane", LastName = "Doe" });
            context.SaveChanges();
        }
    }
}

 

Now, it is time to create my service.  I am going to add just two methods to it – get list of persons and insert a new person.  When project was created, it created default IService1 interface and Service1 implementation.  I am just going to rename both to IPersonService and PersonService respectively.  Then, I am going to implement the two methods above

using System.Collections.Generic;
using
System.ServiceModel;
 

namespace
WcfPhoneService
{
    [
ServiceContract
]
   
public interface IPersonService
    {
        [
OperationContract
]
       
IEnumerable<Person
> GetPeople();
 
        [
OperationContract
]
       
void AddPerson(Person person);
    }
 
 
 
}

 

using System.Collections.Generic;
using
System.Linq;
 

namespace
WcfPhoneService
{
 
   
public class PersonService : IPersonService
    {
       
public IEnumerable<Person
> GetPeople()
        {
           
using (PersonContext context = new PersonContext
())
            {
               
return
context.Persons.OrderBy(one => one.LastName).ThenBy(one => one.FirstName).ToList();
            }
        }
 
       
public void AddPerson(Person
person)
        {
           
using (PersonContext context = new PersonContext())
            {
                context.Persons.Add(person);
                context.SaveChanges();
            }
        }
    }
}

 

Pretty simple, right.  Now I am going to switch to my Phone project.  I am going to remove all pre-generated code from all view models first and build the project to make sure it is all good.  Now, it is time to add a service reference to my WCF project.  To do so, right click on references node in phone project and choose add service reference menu item.  Click on Discover button on the service dialog box.  Change namespace to PersonService for consistency.

image

Click OK and let the studio generate all your code for you.  To see generated code, click on PersonService reference under service references, then click on Show All Files on top of Solution explorer window.  You can then drill down to see Reference.cs.  This contains all your generated code.

image

I am now going to update view model to let it connect to the service and get the list of people.  I have to create an instance of the client (proxy), setup a handler for GetPeople method, then call it.  I also add a property to hold Person collection in.  All fairly simple.  Here is the entire code:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using
WindowsPhonePivotAppWithData.PersonService;
 
 

namespace
WindowsPhonePivotAppWithData
{
   
public class MainViewModel : INotifyPropertyChanged
    {
        PersonService.
PersonServiceClient client = new PersonService.PersonServiceClient
();
       
public
MainViewModel()
        {
 
        }
 
       
private ObservableCollection<Person
> people;
 
       
public ObservableCollection<Person
> People
        {
           
get { return
people; }
           
private set { people = value; NotifyPropertyChanged("People"
); }
        }
 
       
public void
LoadData()
        {
            client.GetPeopleCompleted += client_GetPeopleCompleted;
            client.GetPeopleAsync();
        }
 
       
void client_GetPeopleCompleted(object sender, PersonService.GetPeopleCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
                People = e.Result;
            }
        }
 
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

The last part is to modify the MainPage.xaml and update item template to point to the properties that belong to person class, namely last name and first name.

        <controls:Pivot Title="MY APPLICATION">
            <!–Pivot item one–>
            <controls:PivotItem Header="first">
                <!–Double line list with text wrapping–>
                <ListBox x:Name="FirstListBox" Margin="0,0,-12,0"
 
                       
ItemsSource="{Binding People}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                          <StackPanel Margin="0,0,0,17" Width="432">
                              <TextBlock
 
                                
Text="{Binding FirstName}"
 
                                
TextWrapping="Wrap"
 
                                
Style="{StaticResource PhoneTextExtraLargeStyle}"/>
                              <TextBlock
 
                                
Text="{Binding LastName}"
 
                                
TextWrapping="Wrap"
 
                                
Margin="12,-6,12,0"
 
                                
Style="{StaticResource PhoneTextSubtleStyle}"/>
                          </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </controls:PivotItem
>

 

Now we will just call LoadData from the code behind of MainPage.  This is just a temporary fix, ordinarily I would have the view / view model hook up elsewhere.

    public partial class MainPage : PhoneApplicationPage
    {
       
// Constructor
        public
MainPage()
        {
            InitializeComponent();
 
            DataContext =
App
.ViewModel;
           
App.ViewModel.LoadData();
        }
    }

 

That was the last part.  Now we can run the phone application in the emulator.  And we should be able to see the list of two people that were inserted in Seed() method above.

To summarize, we just consumed WCF service from the phone.  To call the same from a deployed application, we will need to change the address in ServiceReference.ClientConfig file.  That is it.

The other part I would like to try is to insert a new person.  I am going to add a button to the second pivot item and call the insert method.  I am going to just use code behind, but you can look at my past posts on how do use MVVM Light to wire up commands.

            <controls:PivotItem Header="second"> 
                <Grid>
                    <Button
 
                      
Content="Insert Person"
 
                      
Click="Button_Click"
 
                      
Width="200"
 
                      
Height="100"/>
                </Grid>
            </controls:PivotItem
>

 

Here is the code in the view model that I need to add:

        public void InsertPerson()
        {
            client.AddPersonAsync(
new Person
() 
            { PersonID =
Guid.NewGuid(), FirstName = "John", LastName = "Johnson" });
        }

 

Here is the final code for my view model:

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using
WindowsPhonePivotAppWithData.PersonService;
 
 

namespace
WindowsPhonePivotAppWithData
{
   
public class MainViewModel : INotifyPropertyChanged
    {
        PersonService.
PersonServiceClient
client;
       
public
MainViewModel()
        {
            client =
new PersonService.PersonServiceClient
();
            client.AddPersonCompleted += client_AddPersonCompleted;
            client.GetPeopleCompleted += client_GetPeopleCompleted;
        }
 
       
private ObservableCollection<Person
> people;
 
       
public ObservableCollection<Person
> People
        {
           
get { return
people; }
           
private set { people = value; NotifyPropertyChanged("People"
); }
        }
 
       
public void
LoadData()
        {
 
            client.GetPeopleAsync();
        }
 
       
void client_GetPeopleCompleted(object sender, PersonService.GetPeopleCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
                People = e.Result;
            }
        }
 
       
public void
InsertPerson()
        {
            client.AddPersonAsync(
new Person
() 
            { PersonID =
Guid.NewGuid(), FirstName = "John", LastName = "Johnson"
});
        }
 
       
void client_AddPersonCompleted(object sender, AsyncCompletedEventArgs
e)
        {
           
if (e.Error != null
)
            {
               
MessageBox
.Show(e.Error.ToString());
            }
           
else
            {
               
MessageBox.Show("Succecss adding person"
);
                client.GetPeopleAsync();
            }
        }
 
       
public event PropertyChangedEventHandler
PropertyChanged;
       
private void NotifyPropertyChanged(String
propertyName)
        {
           
PropertyChangedEventHandler
handler = PropertyChanged;
           
if (null
!= handler)
            {
                handler(
this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

 

And that is all there is to it.  We created a WCF service and consumed it from Windows phone application.  I used Entity Framework code first to create classes and I used the same classed as data contract for my service.  In the next post of this short series I will work on consuming a custom OData service.

Post to Twitter

Windows Azure Application

This is purely a bragging post :-)

I just deployed a test application to the cloud (Microsoft Azure): http://rolodex.cloudapp.net/

Here is the technology stack for it:

  1. Windows Azure
  2. SQL Azure
  3. CSLA 3.8.1
  4. Silverlight
  5. Entity Framework
  6. WCF
  7. Prism (Composite Application Guidance)
  8. Silverlight Toolkit

I promise to write a blog entry in the near future, the steps one has to follow through to create an Azure application.

Post to Twitter

WCF, basicHTTPBinding and compression

I am working on a distributes WPF application.  This application has rich client UI, while getting the data from a database server.  One complication is that this software will be installed at a several companies across the US.  All the installation have to communicate with central application server that will be hosted inside a data center.  As I was working on  a class that provides a list of customers (only about 3,500 rows), I decided to measure the traffic and performance.  I was rather unpleasantly surprised with the message size.  It was 7.5MB in Fiddler 2.  By the way, if you want to measure local traffic in Fiddler while using basicHTTPBinding with WCF, set your endpoint to 127.0.0.1. (yes, you need that trailing period) in order to trick Fiddler into thinking that this is external communication.  When I tried to switch to custom binding using binary messaging, the size only shrunk by 1 MB!  I was expecting much more than that…  Here is how I accomplished that:

<customBinding>
                <binding name="NetHttpBinding" receiveTimeout="00:10:00"
                        sendTimeout="00:10:00"
                        openTimeout="00:10:00">
                    <reliableSession />
                    <binaryMessageEncoding  maxReadPoolSize="2147483647" maxWritePoolSize="2147483647" maxSessionSize="2147483647">
                        <readerQuotas
                            maxBytesPerRead="2147483647"
                            maxArrayLength="2147483647"
                            maxStringContentLength="2147483647"
                            maxDepth="1024"/>
                    </binaryMessageEncoding>
                    <httpTransport maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" />
                </binding>
            </customBinding>

So, what next?

I thought of compression next.  Guess what, WCF does not have a built in compression mechanisms.

So, I found a few posts of similar implementation (all years old) and fix bugs and extended them to do what I need.  I got the message size down to 400 KB (or so), which is more that I would like, but 90% compression is not something I am going to complain about.  I did not want to switch binding because of firewall issues.

Here is the mechanism that was used.  We extended the WCF behavior by defining a class that implements BehaviorExtensionElement.  Once you do that, you can reference it inside your configuration file as so:

<extensions>
            <behaviorExtensions>
                <add name="compression" type="Compression.CompressionBehaviorSection, Compression, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b99ba6caceb1e8ad"/>
            </behaviorExtensions>
        </extensions>

And

<behaviors>
            <serviceBehaviors>
                <behavior name="WcfPortalBehavior">
                    <serviceMetadata httpGetEnabled="true"/>
                    <serviceDebug includeExceptionDetailInFaults="true"/>
                    <compression/>
                </behavior>
            </serviceBehaviors>
        </behaviors>The key class in implementation has to implement the following interfaces: IEndpointBehavior (client side)

and IServiceBehavior (server side).  I actually combined both in the same class.  You would also need to implement message inspector interfaces that WCF will call if they are registered to perform actions on the message.  These interfaces are: IDispatchMessageInspector (server side) and IClientMessageInspector(client side)

Post to Twitter

How to debug WCF service server side errors

So, here is the issue I encountered today.  I have a solution that is using WCF service to communicate.  My WCF service is hosted in a web site (web application project).  I was getting error from my client, stating that connection was forcibly closed by the server.  I could not figure out why even though I configured behavior to "includeExceptionDetailInFaults".  So, here is the solution that I found.

I added the following to web.config file to web site that hosts WCF service.

<system.diagnostics>
        <sources>
            <source name="System.ServiceModel"
                    switchValue="Information, ActivityTracing"
                    propagateActivity="true">
                <listeners>
                    <add name="traceListener"
                        type="System.Diagnostics.XmlWriterTraceListener"
                        initializeData= "c:\Traces.svclog" />
                </listeners>
            </source>
        </sources>
    </system.diagnostics>

Voila.  I ran the process again, double-clicked on trace log that opened in a viewer.  I was informed that I forgot to add Serializable attribute to my class I was sending across the wire.

What an easy solution!  What a greate WCF feature as well – you can debug service even in production without changing code – just change configuration file.  The same trick works in Windows hosted WCF services – just add the same stuff to app.config.

Post to Twitter