Web API ileti işleyicisinde özel üstbilgi değeri nasıl ayıklanır?


150

Şu anda Web API hizmetimde 'SendAsync'i geçersiz kılan bir ileti işleyici var:

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

Bu kod içinde adı verilen bir özel ek istek üstbilgi değerini incelemek gerekiyor MyCustomID. Sorun ben aşağıdakileri yaptığımda:

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

... Aşağıdaki hata mesajını alıyorum:

'System.Net.Http.Headers.HttpRequestHeaders' türündeki bir ifadeye [] ile dizin oluşturma uygulanamıyor

Bu geçersiz kılınmış yönteme aktarılan ( MSDN Documentation ) örneği aracılığıyla tek bir özel istek başlığına nasıl erişebilirim ?HttpRequestMessage


kullanıyorsanız ne olur request.Headers.Get("MyCustomID");?
udidu

2
Get' on the HttpRequestHeaders türü yoktur . "'Get' sembolü çözülemiyor" mesajı üretiliyor.
atconway

Yanıtlar:


252

Bunun gibi bir şey deneyin:

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

Üstbilgilere her zaman üstbilgiye erişme garantiniz yoksa kullanabileceğiniz bir TryGetValues ​​yöntemi de vardır.


26
GetValues ​​için null denetimi hiçbir zaman null döndürmeyeceğinden herhangi bir değer sunmaz. Üstbilgi yoksa bir InvalidOperationException alırsınız. Başlık istekte bulunmuyorsa ve yanlış bir yanıt olup olmadığını kontrol etmek mümkünse TryGetHeaders kullanmanız gerekir VEYA GetValues ​​çağrısının etrafında denemek / yakalamak (önerilmez).
Drew Marsh

4
@ Çekme isteği.Headers.Single (h => h.Key == "Yetkilendirme"); Çok daha az kod aynı şeyi yapıyor!
Elisabeth

17
Neden sadecevar id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
Gaui

3
@SaeedNeamati çünkü başlık değerleri bire bir değil. Sen olabilir Some-Header: onesonra ve Some-Header: twoaynı istekte. Bazı diller sessizce "bir" i atar, ancak bu yanlıştır. RFC'de ama şimdi bulmak için çok tembelim.
Cory Mawhorter

1
Saeed'in noktası geçerlidir, kullanılabilirlik önemlidir ve buradaki en yaygın kullanım durumu bir istek üstbilgisi için bir değer elde etmektir. Bir istek üstbilgisi için birden çok değer almak için (insanların yalnızca kullanacağı) bir GetValues ​​işleminiz olabilir, ancak% 99'u belirli bir istek üstbilgisi için yalnızca bir değer almak isteyecek ve bu bir değer olmalıdır astar.
Justin

39

throws exceptionAnahtar yoksa aşağıdaki satır .

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

Geçici çözüm:

System.Linq'i dahil edin;

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

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

17

Youssef'in cevabını genişletmek için, Drew'un mevcut olmayan başlık hakkındaki endişelerini temel alarak bu yöntemi yazdım, çünkü ünite testi sırasında bu duruma rastladım.

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

İşte bir örnek kullanım:

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

Ayrıca daha do- ru bir çözüm için @ doguhan-uluca'nın cevabına bir göz atın.


1
Funcve Action.NET 3.5 ve sonraki sürümlerinde yerleşik genel temsilci imza yapılarıdır. Yöntemle ilgili belirli soruları tartışmaktan memnuniyet duyarım, ancak önce bunları öğrenmenizi tavsiye ederim.
neontapir

1
@neontapir (ve diğerleri), anahtar bulunmazsa varsayılan bir değer sağlamak için ikinci parametre kullanılır. Üçüncü parametre, döndürülecek değeri de belirten, istenen türde olacak şekilde dönüş değerini 'dönüştürmek' için kullanılır. Örneğe göre, 'X-MyGuid' bulunmazsa, parametre 2 lambda temel olarak bir dize olarak varsayılan bir kılavuz (Üstbilgiden alındığı gibi) sağlar ve Guid.Parse üçüncü parametre, bulunan veya varsayılan dize değerini çevirir bir GUID içine.
Mikee

