[C#] 웹 API 메시지 핸들러에서 사용자 정의 헤더 값을 추출하는 방법은 무엇입니까?

현재 웹 API 서비스에 다음과 같이 ‘SendAsync’를 재정의하는 메시지 핸들러가 있습니다.

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
  //implementation
}

이 코드 내에서라는 사용자 정의 추가 요청 헤더 값을 검사해야합니다 MyCustomID. 문제는 내가 다음을 할 때입니다.

if (request.Headers.Contains("MyCustomID"))  //OK
    var id = request.Headers["MyCustomID"];  //build error - not OK

… 다음과 같은 오류 메시지가 나타납니다.

‘System.Net.Http.Headers.HttpRequestHeaders’유형의 표현식에 []를 사용하여 인덱싱을 적용 할 수 없습니다.

이 재정의 된 메서드에 전달 된 ( MSDN Documentation ) 인스턴스 를 통해 단일 사용자 지정 요청 헤더에 액세스하려면 어떻게 해야합니까?HttpRequestMessage



답변

다음과 같이 해보십시오 :

IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");
var id = headerValues.FirstOrDefault();

헤더에 대한 액세스 권한이 항상 보장되지 않는 경우 사용할 수있는 헤더에 TryGetValues ​​메소드도 있습니다.


답변

throws exception키가없는 경우 아래 줄 입니다.

IEnumerable<string> headerValues = request.Headers.GetValues("MyCustomID");

해결 방법 :

System.Linq 포함;

IEnumerable<string> headerValues;
var userId = string.Empty;

     if (request.Headers.TryGetValues("MyCustomID", out headerValues))
     {
         userId = headerValues.FirstOrDefault();
     }           


답변

Youssef의 답변을 확장하기 위해 단위 테스트 중에이 상황이 발생했기 때문에 헤더가 존재하지 않는 Drew의 우려 사항을 기반 으로이 방법을 작성했습니다.

private T GetFirstHeaderValueOrDefault<T>(string headerKey,
   Func<HttpRequestMessage, string> defaultValue,
   Func<string,T> valueTransform)
    {
        IEnumerable<string> headerValues;
        HttpRequestMessage message = Request ?? new HttpRequestMessage();
        if (!message.Headers.TryGetValues(headerKey, out headerValues))
            return valueTransform(defaultValue(message));
        string firstHeaderValue = headerValues.FirstOrDefault() ?? defaultValue(message);
        return valueTransform(firstHeaderValue);
    }

사용법 예는 다음과 같습니다.

GetFirstHeaderValueOrDefault("X-MyGuid", h => Guid.NewGuid().ToString(), Guid.Parse);

또한 더 일반적인 솔루션에 대한 @ doguhan-uluca의 답변을 살펴보십시오.


답변

HttpRequestMessage에서 여러 키 값에 액세스해야 할 때마다 ‘ 개별 HTTP 헤더 값을 리턴합니다 ‘라는 새 메소드를 작성하고 키 값으로이 메소드를 호출하십시오.

public static string GetHeader(this HttpRequestMessage request, string key)
        {
            IEnumerable<string> keys = null;
            if (!request.Headers.TryGetValues(key, out keys))
                return null;

            return keys.First();
        }


답변

@neontapir의 솔루션을 더욱 확장하기 위해 HttpRequestMessage 또는 HttpResponseMessage에 동일하게 적용 할 수 있고 손으로 코딩 된 표현식 또는 함수가 필요하지 않은보다 일반적인 솔루션이 있습니다.

using System.Net.Http;
using System.Collections.Generic;
using System.Linq;

public static class HttpResponseMessageExtensions
{
    public static T GetFirstHeaderValueOrDefault<T>(
        this HttpResponseMessage response,
        string headerKey)
    {
        var toReturn = default(T);

        IEnumerable<string> headerValues;

        if (response.Content.Headers.TryGetValues(headerKey, out headerValues))
        {
            var valueString = headerValues.FirstOrDefault();
            if (valueString != null)
            {
                return (T)Convert.ChangeType(valueString, typeof(T));
            }
        }

        return toReturn;
    }
}

샘플 사용법 :

var myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");


답변

ASP.Net Core의 경우 컨트롤러 메소드에서 직접 매개 변수를 사용하려는 경우 쉬운 솔루션이 있습니다. [FromHeader] 주석을 사용하십시오.

        public JsonResult SendAsync([FromHeader] string myParam)
        {
        if(myParam == null)  //Param not set in request header
        {
           return null;
        }
        return doSomething();
    }   

추가 정보 : 필자의 경우 “myParam”은 문자열이어야했고 int는 항상 0이었습니다.


답변

ASP.NET의 경우이 간단한 라이브러리 / 패키지를 사용하여 컨트롤러 메서드의 매개 변수에서 직접 헤더를 가져올 수 있습니다 . [FromHeader]ASP.NET Core에서와 마찬가지로 속성을 제공합니다 . 🙂 예를 들면 다음과 같습니다.

    ...
    using RazHeaderAttribute.Attributes;

    [Route("api/{controller}")]
    public class RandomController : ApiController
    {
        ...
        // GET api/random
        [HttpGet]
        public IEnumerable<string> Get([FromHeader("pages")] int page, [FromHeader] string rows)
        {
            // Print in the debug window to be sure our bound stuff are passed :)
            Debug.WriteLine($"Rows {rows}, Page {page}");
            ...
        }
    }