I’ve spent the last couple weeks wrestling with WCF4 and Silverlight4.
Here is some code that does a GET/POST/PUT/DELETE with a Silverlight4 client.
The Restful WCF Service
[ServiceContract] public interface IInvoiceService { [WebGet(UriTemplate = "/invoices")] [OperationContract] List GetAllInvoices(); [WebGet(UriTemplate = "/invoices/{invoiceId}")] [OperationContract] Invoice GetInvoice(string invoiceId); [WebInvoke(UriTemplate = "/invoices/{invoiceId}", Method = "PUT")] [OperationContract] Invoice UpdateInvoice(string invoiceId, Invoice newInvoice); [WebInvoke(UriTemplate = "/invoices", Method = "POST")] [OperationContract] Invoice AddNewInvoice(Invoice newInvoice); [WebInvoke(UriTemplate = "/invoices/{invoiceId}", Method = "DELETE")] [OperationContract] void DeleteInvoice(string invoiceId); }
Here is the implementation:
public class InvoiceService : IInvoiceService { protected static List<Invoice> invoices = new List<Invoice> { new Invoice(1, "reciever1"), new Invoice(2, "reciever2"), new Invoice(3, "reciever3"), }; public List<Invoice> GetAllInvoices() { return invoices; } public Invoice GetInvoice(string invoiceId) { Invoice invoice = invoices.Find(x => x.Id == int.Parse(invoiceId)); if (invoice == null) { WebOperationContext ctx = WebOperationContext.Current; ctx.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; } return invoice; } public Invoice UpdateInvoice(string invoiceId, Invoice newInvoice) { Invoice current = invoices.Find(x => x.Id == int.Parse(invoiceId)); if (current == null) { WebOperationContext ctx = WebOperationContext.Current; ctx.OutgoingResponse.StatusCode = HttpStatusCode.NotFound; return null; } invoices.Remove(current); invoices.Add(newInvoice); return newInvoice; } public Invoice AddNewInvoice(Invoice newInvoice) { Debug.WriteLine("AddNewInvoice"); Invoice existingInvoice = invoices.Find(x => x.Id == newInvoice.Id); WebOperationContext ctx = WebOperationContext.Current; if (existingInvoice != null) { ctx.OutgoingResponse.StatusCode = HttpStatusCode.Conflict; return null; } invoices.Add(newInvoice); ctx.OutgoingResponse.StatusCode = HttpStatusCode.Created; ctx.OutgoingResponse.Location = PluginFactory.INSTANCE.InvoiceServiceUri() + newInvoice.Id; return new Invoice(newInvoice.Id, newInvoice.Receiver); } public void DeleteInvoice(string invoiceId) { var id = Convert.ToInt32(invoiceId); invoices = invoices.FindAll(invoice => invoice.Id != id); } }
The Silverlight Client
You have two options when consuming services on the client. You can use WebClient (which is easy but weak). Or you can use the more rich HttpWebRequest which you need to consume Status Codes. This example users the later. Here is the Silverlight client.
GET
private void GetClick(object sender, RoutedEventArgs e) { var request = (HttpWebRequest)WebRequest.Create(url + IdTextBox.Text); request.BeginGetResponse(GetCompleted, request); } private void GetCompleted(IAsyncResult ar) { // necessary for concurrency Dispatcher.BeginInvoke(delegate { try { var request = (HttpWebRequest)ar.AsyncState; var response = (HttpWebResponse)request.EndGetResponse(ar); using (var streamReader = new StreamReader(response.GetResponseStream())) { ParseComplex(response, streamReader); } } catch (WebException) { outputTextBlock.Text = "This id does not exist."; } }); }
POST
private void PostComplexClick(object sender, RoutedEventArgs e) { ClearTextBoxes(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl); request.Method = "POST"; request.ContentType = postContentType; request.BeginGetRequestStream(PostComplexRequestReady, request); } private void PostComplexRequestReady(IAsyncResult asyncResult) { HttpWebRequest request = asyncResult.AsyncState as HttpWebRequest; Stream postStream = request.EndGetRequestStream(asyncResult); Dispatcher.BeginInvoke(delegate { Invoice newInvoice = new Invoice(int.Parse(IdTextBox.Text), RandomReceiver()); byte[] byteData = Encoding.UTF8.GetBytes(newInvoice.AsXml()); postStream.Write(byteData, 0, byteData.Length); postStream.Flush(); postStream.Close(); request.BeginGetResponse(PostComplexResponseReady, request); }); } private void PostComplexResponseReady(IAsyncResult asyncResult) { Dispatcher.BeginInvoke(delegate { try { var request = asyncResult.AsyncState as HttpWebRequest; var response = (HttpWebResponse)request.EndGetResponse(asyncResult); using (var streamReader = new StreamReader(response.GetResponseStream())) { ParseComplex(response, streamReader); } } catch (WebException e) { dynamic exceptionResponse = e.Response; if (exceptionResponse.StatusCode == HttpStatusCode.Conflict) outputTextBlock.Text = "This user already exists."; else outputTextBlock.Text = e.Message; } }); }
PUT
private void PutClick(object sender, RoutedEventArgs e) { ClearTextBoxes(); HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + IdTextBox.Text); request.Method = "PUT"; request.ContentType = postContentType; request.BeginGetRequestStream(PostComplexRequestReady, request); // Note: PUT is very similar to POST - only difference is url }
DELETE
private void DeleteClick(object sender, RoutedEventArgs e) { ClearTextBoxes(); var request = (HttpWebRequest)WebRequest.Create(url + IdTextBox.Text); request.Method = "DELETE"; request.BeginGetResponse(GetCompleted, request); // Note: DELETE is very similar to GET }
Sean Feldman
Oct 31, 2010 @ 01:27:48
Hey,
Good that you found time to share it. This was a definitely interesting spiking.
I think it was WCF 4.0, but might be mistake on my end. I’ll take some time later to blog about how to go about testing this service and remove dependency on hard-coded sample data. Maybe you’ll find the time to link it all and put a series together, as you were mentioning before?
dynamic in the Wild - sfeldman.NET
Oct 31, 2010 @ 01:34:00
JR
Oct 31, 2010 @ 18:03:39
No you are right. I think it was 4.0. Updated.
dynamic in the Wild | RecklessDevelopment
Nov 08, 2010 @ 11:45:51
YongKuk Jeong
Nov 22, 2012 @ 07:27:45
I was developing SL RESTful WebService client program. So I was trying to use your code, but I don’t know what is “Parsecomplex” function. Could you explain more detail about this function?
Thankyou.