I use custom HttpClientHandler to authorize test if it is not authorized. Windows Store Unit Test App project type is used
using Microsoft.WindowsAzure.MobileServices;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Windows.Security.Credentials;
using Windows.UI.Popups;
using XperiAndri.Efficiency.Common.Http.Handlers;
namespace XperiAndri.Efficiency.Common.Tests.Online
{
public class AuthenticationHandler : DelegatingHandler
{
private const string user = "";
private const string password = "";
private const string MobileServiceAuthenticationTokenHeader = "X-ZUMO-AUTH";
private readonly PasswordVault vault = new PasswordVault();
public IMobileServiceClient Client { get; set; }
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var headers = request.Headers;
PasswordCredential credential = FindCredential();
if (credential != null)
{
Client.CurrentUser = new MobileServiceUser(user) { MobileServiceAuthenticationToken = credential.Password };
headers.Remove(MobileServiceAuthenticationTokenHeader);
credential.RetrievePassword();
headers.Add(MobileServiceAuthenticationTokenHeader, credential.Password);
response = await base.SendAsync(request, cancellationToken);
}
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
JObject content = new JObject { { "user", user }, { "password", password } };
var result = await Client.InvokeApiAsync("UnitTestLogin", content, HttpMethod.Post, null);
string token = result["token"].Value<string>();
if (Client.CurrentUser != null)
Client.CurrentUser.MobileServiceAuthenticationToken = token;
else
Client.CurrentUser = new MobileServiceUser(user) { MobileServiceAuthenticationToken = token };
headers.Remove(MobileServiceAuthenticationTokenHeader);
headers.Add(MobileServiceAuthenticationTokenHeader, token); // After execution of this line cancellationToken.IsCancellationRequested changes to true
// try again!
response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode != HttpStatusCode.Unauthorized)
{
if (credential != null)
credential.Password = token;
else
{
credential = new PasswordCredential(Client.ApplicationUri.ToString(), user, token);
vault.Add(credential);
}
}
}
}
return response;
}
private PasswordCredential FindCredential()
{
try
{
return vault.FindAllByResource(Client.ApplicationUri.ToString()).FirstOrDefault();
}
catch
{
return null;
}
}
}
}
Look at the comment at the line
headers.Add(MobileServiceAuthenticationTokenHeader, token);
the second time it is executed.
Can somebody explain why does it happened? Why request becomes cancelled?
You're trying to add header to request after actually receiving response (since you already awaited
SendAsync
) which logically is not possible and causes cancellation of original request.