Looking back over the last 6 months of this series of articles, you’ve created wireless-efficient WCF REST + JSON Web Services in Azure to download data from SQL Azure tables to Windows Phone.  You’ve maintained in-memory collections of objects in your own local NoSQL object cache.  You’ve used LINQ to query those collections and bind results to various Silverlight UI elements.  You’ve even serialized those collections to Isolated Storage using memory-efficient JSON.  So what’s left to do?
Oh yeah, I guess you might want to know how to upload an object full to data back to a WCF Web Service in Azure.  In order to keep this article simple and to-the-point, I’m going to work with a basic Submarine object and show you how to fill it with data and upload it from a Windows Phone or Slate to a WCF REST + JSON Web Service.  Let’s take a look at this object:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace Models
{
[DataContract()]
public class Submarine
{
[DataMember()]
public int Id { get; set; }
[DataMember()]
public string Name { get; set; }
}
}
It includes just an integer data type called Id, and a string called Name.  As in previous articles before, its decorated with a [DataContract()] and two [DataMember()]s to allow .NET serialization to do its thing.  So the next thing we need to do is create and populate this Submarine object with data, serialize it as JSON, and send it on its way using WebClient.
Below is the method and its callback that accomplishes this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using Microsoft.Phone.Controls;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
private void AddSubmarine()
{
Uri uri = new Uri(“
http://127.0.0.1:81/SubService.svc/AddSubmarine”);
Models.Submarine submarine = new Models.Submarine() { Id = 3, Name = “Seawolf” };
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Models.Submarine));
MemoryStream mem = new MemoryStream();
ser.WriteObject(mem, submarine);
string data = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
WebClient webClient = new WebClient();
webClient.UploadStringCompleted += new UploadStringCompletedEventHandler(webClient _UploadStringCompleted);
webClient.Headers["Content-type"] = “application/json”;
webClient.Encoding = Encoding.UTF8;
webClient.UploadStringAsync(uri, “POST”, data);
}
void webClient_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
var x = e.Result;
}
As you can see above, I point the URI at a WCF Service called SubService.svc/AddSubmarine.  How RESTful.  Next, I create an instance of the Submarine object, give it an Id of 3 and the Name Seawolf.  I then use the same DataContractJsonSerializer I’ve been using in all the other articles to serialize the Submarine object to a JSON representation.  Using the MemoryStream, I write the JSON to a stream and then artfully turn it into a string.  Last but not least, I instantiate a new WebClient object, create an event handler for a callback, and upload the stringified Submarine object to the WCF Service.
So where did I upload the Submarine object to?
It takes two to Mango, so let’s take a look.  For starters, it goes without saying that every WCF Service starts with an Interface.  This one is called ISubService.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace DataSync
{
[ServiceContract]
public interface ISubService
{
[OperationContract]
[WebInvoke(UriTemplate = "/AddSubmarine", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, Method = "POST")]
bool AddSubmarine(Models.Submarine sub);
}
}
Unlike previous articles where I had you download data with WebGet, this time I’m using WebInvoke to denote that a PUT, POST, or DELETE HTTP Verb is being used with our REST service.  The UriTemplate gives you the RESTful /AddSubmarine, and I added the Method = “POST” for good measure.  Keep in mind that you’ll need the exact same Submarine class on the server that you had on your Windows Phone to make all this work.
Let’s see what we get when we Implement this Interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.Configuration;
using System.Xml.Serialization;
using System.IO;
namespace DataSync
{
public class SubService : ISubService
{
public SubService()
{

}

public bool AddSubmarine(Models.Submarine submarine)
{
try
{
if (submarine != null)
{
//Do something with your Deserialized .NET Submarine Object
//… = submarine.Id
//… = submarine.Name
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
}
}
Here we end up with SubService.svc with the simple AddSubmarine method where you pass in a Submarine object as a parameter.  What you do with this object, I’ll leave to you.  Some might be tempted to INSERT it into SQL Azure.  I’d prefer that you drop it into an Azure Queue and have a Worker Role do the INSERTing later so you can stay loosely-coupled.  Just in case you need a refresher on a REST-based Web.config file, here’s one below:
<?xml version=”1.0″?>
<configuration>
<!–  To collect diagnostic traces, uncomment the section below.
To persist the traces to storage, update the DiagnosticsConnectionString setting with your storage credentials.
To avoid performance degradation, remember to disable tracing on production deployments.
<system.diagnostics>
<sharedListeners>
<add name=”AzureLocalStorage” type=”DataSync.AzureLocalStorageTraceListener, DataSync”/>
</sharedListeners>
<sources>
<source name=”System.ServiceModel” switchValue=”Verbose, ActivityTracing”>
<listeners>
<add name=”AzureLocalStorage”/>
</listeners>
</source>
<source name=”System.ServiceModel.MessageLogging” switchValue=”Verbose”>
<listeners>
<add name=”AzureLocalStorage”/>
</listeners>
</source>
</sources>
</system.diagnostics> –>
<system.diagnostics>
<trace>
<listeners>
<add type=”Microsoft.WindowsAzure.Diagnostics.DiagnosticMonitorTraceListener, Microsoft.WindowsAzure.Diagnostics, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35″
name=”AzureDiagnostics”>
<filter type=”” />
</add>
</listeners>
</trace>
</system.diagnostics>
<system.web>
<compilation debug=”true” targetFramework=”4.0″ />
</system.web>
<!–Add Connection Strings–>
<connectionStrings>

</connectionStrings>

<system.serviceModel>
<behaviors>
<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=”false”/>
</behavior>
</serviceBehaviors>
<!–Add REST Endpoint Behavior–>
<endpointBehaviors>
<behavior name=”REST”>
<webHttp />
</behavior>
</endpointBehaviors>
</behaviors>
<!–Add Service with webHttpBinding–>
<services>
<service name=”DataSync.SubService”>
<endpoint address=”” behaviorConfiguration=”REST” binding=”webHttpBinding”
contract=”DataSync.ISubService” />
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled=”true” multipleSiteBindingsEnabled=”true” />
<!–<serviceHostingEnvironment multipleSiteBindingsEnabled=”true” />–>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests=”true”/>
</system.webServer>
</configuration>
This Web.Config gives you the webHttpBinding you’re looking for to do a REST service.  I even left you a spot to add your own database or Azure storage connection strings.
This article wraps up the Windows Phone 7 Line of Business App Dev series that I’ve been delivering to you since last September.  Who knew I would make fun of OData or have you create your own NoSQL database to run on your phone along the way?  I think I actually wrote the first article in this series from a hotel room in Nantes, France.
But have no fear, this isn’t the end.
In preparation for Tech Ed 2010 North America coming up on May 16th in Atlanta, I’ve been building the next-gen, super-fast, super-scalable Azure architecture designed for mobile devices roaming on wireless data networks.  I’ve spent the last decade building the world’s largest and most scalable mobile infrastructures for Microsoft’s wonderful global customers.  Now it’s time to make the jump from supporting enterprise-level scalability to the much bigger consumer-level scalability.
Yes, I’m talking millions of devices.
No, you won’t have to recreate Facebook’s servers, NoSQL, Memcache, or Hadoop infrastructure to make it happen.  I’m going to show you how to make it happen with Azure in just two weeks so I’m looking forward to seeing everyone in Atlanta in two weeks.
Keep coding,
Rob
Tagged on:                                                                                                                                                     

6 thoughts on “Windows Phone 7 Line of Business App Dev :: Uploading Data back to Azure

  • Pingback: Dew Drop – May 4, 2011 | Alvin Ashcraft's Morning Dew

  • Pingback: Biztalk Musings | WP7 App Data to Azure

  • May 19, 2011 at 5:31 am
    Permalink

    First off, thanks for the great set of articles. VERY useful!! 

    Having a problem though. I am trying to add ASP.NET authentication to the sample and that requires adding aspNetCompatibilityEnabled=”true” (I see you also have that set in the sample Web.config above). The problem is that then my WebClient calls return NotFound. If I remove that flag, then they start working again. It seems I’m missing something. Any clues?

     

    Reply
  • May 21, 2011 at 11:34 am
    Permalink

    I found the problem. If you set aspNetCompatibilityEnabled=”true”, then you need to add the AspNetCompatibilityRequirements attribute to the service classes.

    Reply
    • June 13, 2011 at 2:51 pm
      Permalink

      How are things working out for you?

      Reply

Leave a Reply