×
Namespaces

Variants
Actions
Revision as of 04:27, 10 April 2013 by hamishwillee (Talk | contribs)

Creating and using a hosted server for backing up Windows Phone app data

From Nokia Developer Wiki
Jump to: navigation, search

This article explains how to creating and using a hosted server for backing up Windows Phone app data.

WP Metro Icon File.png
WP Metro Icon Web.png
SignpostIcon XAML 40.png
SignpostIcon WP7 70px.png
Article Metadata
Code ExampleTested with
SDK: Windows Phone 7.1
Devices(s): Any Windows Phones
Compatibility
Platform(s): Windows Phone
Windows Phone 7.5
Article
Keywords: file, server, web service
Created: ArchieCoder (13 Sep 2012)
Last edited: hamishwillee (10 Apr 2013)

Contents

Introduction

There are some use cases where it makes sense to store your application data on a server (for example to backup data so you can maintain access if you switch devices). A common solution for backup is to use SkyDrive, but this creates strange folders on the user's SkyDrive account. Personally, I find it more professional to save the data to a private cloud or server.

This article provides a step by step guide on how to create a Windows Communication Foundation (WCF) backup service for your Windows Phone applications hosted on a cheap hosting server like godaddy.com (at time of writing, around $5/month).

Windows Communication Foundation is a part of the .NET Framework that provides a unified programming model for rapidly building service-oriented applications that communicate across the web in a familiar way.

The article covers both main parts of the backup scenario:

  • Implementing the service on your server.
  • Implementing the client code to send your data.


Implementing the service on your server

  1. Let’s start with the hardest part. After you find a hosting server that supports the framework .NET 4.0, you create the WCF Service Application:
    AddNewProject.png
  2. Rename the file IService1.cs to IFileUploader.cs
  3. Replace the content of the IFileUploader.cs with:
  4. using System.Runtime.Serialization;
    using System.ServiceModel;
     
    namespace FileUploadService
    {
    [ServiceContract]
    public interface IFileUploader
    {
    // Returns null when there is no error, otherwise it is the exception message.
    [OperationContract]
    string Upload(UploadFile uploadFile);
    }
     
    [DataContract]
    public class UploadFile
    {
    // Don't forget to set the variable FileUploadDirectoryWithReadWritePermission in your Web.config and set read/write permission in your web hosting.
    // RelativeDirectory should be in the form as /Path1/Path2/ or null for the root directory.
    [DataMember]
    public string RelativeDirectory { get; set; }
     
    [DataMember]
    public string FileName { get; set; }
     
    [DataMember]
    public byte[] Content { get; set; }
    }
    }
    This interface contains only the Upload() method. The Upload needs a UploadFile which contains only 3 properties: RelativeDirectory, FileName and Content.
  5. Rename the file Service1.svc to FileUploader.svc.
  6. Replace the content of FileUploader.svc with:
    using System;
    using System.Configuration;
    using System.IO;
    using System.Web.Hosting;
     
    namespace FileUploadService
    {
    public class FileUploader : IFileUploader
    {
    #region IFileUploader Members
     
    public string Upload(UploadFile uploadFile)
    {
    string message = null;
     
    try
    {
    string path = HostingEnvironment.MapPath(string.Format("~/{0}", ConfigurationManager.AppSettings["FileUploadDirectoryWithReadWritePermission"]));
     
    if (path != null)
    {
    if (uploadFile.RelativeDirectory != null && uploadFile.RelativeDirectory.StartsWith("/"))
    {
    path = string.Concat(path, uploadFile.RelativeDirectory);
    }
     
    if (!Directory.Exists(path))
    {
    Directory.CreateDirectory(path);
    }
     
    if (!string.IsNullOrEmpty(uploadFile.FileName))
    {
    using (FileStream fileStream = File.Open(Path.Combine(path, uploadFile.FileName), FileMode.Create))
    {
    using (var binaryWriter = new BinaryWriter(fileStream))
    {
    binaryWriter.Write(uploadFile.Content);
    }
    }
    }
    }
    }
    catch (Exception exception)
    {
    message = exception.Message;
    }
     
    return message;
    }
     
    #endregion
    }
    }
  7. Replace the content of the Web.config with:
    <?xml version="1.0"?>
     
    <configuration>
     
    <appSettings>
    <add key="FileUploadDirectoryWithReadWritePermission" value="/backup/" />
    </appSettings>
     
    <system.web>
    <compilation debug="true" targetFramework="4.0" />
    <customErrors mode="Off" />
    </system.web>
     
    <system.serviceModel>
     
    <behaviors>
    <serviceBehaviors>
    <behavior name="FileUploadBehavior">
    <serviceMetadata httpGetEnabled="true" />
    </behavior>
    </serviceBehaviors>
    </behaviors>
     
    <services>
    <service behaviorConfiguration="FileUploadBehavior" name="FileUploadService.FileUploader">
    <endpoint address="" name="basicHttpStream" binding="basicHttpBinding"
    bindingConfiguration="httpLargeMessageStream" contract="FileUploadService.IFileUploader" />
    <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
    </service>
    </services>
     
    <bindings>
    <basicHttpBinding>
    <binding receiveTimeout="00:10:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00"
    name="httpLargeMessageStream" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
    <readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
    </binding>
    </basicHttpBinding>
    </bindings>
     
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
     
    </system.serviceModel>
     
    <system.webServer>
    <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
     
    </configuration>
    This file has two important sections:
    • The parameter FileUploadDirectoryWithReadWritePermission is used by the file FileUploader.svc and it will be used in your public folder later.
      <appSettings>
      <add key="FileUploadDirectoryWithReadWritePermission" value="/backup/" />
      </appSettings>
    • The section about the length of the service parameters: You don’t need to understand everything here. It just works as is. If you are curious, I invite you to read the documentation on MSDN.
      <bindings>
      <basicHttpBinding>
      <binding receiveTimeout="00:10:00" sendTimeout="00:10:00" openTimeout="00:10:00" closeTimeout="00:10:00"
      name="httpLargeMessageStream" maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
      <readerQuotas maxArrayLength="2147483647" maxStringContentLength="2147483647" />
      </binding>
      </basicHttpBinding>
      </bindings>
  8. The service is ready to be published. Right-click on the FileUploadService project and choose Publish. Depending on your web hosting service, you need to set the info.
    Publish.png
  9. The trickiest part is to configure the application settings for the WCF service in the hosting service. In GoDaddy, it’s in the IIS Management in the Tools section. You need to check Anonymous Access and Set Application Root.
    The upm\servertest points to http://www.ultimatepokermanager.com/upm/servertest
    GoDaddy.png
  10. To check if your service is running, open your browser and put the address of the web service. With my web service, the address is: http://www.ultimatepokermanager.com/upm/servertest/FileUploader.svc


