Tuesday, November 22, 2011

Calling WCF From Silverlight Without Using Service Reference

Calling WCF From Silverlight Without Using Service Reference
In this article I will demonstrate how to call WCF service without using the Service Reference. Practical reasons of doing this as a developing is allowing us to have more control over our calls to WCF.

Basically I will introduce two ways of doing this;

1. Using the ChannelFactory

2. Using the ClientBase

To start calling WCF service to your Silverlight application first we have to copy the ServiceContract and DataContract codes to our silverlight projects.

namespace Demo.Wcf.Services
{
[System.ServiceModel.ServiceContract()]
public interface PersonService
{

[System.ServiceModel.OperationContract(AsyncPattern = true)]
IAsyncResult BeginGetPerson(int no, AsyncCallback callback, object state);

Person EndGetPerson(IAsyncResult result);

}

[System.Runtime.Serialization.DataContract()]
public class Person
{
private int _No;
[System.Runtime.Serialization.DataMember()]
public int No
{
get { return _No; }
set { }
}

private string _FirstName;
[System.Runtime.Serialization.DataMember()]
public string FirstName
{
get { return _FirstName; }
set { _FirstName = value; }
}

private string _LastName;
[System.Runtime.Serialization.DataMember()]
public string LastName
{
get { return _LastName; }
set { _LastName = value; }
}

private DateTime _BirthDate;
[System.Runtime.Serialization.DataMember()]
public DateTime BirthDate
{
get { return _BirthDate; }
set { _BirthDate = value; }
}

public Person(int no)
{
_No = no;
}
}
}
First thing to note from the above code is the namespace should be the same namespace as the service definition. Secondly, the service methods will be defined using the Async pattern. Primary reason for doing this is Silverlght 2 only supports async operations to WCF calls. To define the service methods using async pattern is to define methods with Begin and End prefix (e.g. BeginGetPerson, EndGetPerson) and set the attribute OperationContract AsyncPattern parameter to true. This will instruct the runtime to interprete the methods prefixed by Begin and End.

Now we come to the most interesting part how to call the service. as mention we will implement this in wo ways

Using ChannelFactory

protected void Page_Loaded(object sender, RoutedEventArgs e)
{
PersonService svc = new ChannelFactory(
new BasicHttpBinding(),
new EndpointAddress("http://localhost:9902/PersonService.svc")).CreateChannel();
svc.BeginGetPerson(0,
delegate(IAsyncResult result)
{
Person p = ((PersonService)result.AsyncState).EndGetPerson(result);
this.Dispatcher.BeginInvoke(
delegate()
{
txtName.Text = p.FirstName;
}
);
},
svc);
}
As you can see from the above code that it is pretty straight forward similar on the how the ChannelFactory is being used by the .NET Framework. However important thing to note was to use the Dispatcher when assigning values to the control properties this is to avoid cross-thread errors.

Using the ClientBase

To use the ClientBase we need to create a class that will inherit the ClientBase class and for the sake of my implementation I suggest to create an event argument class as well. This is necessary because our implementatio will be using the event base pattern.


namespace Demo.Wcf.Services
{
public class PersonServiceEventArgs : EventArgs
{
private Person _Result;

public Person Result
{
get { return _Result; }
}

public PersonServiceEventArgs(Person result)
{
_Result = result;
}
}

public class PersonServiceClient : ClientBase
{
public event EventHandler GetPersonCompleted;

public PersonServiceClient(Binding binding, EndpointAddress endpoint) : base(binding, endpoint)
{

}

public void GetPersonAsync(int no)
{
IAsyncResult result = Channel.BeginGetPerson(no, GetPersonCallback, no);
}

private void GetPersonCallback(IAsyncResult result)
{
Person p = Channel.EndGetPerson(result);
if (GetPersonCompleted != null)
GetPersonCompleted(this, new PersonServiceEventArgs(p));
}

protected override PersonService CreateChannel()
{
return base.CreateChannel();
}
}
}
The above example is also straightforward is a sense that we implemented an event that will response when the call from WCF has been completed and the result will be retrieved from the event argument class that we created. Now to call this from your Silverlight is pretty simple also.

protected void Page_Loaded(object sender, RoutedEventArgs e)
{

PersonServiceClient proxy = new PersonServiceClient(new BasicHttpBinding(), new EndpointAddress("http://localhost:9902/PersonService.svc"));
proxy.GetPersonCompleted += delegate(object source, PersonServiceEventArgs args)
{
this.Dispatcher.BeginInvoke(
delegate()
{
txtName.Text = args.Result.FirstName;
}
);
};

proxy.GetPersonAsync(0);
}

0 comments:

Post a Comment