2

I have a DelegatingHandler in my web API for authentification (HMAC).

I would like to add a GET parameter to the request to return the user's id to my controller.

In my handler, I tried adding it like so:

public class SecurityHandler : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        string apikey = request.Headers.GetValues(AuthConfig.ApiKeyHeader).First();
        UserDTO user = UserRepo.GetUser(apikey);
        if (user == null)
        {
            return SendResponseText("Invalid API key");
        }

        // Validate signature ...

        // Add user Id to the URI
        request.RequestUri = new Uri(request.RequestUri.OriginalString + "&UserId=" + user.Id);
        return base.SendAsync(request, cancellationToken);
    }
}

In my controller, I'm able to get the newly added parameter from the request uri, however the parameter binding is not working

public class MyModel
{
    public int UserId { get; set; }
    ...
}

public string Get([FromUri] MyModel model)
{
    // model.UserId has not been set (= 0)
    // Request.RequestUri contains "&UserId=5"
}

Update

I'm guessing the binding is being done from the Params in the HttpContext. I tried something like this, but Params collection is readonly.

var newContext = request.Properties["MS_HttpContext"] as HttpContextWrapper;
newContext.Request.Params.Add("UserId", "8");
request.Properties.Remove("MS_HttpContext");
request.Properties.Add("MS_HttpContext", newContext);
3
  • If UserId is your first parameter, it should has ? instead of & request.RequestUri = new Uri(request.RequestUri.OriginalString + "?UserId=5"; Commented Dec 1, 2014 at 10:40
  • It is not my first parameter Commented Dec 1, 2014 at 10:50
  • It seems that you did not check my last update that I made more than 8 hours ago Commented Dec 3, 2014 at 13:36

2 Answers 2

5
+50

I have tried at my side and it working.

Here is my sample url.

http://localhost:50382/api/values?UserId=10

Here is controller action.

public class ValueController : ApiController
{
    public IEnumerable<string> Get([FromUri]Model my)
            {
                return new string[] { "value1", "value2" , my.UserId.ToString() };
            }
}

As per your comment here I created delegate handler.

  public class MyMessageHandler : DelegatingHandler
  {
    protected override Task<HttpResponseMessage> SendAsync(
            HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var myTempObj = new { id = 20 };
      /* You have to check this and remove this key. If key present that FromUri use cached properties*/
        if (request.Properties.ContainsKey("MS_QueryNameValuePairs"))
        {
            request.Properties.Remove("MS_QueryNameValuePairs");                
        }

        // Now prepare or update uri over here. It will surely work now.
            if (!string.IsNullOrEmpty(request.RequestUri.Query) && request.RequestUri.Query.Contains('?'))
            {
                request.RequestUri = new Uri(request.RequestUri + "&UserID=" + myTempObj.id);
            }
            else
            {
                request.RequestUri = new Uri(request.RequestUri + "?UserID=" + myTempObj.id);
            }    

        return base.SendAsync(request, cancellationToken);
    }
}

It is work as expected.

If your original request contain userid then it get duplicated and it will not work. It return 0.

I also have doubt that you are using request.RequestUri.OriginalString. Just try to use request.RequestUri. It might possible that OriginalString has encoded value.

Sign up to request clarification or add additional context in comments.

7 Comments

In my case I want to add a new parameter to the current request in my delegating handler.
So once request comes you modify RequestUrl in your custom delegate handler. Is this you are doing ?
Your example is similar to mine, tried it anyway but it doesn't not work. Did you actually get this to work ? I'm running on framework 4.0 by the way.
Yes. It is working example. Did you try my handler ? I can only see problem with your URL.
For some reason this only works if the original URI does not contain any parameters. If I add a parameter to the URI (eg. localhost:1234/api/forum?Product=10), then the binding of the UserId added in the handler does not work :(
|
1

I found the following solution to my problem

request.RequestUri = new Uri(request.RequestUri + "&UserId=8");

var newFormDataCollection = new FormDataCollection(request.RequestUri);
request.Properties.Remove("MS_QueryNameValuePairs");
request.Properties.Add("MS_QueryNameValuePairs", newFormDataCollection);

return base.SendAsync(request, cancellationToken);

[FromURI] seems to use the values in the FormDataCollection, so you simply need to update the "MS_QueryNameValuePairs" property.

2 Comments

My update somewhat similar and more than 8 hours ago
Indeed, I did not get a notification of you edits. Thank you for your help ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.