4

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

RaKer
  • 279
  • 1
  • 5
  • 18

2 Answers2

4

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#?

Community
  • 1
  • 1
Federico Dipuma
  • 17,655
  • 4
  • 39
  • 56
  • Thank you for your help, it was the mix of sync and async calls that was causing a deadlock. I reworked my code based on your suggestion and I now have a fully functioning WPF client calling secure Web API methods. – RaKer May 26 '16 at 08:57
  • @RichK You are welcome, but please remember to always up vote and/or mark as selected the answer if it solved your problem here at stackoverflow – Federico Dipuma May 27 '16 at 06:42
  • I've marked the answer as solved. I can't up vote yet, I need more reputation points :-( – RaKer May 28 '16 at 18:14
0

complementary of Federico Dipuma solutions is to call Form_Load from constructor using

this.Loaded += new RoutedEventHandler(Form_Load);
Mehdi Benkirane
  • 437
  • 4
  • 7
  • What should this do ? – Felix D. Nov 03 '16 at 09:38
  • if you a window and "code behind" class, if you have this function without being "called", instructions would not be executed. the code above will added to routed event and be executed once page is fully loaded – Mehdi Benkirane Nov 03 '16 at 09:46
  • Sorry I still don't get it .. Since The accepted answer is correct I cannot see this to be any helpful .. #NoOffense – Felix D. Nov 03 '16 at 09:49
  • The accepted answer is correct, this is complementary as i have mentioned in my answer, if you don t know what is a constructor or how to invoke function evidently you won t see the use of it – Mehdi Benkirane Nov 03 '16 at 12:45
  • I cannt see the use of ANY constructor in the Question. That't what confuses me. It is never mentiones that his function is triggered by any FormEvents. Maybe you should add some more detailes to your answer since just sayin its complementairy while not talking about advantages/disadvantages of your approach its not even useful #StillNoOffense – Felix D. Nov 03 '16 at 12:49
  • The `Form_Load` handler is created automatically when you click anywhere clear on the Window's surface. It has always been like this since the first Windows Forms and is still like this in WPF. I am dumbstruck that you guys aren't aware of this, and yes, @MehdiBenkirane is correct, if you do it the non-lazy way, you do have to wire up the handler yourself. It's a crying shame on anyone else in this comment thread that he was down-voted. Go back to school, kids. – ProfK Nov 09 '16 at 16:51