3

I've created a custom MessageHandler as such:

public class WebAPICustomMessageHandler : DelegatingHandler {

  protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
  //Parse QueryString
    NameValueCollection queryString = HttpUtility.ParseQueryString(request.RequestUri.Query);

    if (queryString != null) {
    //Find my token
      String token = queryString.Get("qsVariable");

      if (!String.IsNullOrWhiteSpace(token)) {
      //Remove token so it doesn't impact future handlers / controllers / etc.
        queryString.Remove("qsVariable");
        request.RequestUri.Query = queryString.ToString(); //How can we modify the querystring? apparently it's readonly?

      //Append token as custom header to the request
        request.Headers.Add("token", new String[] { token });
      }
    }

    HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

    return response;
  }

}

It appears that I can't directly change the QueryString, which is a bit odd as I thought that the entire point of custom message handlers in the Web API pipeline was to allow this exact sort of thing. The ability issue pre and post operations on request/response, including things like data scrubbing / injection etc.

I already know I can do what I want very easily utilizing OWIN (as I've already done it), but now I'm trying to do this without OWIN. Am I going to have to create an entirely new HttpRequestMessage in order to just change the QueryString? From the looks of it, I'll have to build a new Uri, then construct the HttpRequestMessage, then copy over each and every other piece from the original.

Is that the only way to do this? or is there a better way that I'm just not aware of?

  • Please note, that other routines later in the pipeline are setup to use a token found in the header of the request, but setting the header is not possible if the request came from a submission to an iframe, which is where the process above comes into place. The token is added to the querystring, then converted to a header to prevent changes to the rest of the pipeline.
Ben Ripley
  • 2,115
  • 21
  • 33
Xorcist
  • 3,129
  • 3
  • 21
  • 47

1 Answers1

1

You're correct, the query string is read-only. Just use a standard redirect with the substituted query string values.

public class WebAPICustomMessageHandler : DelegatingHandler {

  protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
    var query = HttpUtility.ParseQueryString(request.RequestUri.Query);
    var token = query["qsVariable"];

    // just 'short-circuit' if our token was not found...
    if (token == null) 
      return await base.SendAsync(request, cancellationToken);

    token = "newValue"; // modify your value here...
    query["token"] = token;

    // redirect with new query string...
    var response = request.CreateResponse(HttpStatusCode.Redirect);
    var uri = request.RequestUri;
    var ub = new UriBuilder(uri.Scheme,
      uri.Host,
      uri.Port,
      uri.AbsolutePath);
    ub.Query = query.ToString();
    response.Headers.Location = ub.Uri;
    return response;
  }
}

For interest sake, it is possible to modify the query string even though it is read-only but I would avoid this practice.

Community
  • 1
  • 1
Ben Ripley
  • 2,115
  • 21
  • 33
  • I think you might have misunderstood what I was trying to do. When a request is made through an iFrame (rather than an AJAX call) you can not append custom header information, which is normally how this token is handled. I want to grab any request with a token on the querystring and move it into the header before handing it off to the rest of the pipeline, but as stated, Web API won't let me actually change querysting. Sending a modified response back to the iFrame with a redirect won't really help me. The token needs to be removed from the querystring so it doesn't affect our OData setup. – Xorcist Sep 23 '15 at 14:29