WebApi: mapping parameter to header value

两盒软妹~` 提交于 2019-11-29 22:36:37

I don't think this is supported out of the box, like for example with the [FromBody] attribute. It seems you should be able to achieve this functionality by using Model Binders, as described here. In the model binder you have access to the request and its headers, so you should be able to read the header and set its value to the bindingContext.Model property.

Edit: Reading the article further, it seems a custom HttpParameterBinding and a ParameterBindingAttribute is a more appropriate solution, or at least I would go this way. You could implement a generic [FromHeader] attribute, which does the job. I am also fighting the same problem, so I will post my solution once I have it in place.

Edit 2: Here is my implementation:

public class FromHeaderBinding : HttpParameterBinding
{
    private string name;

    public FromHeaderBinding(HttpParameterDescriptor parameter, string headerName) 
        : base(parameter)
    {
        if (string.IsNullOrEmpty(headerName))
        {
            throw new ArgumentNullException("headerName");
        }

        this.name = headerName;
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        IEnumerable<string> values;
        if (actionContext.Request.Headers.TryGetValues(this.name, out values))
        {
            actionContext.ActionArguments[this.Descriptor.ParameterName] = values.FirstOrDefault();
        }

        var taskSource = new TaskCompletionSource<object>();
        taskSource.SetResult(null);
        return taskSource.Task;
    }
}

public abstract class FromHeaderAttribute : ParameterBindingAttribute
{
    private string name;

    public FromHeaderAttribute(string headerName)
    {
        this.name = headerName;
    }

    public override HttpParameterBinding GetBinding(HttpParameterDescriptor parameter)
    {
        return new FromHeaderBinding(parameter, this.name);
    }
}

public class MyHeaderAttribute : FromHeaderAttribute
{
    public MyHeaderAttribute()
        : base("MyHeaderName")
    {
    }
}

Then you can use it like this:

[HttpGet]
public IHttpActionResult GetItem([MyHeader] string headerValue)
{
    ...
}

Hope that helps.

WebApi on DotNet Core has a has some additional attributes for extracting data from the request. Microsoft.AspNetCore.Mvc.FromHeaderAttribute will read from the request head.

public ActionResult ReadFromHeader([FromHeader(Name = "your-header-property-name")] string data){
   //Do something
}
NYCChris

Thank you filipov for the answer.. I took your code and modified it a bit to suit my needs. I am posting my changes here in case anyone can make use of this.

I made 2 changes.

  1. I liked the idea of the FromHeaderAttribute, but without subclassing. I made this class public, and require the user to set the param name.

  2. I needed to support other data types besides string. So I attempt to convert the string value to the descriptor's parameterType.

Use it like this:

[HttpGet]
public void DeleteWidget(long widgetId, [FromHeader("widgetVersion")] int version)
{
    ... 
}

And this is my FromHeaderBinding

public class FromHeaderBinding : HttpParameterBinding
{
    private readonly string _name;

    public FromHeaderBinding(HttpParameterDescriptor parameter, string headerName)
        : base(parameter)
    {
        if (string.IsNullOrEmpty(headerName)) throw new ArgumentNullException("headerName");
        _name = headerName;
    }

    public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider, HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        IEnumerable<string> values;
        if (actionContext.Request.Headers.TryGetValues(_name, out values))
        {
            var tempVal = values.FirstOrDefault();
            if (tempVal != null)
            {
                var actionValue = Convert.ChangeType(tempVal, Descriptor.ParameterType);
                actionContext.ActionArguments[Descriptor.ParameterName] = actionValue;
            }
        }

        var taskSource = new TaskCompletionSource<object>();
        taskSource.SetResult(null);
        return taskSource.Task;
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!