Online Since 1995. Yep, that long.

Adventures in Windows 8: HTTP Post Helper WinRT Component

Tags: Adventures in Windows 8, Windows RT, HTTP, Cookie, HTTP302, Metro, Apps, JavaScript

Are you writing a Metro style app in JavaScript and dealing with a pesky HTTP 302 server response?

Are you using the WinJS.xhr to send an HTTP POST request and everything appears to work fine, but you don’t see any cookies come back from the server?

Then I may have your answer.

For more details on the actual mechanics of what’s going on, read my previous post on this topic.

In fact, you might want to read it now, as I’ll keep referring to it throughout this post.

But, if you’re impatient, the code below will help you mitigate this problem.

Brief Overview

Many sites follow a pattern where you send an HTTP Post request, the server sends a cookie along with an HTTP 302 response.

Here’s a screenshot from Fiddler detailing the action.

image

 

The problem is that WinJS.xhr will automatically follow the HTTP 302 response and make another request.  That second request will typically not contain the header data you’re looking for.

The Solution

To my knowledge, there’s no way to tell the WinJS.xhr not to automatically redirect.

The only way around this is to write a WinRT Component, use HTTPClient and expose the functionality to JavaScript.

I encountered this problem before.

As I was working on app #3, it came up again. Something tells me I’m going to see this issue again.

So, I decided to make the solution a little more generic.

Creating a WinRT Component

Basically, you’ll need to add a WinRT component to your Metro-style app For more info, read this post.

Here’s a quick recap:

Creating a WinRT component is easy enough in Visual Studio 2012. From your Metro style app solution, just click on File > Add > New Project.

image

Then this dialog will come up. Be sure to click on Windows Metro Style under Visual C#  (or whatever language you wish to work with), then click on Windows Runtime Component.

Name your component and then click OK.

image

The Component Code

Since the content of an HTTP 302 is usually contains a “Content Moved” message along with a link to the redirected URL, we usually only care about the HTTP header content from the response.

The HTTP response header contains HTTP cookie data as well as the redirect URL – basically everything we need.

There are two methods below: one public and the other private.

 

   1:  namespace HttpHelper
   2:  {
   3:      public sealed class Post
   4:      {
   5:          public IAsyncOperation<IDictionary<string, string>> PostToUriAsync(string targetUri, string content)
   6:          {
   7:              return Task.Run<IDictionary<string, string>>(async () =>
   8:              {
   9:                  var headers = await SendPostToUriAsync(targetUri, content);
  10:                  return headers;
  11:   
  12:              }).AsAsyncOperation();
  13:          }
  14:   
  15:          private async Task<IDictionary<string, string>> SendPostToUriAsync(string targetUri, string content)
  16:          {
  17:              HttpClientHandler handler = new HttpClientHandler();
  18:              handler.UseDefaultCredentials = true;
  19:              handler.AllowAutoRedirect = false;
  20:   
  21:              HttpClient client = new HttpClient(handler);
  22:   
  23:              HttpContent httpContent = new StringContent(content);
  24:              httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
  25:   
  26:              HttpResponseMessage response = await client.PostAsync(targetUri, httpContent);
  27:   
  28:              Dictionary<string, string> headers = new Dictionary<string, string>();
  29:   
  30:              foreach (var header in response.Headers)
  31:              {
  32:                  string headerValue = string.Empty;
  33:   
  34:                  if (header.Value.Count() == 1)
  35:                  {
  36:                      headerValue = header.Value.First();
  37:                  }
  38:                  else
  39:                  {
  40:                      StringBuilder stringValue = new StringBuilder();
  41:   
  42:                      foreach (var value in header.Value)
  43:                      {
  44:                          stringValue.Append(value);
  45:                          stringValue.Append("\n");
  46:                      }
  47:   
  48:                      headerValue = stringValue.ToString();
  49:                  }
  50:   
  51:                  headers.Add(header.Key, headerValue);
  52:              }
  53:   
  54:              return headers;
  55:          }
  56:      }
  57:  }

 

The Client JavaScript Code

Once you set up the appropriate reference in the JavaScript Metro-style app project.

   1:      function someFunction() {
   2:   
   3:          var httpPostContent = "Number=4&State=NY";
   4:          var poster = new HttpHelper.Post();
   5:   
   6:          poster.postToUriAsync(storeSelectTargetUri, httpPostContent).then(function (results) {
   7:   
   8:              // TODO: add your code here
   9:   
  10:          });
  11:      }

The Results

The postToUriAsync method returns a hash table of HTTP header keys and values.

The Cookie field contains a “\n” separated field of raw cookie values.

image

2 Comments

  • Rene said

    Thanks a lot for this, Frank!
    Just encountered such a situation, and this helped me a lot already. Wish I had discovered a few hours earlier, would've saved me a lot of headaches

  • frank said

    Thanks Rene!

    Keep checking back for more content.

    I've got a few more posts I'm working on at the moment.

Add a Comment