@neontapir Bu işlevde İstek nereden geliyor? (ve eğer boşsa, yeni bir HttpRequestMessage () herhangi bir başlığa sahip olacak mı? İstek boşsa varsayılan değeri döndürmek mantıklı değil mi?
mendel

İki yıl oldu, ancak hatırlıyorsam, HttpRequestMessageboş bir Headers koleksiyonuyla yeni bir değer başlatılır, ki bu boş değildir. Bu işlev, istek boşsa varsayılan değeri döndürür.
neontapir

@mendel, neontapir Yukarıdaki snippet'i kullanmayı denedim ve yöntem gövdesinin 2 satırındaki "İstek" yöntemini içeren sınıfta özel bir alan olmalıdır veya bir parametre (HttpRequestMessage türü) olarak geçirilmesi gerektiğine inanıyorum yöntemi
Sudhanshu Mishra

12

Yeni bir yöntem oluştur - ' Tek bir HTTP Üstbilgisi değeri döndürür ' ve HttpRequestMessage'dan birden fazla anahtar değerine erişmeniz gerektiğinde bu yöntemi anahtar değeriyle her zaman çağırın.

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 isteğin bir parçası değilse .. null istisna döndürür.
Prasad Kanaparthi

10

@ Neontapir'in çözümünü daha da genişletmek için, HttpRequestMessage veya HttpResponseMessage'a eşit olarak uygulanabilen ve elle kodlanmış ifadeler veya işlevler gerektirmeyen daha genel bir çözüm.

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

Örnek kullanım:

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

Harika görünüyor, ancak GetFirstHeaderValueOrDefaultiki parametre var, bu yüzden örnek kullanımı olarak çağırırken eksik paramdan şikayet ediyor var myValue = response.GetFirstHeaderValueOrDefault<int>("MyValue");Bir şey mi kaçırıyorum?
Jeb50

Yeni statik sınıf eklendi, İstek için Yanıt değiştirildi. API denetleyicisinden denilen yanı var myValue = myNameSpace.HttpRequestMessageExtension.GetFirstHeaderValueOrDefault<int>("productID");var verilen tartışma yok olması gerekmektedir biçimsel parametre 'headerKey' 'HttpRequestMessageExtension.GetFirstHeaderValueOrDefault <T> (HttpRequestMessage, string)' karşılık gelir
Jeb50

@ Jeb50, using HttpResponseMessageExtensionsbu uzantıyı kullanmaya çalıştığınız dosyada mı beyan ediyorsunuz?
Doguhan Uluca

4

ASP.Net Core için, parametreyi doğrudan denetleyici yönteminde kullanmak istiyorsanız kolay bir çözüm vardır: [FromHeader] ek açıklamasını kullanın.

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

Ek Bilgi: Benim durumumda "myParam" bir dize olması gerekiyordu, int her zaman 0 idi.


4

ASP.NET için bu basit kitaplık / paketi kullanarak üstbilgiyi doğrudan denetleyici yöntemindeki parametreden alabilirsiniz . [FromHeader]ASP.NET Core'da olduğu gibi bir özellik sağlar :). Örneğin:

    ...
    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

Tek hat çözümü

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

MyCustomID isteğin bir parçası değilse .. null istisna döndürür.
Prasad Kanaparthi

1
@PrasadKanaparthi o zaman stackoverflow.com/a/25640256/4275342 gibi başka bir cevap kullanmalısınız . Ne, yani, hayır, hiç boş çek olduğunu görüyoruz requestolduğunu null? Ayrıca mümkündür. Ya da MyCustomIDboş bir dize eşit veya eşit değilse foo? Bağlama bağlıdır, bu nedenle bu cevap sadece yolu ve kendi kendinize eklemeniz gereken tüm doğrulama ve iş mantığını
açıklar

Kodun çalıştığını ve başlık değerini döndürebileceğini kabul etmiyor musunuz?
Roman Marusyk

1
İyi çalışır .. "MyCustomID" istek isteğinin bir parçası ise. Evet, tüm doğrulamaların yapılması gerekiyor
Prasad Kanaparthi

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.