If you see something like the following image, you’re good to go!

Service.png


Implementing the client code to send your data

This section shows how to create a simple application that sends a string into a file in the server.

Client.png

  1. Create a Windows Phone Application in the normal way
  2. The WCF service client FileUploader needs to be added to the project. Right-click on the Windows Phone project and click on Add Service Reference.
    AddService.png
  3. Replace the content of the MainPage.xaml with:
    <phone:PhoneApplicationPage x:Class="SendFileApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignWidth="480"
    d:DesignHeight="800"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}">
     
    <Grid>
     
    <Grid.RowDefinitions>
    <RowDefinition Height="Auto" />
    <RowDefinition Height="*" />
    </Grid.RowDefinitions>
     
    <StackPanel Margin="12,17,0,28">
     
    <TextBlock Text="SEND FILE"
    Style="{StaticResource PhoneTextNormalStyle}" />
     
    <TextBlock Text="dashboard"
    Margin="9,-7,0,0"
    Style="{StaticResource PhoneTextTitle1Style}" />
     
    </StackPanel>
     
    <StackPanel Grid.Row="1"
    Margin="12,0,12,0">
     
    <TextBlock Margin="12,0,0,0"
    Text="Content" />
     
    <TextBox Text="abcdefg"
    x:Name="textBoxContent" />
     
    <TextBlock Margin="12,0,0,0"
    Text="File name" />
     
    <TextBox Text="Sample.txt"
    x:Name="textBoxFileName" />
     
    <Button Content="Send File"
    Click="ButtonSendFile" />
     
    <Button Content="Download File"
    Click="ButtonDownloadFile"
    IsEnabled="False"
    x:Name="buttonDownloadFile"/>
     
    </StackPanel>
     
    </Grid>
     
    </phone:PhoneApplicationPage>
    This content uses only standard controls.
  4. Replace the content of MainPage.xaml.cs with:
    using System;
    using System.Net;
    using System.Text;
    using System.Windows;
    using SendFileApp.FileUploader;
     
    namespace SendFileApp
    {
    public partial class MainPage
    {
    #region Constants
     
    // For this sample, the uploaded file can be access from my public folder
    private const string PublicServer = "http://www.ultimatepokermanager.com/upm/ServerTest/backup";
     
    #endregion
     
    #region Fields
     
    private string _directory;
     
    #endregion
     
    #region Constructor
     
    public MainPage()
    {
    InitializeComponent();
    }
     
    #endregion
     
    #region Event Handlers
     
    private void ButtonSendFile(object sender, RoutedEventArgs e)
    {
    byte[] content = Encoding.UTF8.GetBytes(textBoxContent.Text);
    _directory = Guid.NewGuid().ToString();
     
    FileUploaderClient fileUploaderClient = new FileUploaderClient();
    fileUploaderClient.UploadCompleted += UploadCompleted;
     
    fileUploaderClient.UploadAsync(new UploadFile { RelativeDirectory = string.Format("/{0}", _directory), FileName = textBoxFileName.Text, Content = content });
    }
     
    private void UploadCompleted(object sender, UploadCompletedEventArgs uploadCompletedEventArgs)
    {
    buttonDownloadFile.IsEnabled = true;
     
    if (uploadCompletedEventArgs.Result == null)
    {
    MessageBox.Show("The file has been successfully uploaded.", "Success!", MessageBoxButton.OK);
    }
    else
    {
    MessageBox.Show(string.Format("An error occured:\n\n{0}", uploadCompletedEventArgs.Result), "Error", MessageBoxButton.OK);
    }
    }
     
    private void ButtonDownloadFile(object sender, RoutedEventArgs e)
    {
    WebClient webClient = new WebClient();
    webClient.DownloadStringCompleted += WebClientDownloadStringCompleted;
     
    webClient.DownloadStringAsync(new Uri(string.Format("{0}/{1}/{2}", PublicServer, _directory, textBoxFileName.Text)));
    }
     
    private void WebClientDownloadStringCompleted(object sender, DownloadStringCompletedEventArgs downloadStringCompletedEventArgs)
    {
    if (downloadStringCompletedEventArgs.Error == null)
    {
    MessageBox.Show(string.Format("The content of your file is:\n\n{0}", downloadStringCompletedEventArgs.Result), "Success!", MessageBoxButton.OK);
    }
    else
    {
    MessageBox.Show(string.Format("An error occured:\n{0}", downloadStringCompletedEventArgs.Error), "Error", MessageBoxButton.OK);
    }
    }
     
    #endregion
    }
    }


