RichK RichK - 1 month ago 15
C# Question

Accessing a secure Web API from a WPF client

I have a Web API project which is configured for CORS and implements [Authorize] on one of the APIControllers. I can access the API from the WPF client when I remove the [Authorize] but when it's in place the call seems to get lost. This is what I have setup to request a token.

In the WPF code behind

internal void RefreshRecentFilesList()
{
//Get the token
var token = GetAPIToken(email, password, "http://localhost:50006").Result;
MessageBox.Show(token);
}

private static async Task<string> GetAPIToken(string userName, string password, string apiBaseUri)
{
using (var client = new HttpClient())
{
//setup client
client.BaseAddress = new Uri(apiBaseUri);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token.AccessToken);

//setup login data
var formContent = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("grant_type", "password"),
new KeyValuePair<string, string>("username", userName),
new KeyValuePair<string, string>("password", password),
});

//send request
HttpResponseMessage responseMessage = await client.PostAsync("/Token", formContent);

//get access token from response body
var responseJson = await responseMessage.Content.ReadAsStringAsync();
var jObject = JObject.Parse(responseJson);
return jObject.GetValue("access_token").ToString();
}
}


In the Web API project
WebAPIConfig.cs

//Enable CORS
var cors = new EnableCorsAttribute("*", "*", "GET");
config.EnableCors(cors);


In the API controller

[HttpGet]
//[Authorize]
public List<FileInfo> GetFileTypes()
{
List<FileInfo> fileInfos = new List<FileInfo>();
...


In the StartAuth.cs

public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
AllowInsecureHttp = true
};

// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);


When I run the WPF and step through the code it's getting to the send request line and then just hangs.

Can anyone point me in the right direction please?

Many thanks

Answer

I think the primary candidate for your issue is this line:

var token = GetAPIToken(email, password, "http://localhost:50006").Result;

You are calling an async method and then you are waiting for its result synchronously: this will lead to deadlocks. Never do that.

Instead, turn your method (and you entire call stack) asynchronous. If you are inside WPF you are almost certainly calling this method from some kind of event handler callback. Those callbacks supports async (even if they have to return void).

Change your code to something similar to this and then try again (assuming Form_Load is an event handler callback):

private async void Form_Load(object sender, EventArgs e)
{
    await RefreshRecentFilesList();
}

internal async Task RefreshRecentFilesList()
{
    //Get the token
    var token = await GetAPIToken(email, password, "http://localhost:50006");
    MessageBox.Show(token);
}

References:
Why does this async action hang?
How to call asynchronous method from synchronous method in C#?