Consuming the Data in the Windows Phone 7 Client Application

0
118

The mobile client application uses the methods exposed by the Surveys service to send and receive survey data.

The following code example shows the ISurveysServiceClient interface that defines the set of asynchronous WCF REST calls that the mobile client application can make.

C#
public interface ISurveysServiceClient
{
IObservable<IEnumerable<SurveyTemplate>>
GetNewSurveys(string lastSyncDate);
IObservable<Unit>
SaveSurveyAnswers(IEnumerable<SurveyAnswer> surveyAnswers);
}

The SurveysServiceClient class implements this interface, and the following code example shows the GetNewSurveys method that sends the request to the service and returns the observable list of surveys to the application. This method makes the asynchronous web request by using the GetJson extension method from the Http WebRequestExtensions class, converts the returned data transfer objects to SurveyTemplate objects, and then returns an observable sequence of SurveyTemplate objects.

C#
public IObservable<IEnumerable<SurveyTemplate>>
GetNewSurveys(string lastSyncDate)
{
var surveysPath = string.Format(CultureInfo.InvariantCulture,
“Surveys?lastSyncUtcDate={0}”, lastSyncDate);
var uri = new Uri(this.serviceUri, surveysPath);
return
HttpClient
.RequestTo(uri, this.settingsStore.UserName,
this.settingsStore.Password)
.GetJson<IEnumerable<SurveyDto>>()
.Select(ToSurveyTemplate);
}

 

Note: For more information about the HttpClient class that makes the asynchronous web request, see the section, “Registering for Notifications,” earlier in this chapter; it describes the HttpClient and HttpWebRequestExtensions classes.

To save completed survey answers to the Surveys service, the client must first save any image and sound clip answers. It uploads each media answer in a separate request, and then it includes the URL that points to the BLOB that contains the media when the client uploads the complete set of answers for a survey. It would be possible to upload the survey answers and the media in a single request, but this may require a large request that exceeds the maximum upload size configured in the service. By uploading all the media items first, the worst that can happen if there is a failure is that there are orphaned media items in Windows Azure storage.

The following code example shows the first part of the Save AndUpdateMediaAnswers method that creates a list of answers that contain media.

C#
var mediaAnswers =
from surveyAnswer in surveyAnswersDto
from answer in surveyAnswer.QuestionAnswers
where
answer.Answer != null &&
(answer.QuestionType ==
Enum.GetName(typeof(QuestionType), QuestionType.Picture) ||
answer.QuestionType ==
Enum.GetName(typeof(QuestionType), QuestionType.Voice))
select answer;

The method then iterates over this list and asynchronously creates HTTP requests to post each media item to the Tailspin Surveys service.

C#
foreach (var answer in mediaAnswers)
{
var mediaAnswerPath = string.Format(
CultureInfo.InvariantCulture,
“MediaAnswer?type={0}”,
answer.QuestionType);
var mediaAnswerUri = new Uri(this.serviceUri, mediaAnswerPath);
byte[] mediaFile = GetFile(answer.Answer);
var request = HttpClient.RequestTo(mediaAnswerUri,
this.settingsStore.UserName, this.settingsStore.Password);
request.Method = “POST”;
request.Accept = “application/json”;

}

The method then, asynchronously, needs to send each of these requests and retrieve the response to each request in order to extract the URL that points to the BLOB where the service saved the media item. It must then assign the returned URLs to the Answer property of the correct QuestionAnswerDto data transfer object. The following code example shows how the SaveAndUpdateMediaAnswers method sends the media answers to the Tailspin Surveys service asynchronously. The code example shows how this operation is broken down into the following steps:

  1. The method first makes an asynchronous call to access the HTTP request stream as an observable object.
  2. The method writes the media item to the request stream and then makes an asynchronous call to access the HTTP response stream.
  3. It reads the URL of the saved media item from the response stream and sets the Answer property of the Question
    AnswerDto object.
  4. The ForkJoin method makes sure that the media answers are uploaded in parallel, and after all the media answers are uploaded, the method returns an IObservable<Unit> object.

C#
var mediaAnswerObservables = new List<IObservable<Unit>>();
foreach (var answer in mediaAnswers)
{

QuestionAnswerDto answerCopy = answer;
var saveFileAndUpdateAnswerObservable =
Observable
.FromAsyncPattern<Stream>(request.BeginGetRequestStream,
request.EndGetRequestStream)()
.SelectMany(
requestStream =>
{
using (requestStream)
{
requestStream.Write(mediaFile, 0, mediaFile.Length);
requestStream.Close();
}
return
Observable.FromAsyncPattern<WebResponse>(
request.BeginGetResponse, request.EndGetResponse)();
},
(requestStream, webResponse) =>
{
using (var responseStream =
webResponse.GetResponseStream())
{
var responseSerializer = new
DataContractJsonSerializer(typeof(string));
answerCopy.Answer =
(string)responseSerializer.ReadObject(responseStream);
}
return new Unit();
});
mediaAnswerObservables.Add(saveFileAndUpdateAnswerObservable);
}
return mediaAnswerObservables.ForkJoin().Select(u => new Unit());

The following code example shows how the mobile client uploads completed survey answers. It first creates the data transfer objects, then it uploads any media answers using the SaveAndUpdateMedia Answers method described earlier, and finally, it uploads the Survey AnswerDto object using the HttpClient class. The SelectMany method here makes sure that all the media answers are uploaded before the SurveyAnswerDto object.

C#
public IObservable<Unit>
SaveSurveyAnswers(IEnumerable<SurveyAnswer> surveyAnswers)
{
var surveyAnswersDto = ToSurveyAnswersDto(surveyAnswers);
var saveAndUpdateMediaAnswersObservable =
this.SaveAndUpdateMediaAnswers(surveyAnswersDto);
var uri = new Uri(this.serviceUri, “SurveyAnswers”);
var saveSurveyAnswerObservable =
HttpClient
.RequestTo(uri, this.settingsStore.UserName,
this.settingsStore.Password)
.PostJson(surveyAnswersDto);
return saveAndUpdateMediaAnswersObservable.SelectMany(
u => saveSurveyAnswerObservable);
}

Both the GetNewSurveys and SaveSurveyAnswer methods are called from the SurveysSynchronizationService class that is responsible for coordinating which surveys should be downloaded and which survey answers should be uploaded.