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


150

현재 웹 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


사용하면 request.Headers.Get("MyCustomID");어떻게 되나요?
udidu 2019

2
Get' on the HttpRequestHeaders` 유형 이 없습니다 . " 'Get'기호를 확인할 수 없습니다"라는 메시지가 표시됩니다.
atconway 2013

답변:


252

다음과 같이 해보십시오 :

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

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


26
GetValues에 대한 null 검사는 null을 반환하지 않으므로 값을 제공하지 않습니다. 헤더가 존재하지 않으면 InvalidOperationException이 발생합니다. 요청에 헤더가 없을 수 있고 TryValues ​​호출 주위에 잘못된 응답 또는 시도 / 캐치를 확인하는 것이 가능하면 TryGetHeaders를 사용해야합니다 (권장되지 않음).
Drew Marsh

4
@Drew request.Headers.Single (h => h.Key == "권한 부여"); 같은 일을하는 코드가 훨씬 적습니다!
엘리자베스

17
그냥var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
가우이

3
헤더 값이 일대일이 아니므로 @SaeedNeamati. 동일한 요청 Some-Header: one을 가질 수 있습니다 Some-Header: two. 일부 언어는 "하나"를 자동으로 삭제하지만 올바르지 않습니다. 그것은 RFC에 있지만 지금 그것을 찾기에는 너무 게으르다.
Cory Mawhorter 2016 년

1
Saeed의 요점은 유효하고 유용성이 중요하며 여기서 가장 일반적인 사용 사례는 요청 헤더에 대한 하나의 값을 검색하는 것입니다. 요청 헤더 (사람들이 사용하게 될)에 대해 여러 값을 검색하기위한 GetValues ​​오퍼레이션을 계속 사용할 수 있지만 99 %는 특정 요청 헤더에 대해 하나의 값만 검색하려고합니다. 정기선.
Justin

39

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();
     }           

17

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의 답변을 살펴보십시오.


1
FuncAction.NET 3.5에 이상 내장 된 일반적인 위임 서명 구조입니다. 이 방법에 대한 구체적인 질문에 대해 기꺼이 이야기하지만 먼저 그 방법에 대해 배우는 것이 좋습니다.
neontapir

1
@neontapir (및 기타) 두 번째 매개 변수는 키를 찾을 수없는 경우 기본값을 제공하는 데 사용됩니다. 세 번째 매개 변수는 리턴 값을 원하는 유형으로 '변환'하여 리턴 할 유형도 지정하는 데 사용됩니다. 예를 들어, 'X-MyGuid'를 찾을 수 없으면 매개 변수 2 람다는 기본적으로 기본 guid를 문자열로 제공하고 (Header에서 검색 한대로) Guid.Parse 세 번째 매개 변수는 찾은 기본 문자열 값을 변환합니다. GUID로.
Mikee

@neontapir이 함수에서 요청은 어디에서 오는가? (그리고 그것이 null이라면 새로운 HttpRequestMessage ()는 어떤 헤더를 가질 것인가? Request가 null이면 기본값을 반환하는 것은 의미가 없다.
mendel

2 년이 지났지 만 기억하면 새 HttpRequestMessage헤더는 빈 헤더 컬렉션으로 초기화되며 null이 아닙니다. 이 함수는 request가 null 인 경우 기본값을 반환합니다.
neontapir

@mendel, neontapir 위의 스 니펫을 사용해 보았고 메소드 본문 2 행의 "요청"이 메소드를 포함하는 클래스의 개인 필드이거나 매개 변수 (HttpRequestMessage 유형)에 전달되어야한다고 생각합니다. 방법
Sudhanshu Mishra 1

12

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();
        }

MyCustomID가 요청의 일부가 아닌 경우 null 예외를 반환합니다.
Prasad Kanaparthi

10

@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");

멋지지만 GetFirstHeaderValueOrDefault두 개의 매개 변수가 있으므로 샘플 사용법으로 호출 할 때 매개 변수 누락에 대해 불평 var myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");합니다.
Jeb50

새로운 정적 클래스를 추가하고 요청에 대한 응답을 대체했습니다. API 컨트롤러에서 호출뿐만 var myValue = myNameSpace.HttpRequestMessageExtension.GetFirstHeaderValueOrDefault<int>("productID");가지고 주어진 인수를가 없다는 것을 요구되는 형식 매개 변수의 'headerKey' 'HttpRequestMessageExtension.GetFirstHeaderValueOrDefault <T> (HttpRequestMessage, 문자열)'에 해당
Jeb50

@ Jeb50 using HttpResponseMessageExtensions이 확장명을 사용하려는 파일 을 선언 하고 있습니까?
Doguhan Uluca

4

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이었습니다.


4

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}");
            ...
        }
    }

4

한 줄 솔루션

var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();

MyCustomID가 요청의 일부가 아닌 경우 null 예외를 반환합니다.
Prasad Kanaparthi

1
@PrasadKanaparthi 그런 다음 stackoverflow.com/a/25640256/4275342 와 같은 다른 답변을 사용해야합니다 . 당신은 무엇 때문에, 어떤에 null 체크가 있다는 것을 볼 request것입니다 null? 가능하다. 또는 MyCustomID빈 문자열이거나 같지 않으면 foo어떻게됩니까? 상황에 따라 달라
지므로이

코드가 작동하고 헤더 값을 반환 할 수 있다는 데 동의하지 않습니까?
로마 Marusyk

1
"MyCustomID"가 요청 요청의 일부인 경우 제대로 작동합니다. 예, 모든 유효성 검사는주의해야합니다
Prasad Kanaparthi

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.