WCF, Silverlight – Access WCF REST services with Silverlight

Windows Communication Foundation (WCF), part of the .NET Framework, provides the first unified programming model for rapidly building service-oriented applications. It enables the development of secure, reliable, transacted services that interoperate with current Microsoft investments and non-Microsoft platforms.

With the .NET Framework 3.5 release, WCF added support for building REST style services. REST, an architectural style for building distributed hypermedia driven applications, involves building resource-oriented services by defining resources that implement uniform interfaces using standard HTTP verbs (GET, POST, PUT, and DELETE), and that can be located/identified by a URI.

That is a snapshot about WCF REST Service. If you want to learn more about this type of service you can read here http://msdn.microsoft.com/en-us/netframework/dd547388.aspx . In this small post, I would like to illustrate how I create a WCF REST service and access it through a Silverlight application. This WCF Services allow me to show, edit and insert data from/into database in back-end.

1. Create a blank solution and add to it a WCF Service and a Silverlight application.
2. In WCF Service, define the Service Contract and its operation contract in an interface

[OperationContract]
[WebInvoke(
	BodyStyle=WebMessageBodyStyle.Bare,
	Method="POST",
	RequestFormat=WebMessageFormat.Xml,
	ResponseFormat=WebMessageFormat.Xml,
	UriTemplate="CreateStudent/{StudentName}/{Chair}/{AverageNote}")]
int Insert(string StudentName, string Chair, string AverageNote);

[OperationContract]
[WebInvoke(
	BodyStyle = WebMessageBodyStyle.Bare,
	Method = "POST",
	RequestFormat = WebMessageFormat.Xml,
	ResponseFormat = WebMessageFormat.Xml,
	UriTemplate = "DeleteStudent/{StudentID}")]
int DeleteStudent(string StudentID);

[OperationContract]
[WebGet(
	BodyStyle= WebMessageBodyStyle.Bare,
	RequestFormat = WebMessageFormat.Xml,
	ResponseFormat = WebMessageFormat.Xml)]
Student[] GetAllStudents();

You can see the differences in compare to a normal WCF Services. I have used ‘WebGet’ (indicates that a service operation is logically a retrieval operation and that it can be called by the Web programming model) and ‘WebInvoke’ (indicates a service operation is logically an invoke operation and that it can be called by the Web programming model) attributes along with ‘OperationContract’. WebGet has HTTP ‘GET’ by default and ‘WebInvoke’ can be used for HTTP ‘PUT’, ‘POST’ and ‘DELETE’ verbs. Request and Response formats can be either ‘XML’ or ‘JSON’.

3. Create a Dataset to access our database by adding new Item “Dataset” and drag-and-drop the table which we want to work with on Dataset. Insert some queries that we need for later using.

4. Implement the interface to tell what the WCF REST service should do when I call it.

// NOTE: If you change the class name "StudentService" here, you must also update the reference to "StudentService" in Web.config.
public class StudentService : IStudentService
{

	#region IStudentService Members

	public int Insert(string StudentName, string Chair, string AverageNote)
	{
		StudentViewTableAdapters.StudentTableAdapter adapter = new DMLService.StudentViewTableAdapters.StudentTableAdapter();
		return adapter.Insert(StudentName, Convert.ToInt32(Chair), Convert.ToInt32(AverageNote));
	}

	public int DeleteStudent(string StudentID)
	{
		StudentViewTableAdapters.StudentTableAdapter adapter = new DMLService.StudentViewTableAdapters.StudentTableAdapter();
		return adapter.DeleteStudent( Convert.ToInt32(StudentID));
	}