The interesting part in the previous code is:

private void ButtonSendFile(object sender, RoutedEventArgs e)
{
byte[] content = Encoding.UTF8.GetBytes(textBoxContent.Text);
_directory = Guid.NewGuid().ToString();
 
FileUploaderClient fileUploaderClient = new FileUploaderClient();
fileUploaderClient.UploadCompleted += UploadCompleted;
 
fileUploaderClient.UploadAsync(new UploadFile { RelativeDirectory = string.Format("/{0}", _directory), FileName = textBoxFileName.Text, Content = content });
}

The usage of the FileUploaderClient is really simple:

  • Create the instance FileUploaderClient.
  • Listen to the UploadCompleted event.
  • Upload the file asynchronously.

Please note that the UploadFile needs the following properties RelativeDirectory (which starts with a “/”), a FileName and the Content in an array of bytes.

An example of an uploaded file address is: http://www.ultimatepokermanager.com/upm/ServerTest/backup/a5a8ae0b-50f0-4d16-90da-e83d6e1d30a3/Sample.txt. You can see the backup directory previously set in the Web.config file.

In the sample, I've generated a GUID for the directory name. Also, the uploaded files are public as long as the user (or the application) knows about the directory name and the file name. If you want to add a layer of privacy, you just have to implement a DownloadFile method into your service. It should not be difficult if you read the code of the Upload method.

I guarantee you that you’ll be happy to see when your web service is working!

References

What was demonstrated in this WIKI was a little part of what you can do with WCF. It permits to create an application on a server where you can do whatever you want with the data (not just for backing up files). You can calculate statistics, you can generate contents, you can add authentication to access a web service and so on.

If you want to know more about WCF, I suggest the following links:

Downloads

Version Hint

Windows Phone: [[Category:Windows Phone]]
[[Category:Windows Phone 7.5]]
[[Category:Windows Phone 8]]

Nokia Asha: [[Category:Nokia Asha]]
[[Category:Nokia Asha Platform 1.0]]

Series 40: [[Category:Series 40]]
[[Category:Series 40 1st Edition]] [[Category:Series 40 2nd Edition]]
[[Category:Series 40 3rd Edition (initial release)]] [[Category:Series 40 3rd Edition FP1]] [[Category:Series 40 3rd Edition FP2]]
[[Category:Series 40 5th Edition (initial release)]] [[Category:Series 40 5th Edition FP1]]
[[Category:Series 40 6th Edition (initial release)]] [[Category:Series 40 6th Edition FP1]] [[Category:Series 40 Developer Platform 1.0]] [[Category:Series 40 Developer Platform 1.1]] [[Category:Series 40 Developer Platform 2.0]]

Symbian: [[Category:Symbian]]
[[Category:S60 1st Edition]] [[Category:S60 2nd Edition (initial release)]] [[Category:S60 2nd Edition FP1]] [[Category:S60 2nd Edition FP2]] [[Category:S60 2nd Edition FP3]]
[[Category:S60 3rd Edition (initial release)]] [[Category:S60 3rd Edition FP1]] [[Category:S60 3rd Edition FP2]]
[[Category:S60 5th Edition]]
[[Category:Symbian^3]] [[Category:Symbian Anna]] [[Category:Nokia Belle]]

131 page views in the last 30 days.
×