Web APIメッセージハンドラーでカスタムヘッダー値を抽出する方法


150

現在、次のように 'SendAsync'をオーバーライドするメッセージハンドラーをWeb APIサービスに持っています。

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 2013

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が発生します。リクエストにヘッダーが存在しない可能性がある場合は、TryGetHeadersを使用して、誤った応答がないか確認するか、GetValues呼び出しを試行/キャッチします(非推奨)。
ドリューマーシュ

4
@Drew request.Headers.Single(h => h.Key == "Authorization"); 同じことを行うコードははるかに少なくなります!
エリザベス

17
なぜだけではないvar id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
Gaui

3
ヘッダー値が1対1ではないため、@ SaeedNeamati。あなたは持つことができSome-Header: one、その後、Some-Header: two同じリクエストインチ 一部の言語は「1つ」を警告なしで破棄しますが、これは誤りです。それはRFCにありますが、私は今それを見つけるのが面倒です。
Cory Mawhorter

1
Saeedのポイントは有効で、使いやすさが重要であり、ここで最も一般的な使用例は、要求ヘッダーの1つの値を取得することです。GetValuesオペレーションを使用して、リクエストヘッダーの複数の値を取得することもできます(これはほとんどの場合使用されます)が、99%の時間、特定のリクエストヘッダーの1つの値を取得するだけで、それは1である必要があります。ライナー。
ジャスティン

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

ユセフの答えをさらに詳しく説明するために、ユニットテスト中にこの状況に遭遇したので、ヘッダーが存在しないという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
FuncおよびAction.NET 3.5以降に組み込まれている汎用デリゲート署名コンストラクトです。この方法に関する具体的な質問については喜んで話したいと思いますが、最初にそれらについて学ぶことをお勧めします。
ネオタピル2013

1
@neontapir(およびその他)2番目のパラメーターは、キーが見つからない場合のデフォルト値を提供するために使用されます。3番目のパラメーターは、戻り値を目的の型に「変換」して、返される型も指定するために使用されます。この例では、「X-MyGuid」が見つからない場合、パラメーター2ラムダは基本的にデフォルトのGUIDを文字列として提供し(ヘッダーから取得されるため)、Guid.Parseの3番目のパラメーターは見つかった文字列値またはデフォルトの文字列値を変換しますGUIDに。
Mikee

@neontapirこの関数のリクエストはどこから来ますか?(そしてそれがnullの場合、新しいHttpRequestMessage()はどのようにヘッダーを持ちますか?Requestがnullの場合にデフォルト値を返すだけでは意味がありませんか?
mendel

2年経ちましたが、思い出すと、HttpRequestMessagenullではない空のHeadersコレクションでnew が初期化されます。この関数は、リクエストがnullの場合、最終的にデフォルト値を返します。
neontapir 2015

@mendel、neontapir上記のスニペットを使用してみましたが、メソッド本体の2行目の「リクエスト」は、メソッドを含むクラスのプライベートフィールドであるか、または(HttpRequestMessageタイプの)パラメータとして渡される必要がありますメソッド
Sudhanshu Mishra 2015

12

新しいメソッドを作成します-「個々のHTTPヘッダー値を返します」。HttpRequestMessageから複数のキー値にアクセスする必要がある場合は、毎回このメソッドをキー値で呼び出します。

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

見栄えは良いですが、GetFirstHeaderValueOrDefault2つのパラメーターがあるため、サンプルの使用法として呼び出すときにparamが不足しているというメッセージが表示されvar myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");ますか?
Jeb50

新しい静的クラスが追加され、リクエストの応答が置き換えられました。var myValue = myNameSpace.HttpRequestMessageExtension.GetFirstHeaderValueOrDefault<int>("productID");取得したとおり
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のような別の回答を使用する必要があります。あなたは何で、そう、何のいずれかのヌルチェックがあることが見ていないrequestですかnull?それも可能です。またはMyCustomID、空の文字列または等しくない場合はfooどうなりますか?それはコンテキストに依存するので、この回答は方法と、独自に追加する必要があるすべての検証およびビジネスロジックを説明します
Roman Marusyk

コードが機能していて、ヘッダー値を返すことができることに同意しませんか?
ローママルシク

1
「MyCustomID」がリクエストのリクエストの一部である場合、正常に動作します。はい、すべての検証には注意が必要です
Prasad Kanaparthi

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.