	public Student[] GetAllStudents()
	{
		List<Student> lstTemp = new List<Student>();
		Student stuTemp = null;
		StudentViewTableAdapters.StudentTableAdapter adapter = new DMLService.StudentViewTableAdapters.StudentTableAdapter();
		StudentView.StudentDataTable dtStudents = adapter.GetData();
		for (int nIndex = 0; nIndex < dtStudents.Rows.Count; nIndex++)
		{
			stuTemp = new Student();
			stuTemp.StudentID = (int) dtStudents.Rows[nIndex]["StudentID"];
			stuTemp.StudentName = (string) dtStudents.Rows[nIndex]["StudentName"];
			stuTemp.Chair = (int) dtStudents.Rows[nIndex]["Chair"];
			stuTemp.AverageNote = (int) dtStudents.Rows[nIndex]["AverageNote"];
			lstTemp.Add(stuTemp);
		}
		return lstTemp.ToArray();
	}

	#endregion
}

5. Publish your WCF REST Services to localhost. If you do not know how to publish it, then read this post http://hintdesk.com/wcf-publish-wcf-services-in-iis-7-step-by-step-for-dummies/

6. Build User Interface for your Silverlight application. Then add code to get, insert and delete data

private void btnGetAll_Click(object sender, System.Windows.RoutedEventArgs e)
{
	// TODO: Add event handler implementation here.
	WebClient wcClient = new WebClient();
	wcClient.DownloadStringCompleted += new DownloadStringCompletedEventHandler(wcClient_DownloadStringCompleted);
	wcClient.DownloadStringAsync(new Uri("http://localhost/StuSer/StudentService.svc/GetAllStudents"), UriKind.Absolute);
}

void wcClient_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
	if (e.Error == null)
	{
		XDocument xdStudent = XDocument.Parse(e.Result);
		var vStudents = from stu in xdStudent.Descendants("Student")
						select new Student()
						{
							StudentID = Convert.ToInt32(stu.Descendants("StudentID").First().Value),
							StudentName = stu.Descendants("StudentName").First().Value,
							Chair = Convert.ToInt32(stu.Descendants("Chair").First().Value),
							AverageNote = Convert.ToInt32(stu.Descendants("AverageNote").First().Value)
						};
		dgStudents.DataContext = vStudents.ToList();
	}

}

private void btnInsert_Click(object sender, System.Windows.RoutedEventArgs e)
{
	try
	{
		// TODO: Add event handler implementation here.
		string strInsertUrl = "http://localhost/StuSer/StudentService.svc/CreateStudent/" + txtName.Text + "/" + txtChair.Text + "/" + txtNote.Text;
		WebRequest wreqInsert = WebRequest.Create(strInsertUrl);
		wreqInsert.Method = "POST";
		wreqInsert.BeginGetRequestStream(RequestCallback, wreqInsert);
	}
	catch (Exception ex)
	{
		HtmlPage.Window.Alert(ex.Message);
	}
}

private void RequestCallback(IAsyncResult ar)
{
	WebRequest wreqInsert = (WebRequest)ar.AsyncState;
	Stream strReq = wreqInsert.EndGetRequestStream(ar);
	strReq.Close();
	wreqInsert.BeginGetResponse(ResponseCallback, wreqInsert);
}

private void ResponseCallback(IAsyncResult ar)
{
	try
	{
		WebRequest wreqInsert = (WebRequest)ar.AsyncState;
		WebResponse wrpsInsert = wreqInsert.EndGetResponse(ar);
		Stream streamResult = wrpsInsert.GetResponseStream();
		streamResult.Close();
		wrpsInsert.Close();
	}
	catch (Exception ex)
	{
		HtmlPage.Window.Alert(ex.Message);
	}
}

If you have System.Security. Security Exception in Silverlight application, then you need to add 2 files clientaccesspolicy.xml and crossdomain.xml in your wwwroot folder

– clientaccesspolicy.xml

<?xml version="1.0" encoding="utf-8" ?>
<access-policy>
  <cross-domain-access>
    <policy>
      <allow-from http-request-headers="*">
        <domain uri="*"/>
      </allow-from>
      <grant-to>
        <resource path="/" include-subpaths="true"/>
      </grant-to>
    </policy>
  </cross-domain-access>
</access-policy>

– crossdomain.xml

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
  <allow-http-request-headers-from domain="*" headers="*"/>
</cross-domain-policy>

The complete source code of this example you can download here “DML Operation using WCF REST services and Silverlight

7 thoughts on “WCF, Silverlight – Access WCF REST services with Silverlight”

  1. Hi there,
    I understand everything you said up there, but I do have a question to ask.
    From what I know, one of the reason why we use POST because we might not be able to fit all the data in the URL.
    So if we still have to put those data into the URL, then what can we do if we have a big size of data.

    Please advise me on that.

    Cheers,
    Brandon

  2. For more information about max size of HTTP POST you can find here

    http://www.google.com/search?q=http+post+max+size&ie=utf-8&oe=utf-8&aq=t&rls=org.mozilla:en-US:official&client=firefox-a

    I think making a HTTP POST of large data is exactly same as uploading large file. It will work in any circumstance and depend on configuration of your server. However we must consider how we can get the status of posting process (how many bytes was sent?) when posting lasts too long. I will make a small experience and hope that I can find out the answer.
    Regards.

  3. Hi there,
    An other thing I also wanna ask.
    Correct me if I am wrong, with POST method, normally we don’t need to reply on the querystring. For example, instead of calling the URI
    “http://localhost/StuSer/StudentService.svc/CreateStudent/” + txtName.Text + “/” + txtChair.Text + “/” + txtNote.Text;
    can we just call “http://localhost/StuSer/StudentService.svc/CreateStudent/ with the method is still POST.

    I don’t really like the idea of attaching data into the URL.
    Is it something lack in the Window Modile phone?
    I am pretty sure that we don’t need to put the data in the URL when calling POST method in normal web development.

    Hope what I said makes sense to you.

    Cheers,

  4. @Brandon:
    – First, this is a REST Service. Please read the definition above again and more information at the link I gave or http://en.wikipedia.org/wiki/REST. Data will be given in URI and processed according to HTTP methods. My example is bad because I create different URIs for each action but in principle man needs only one URI for all CRUD actions.
    – Second, I do not see any differences between putting data in URL and passing data to argument. Let’s see an example, we have a login service. http://www.example.com/login.php with arguments username and password. One would like to login to this service. There 2 ways to do it.
    1. URI=http://www.example.com/login.php?username=haha&password=hehe then HTTP POST
    2. URI=http://www.example.com/login.php then HTTP POST with arguments username=haha and password=hehe
    So are there any differences? No, if you use a HTTP Snipper, you will see both all of them are exactly same. Let’s look at HTTP protocol, you’ll understand more.
    – Third, in compare to normal service the URI is shorter and more secret.
    Normal: URI=http://www.example.com/login.php?username=haha&password=hehe
    REST: URI=http://www.example.com/login/haha/hehe

    Regards.

  5. Hi,
    Thanks for clearing it out.
    One last question, from the link you provided in your blog
    http://msdn.microsoft.com/en-us/library/dd203052.aspx

    I have found the way they declared the service using POST as below

    [WebInvoke(Method = “POST”, UriTemplate = “users/{username}/bookmarks”)]
    [OperationContract]
    void PostBookmark(string username, Bookmark newValue) {…}

    I realized that the newValue is an BookMark object.
    Can we do something like that in your example?
    Like

    [WebInvoke(Method = “POST”, UriTemplate = “student/{studentId}/student”)]
    [OperationContract]
    void PostBookmark(string studentId, Student newValue) {…}

    I tried but it doesn’t work for some reason.
    I am using it in developing an Mobile app.

    Hope you can check it out for me. Its even better if you can provide a source code example 🙂

    Much appreciated

  6. Hello Nice Article..
    Please Help Me to Find Out Solution
    I am Facing This Problem in My REST Service
    Any Idea?
    to this:

    [OperationContract]
    [WebGet( UriTemplate = “strCustomLabelCollection/{Name},{Type},{Id}” )]
    int CheckCustomLabelMaster(List strCustomLabelCollection);

    Is there a way to make the Name,Type,Id be a variable length list of parameters? So it could be
    Name1,name2.. …., namen? And end up with a service method such as:

    int CheckCustomLabelMaster(List strCustomLabelCollection);
    Or something along those lines?

Leave a Reply

Your email address will not be published. Required fields are marked *