वेब एपीआई संदेश हैंडलर में कस्टम हेडर मान कैसे निकालें?


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

मैं इस ओवरराइड विधि में पारित ( MSDN प्रलेखन ) उदाहरण के माध्यम से एक एकल कस्टम अनुरोध शीर्षलेख तक कैसे पहुँच सकता हूँ ?HttpRequestMessage


यदि आप उपयोग कर रहे हैं तो क्या होगा request.Headers.Get("MyCustomID");?
udidu

2
कोई Get' on the HttpRequestHeaders 'प्रकार नहीं है। संदेश: "प्रतीक प्राप्त नहीं कर सकता '' प्राप्त करें" का उत्पादन किया जाता है।
21

जवाबों:


252

कुछ इस तरह की कोशिश करो:

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

हेडर पर एक TryGetValues ​​विधि भी है जिसका उपयोग आप कर सकते हैं यदि आपको हेडर तक पहुंच की गारंटी नहीं है।


26
GetValues ​​के लिए अशक्त चेक किसी भी मूल्य की सेवा नहीं करता है क्योंकि यह कभी भी अशक्त नहीं लौटेगा। यदि शीर्ष लेख मौजूद नहीं है, तो आपको एक InvalidOperationException मिलेगी। यदि यह संभव है कि हेडर अनुरोध में मौजूद नहीं हो सकता है और GetValues ​​कॉल (अनुशंसित नहीं है) के आसपास कोशिश करें या पकड़ें, तो ट्राइगेटहेडर्स का उपयोग करने की आवश्यकता है।
आकर्षित मार्श

4
@ ड्रू रिक्वेस्ट.हेडर्स.सिंगल (h => h.Key == "प्राधिकरण"); बहुत कम कोड ही कर!
एलिजाबेथ

17
सिर्फ क्यों नहींvar id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
गौरी

3
@SaeedNeamati क्योंकि हेडर मान एक-से-एक नहीं हैं। आप कर सकते हैं Some-Header: oneऔर फिर Some-Header: twoउसी अनुरोध में। कुछ भाषाएं चुपचाप "एक" को छोड़ देती हैं लेकिन यह गलत है। यह RFC में है, लेकिन मैं इसे खोजने के लिए बहुत आलसी हूं।
कोरी मोवह्टर

1
सईद की बात वैध है, प्रयोज्यता महत्वपूर्ण है और यहां सबसे आम उपयोग मामला एक अनुरोध हेडर के लिए एक मान प्राप्त करना है। आपके पास अनुरोध शीर्षलेख के लिए कई मान प्राप्त करने के लिए गेटवेअल्स ऑपरेशन हो सकता है (जो लोग उपयोग करेंगे), लेकिन 99% समय वे केवल एक विशिष्ट अनुरोध हेडर के लिए एक मान प्राप्त करना चाहते हैं, और यह एक होना चाहिए लाइनर।
जस्टिन

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

यूसुफ के जवाब पर विस्तार करने के लिए, मैंने हेडर के बारे में ड्रू की चिंताओं पर आधारित इस पद्धति को नहीं लिखा, क्योंकि मैं इकाई परीक्षण के दौरान इस स्थिति में भाग गया था।

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 और इसके बाद के संस्करण में निर्मित सामान्य प्रतिनिधि हस्ताक्षर निर्माण हैं। मुझे विधि के बारे में विशिष्ट प्रश्नों पर चर्चा करने में खुशी होगी, लेकिन मैं पहले उन लोगों के बारे में जानने की सलाह दूंगा।
नेणतापीर

1
@neontapir (और अन्य) कुंजी नहीं मिलने पर डिफ़ॉल्ट मान प्रदान करने के लिए दूसरे पैरामीटर का उपयोग किया जाता है। तीसरे पैरामीटर का उपयोग वांछित प्रकार के होने के लिए रिटर्न वैल्यू को बदलने के लिए किया जाता है जो कि रिटर्न के प्रकार को भी निर्दिष्ट करता है। उदाहरण के अनुसार, यदि 'X-MyGuid' नहीं मिला है, तो पैरामीटर 2 लैम्ब्डा मूल रूप से एक स्ट्रिंग के रूप में डिफ़ॉल्ट गाइड की आपूर्ति करता है (जैसा कि यह हेडर से पुनर्प्राप्त किया गया होगा) और Guide.Parse तीसरा पैरामीटर पाया या डिफ़ॉल्ट मान मान का अनुवाद करेगा एक GUID में।
मका

@neontapir इस फ़ंक्शन में अनुरोध कहां से आ रहा है? (और अगर यह शून्य है तो नया HttpRequestMessage () का कोई हेडर कैसे होगा? क्या यह अनुरोध
मानने के

यह दो साल हो गया है, लेकिन अगर मुझे याद है, एक नया HttpRequestMessageएक खाली हेडर संग्रह के साथ शुरू होता है, जो शून्य नहीं है। यदि अनुरोध शून्य है, तो यह फ़ंक्शन डिफ़ॉल्ट मान लौटाता है।
नॉनटापिर

@mendel, neontapir मैंने उपरोक्त स्निपेट का उपयोग करने की कोशिश की है और मेरा मानना ​​है कि विधि बॉडी की लाइन 2 पर "अनुरोध" या तो विधि युक्त कक्षा में एक निजी क्षेत्र होना चाहिए या एक पैरामीटर (प्रकार HttpRestestMessage) के रूप में पारित किया जाना चाहिए विधि
सुधांशु मिश्रा

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 अनुरोध का हिस्सा नहीं है .. यह अशक्त अपवाद देता है।
प्रसाद कानापर्थी

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");मुझे कुछ याद आ रहा है तो क्या यह अनुपस्थित है?
जेबी 50

रिक्वेस्ट के लिए रिस्पॉन्स की जगह नया स्टैटिक क्लास जोड़ा गया। एपीआई नियंत्रक से कहा जाता है, के रूप में var myValue = myNameSpace.HttpRequestMessageExtension.GetFirstHeaderValueOrDefault<int>("productID");मिल गया कोई दिए गए तर्क नहीं है कि आवश्यक औपचारिक पैरामीटर के 'headerKey' 'HttpRequestMessageExtension.GetFirstHeaderValueOrDefault <टी> (HttpRequestMessage, स्ट्रिंग)' से मेल खाती है
Jeb50

@ Jeb50 क्या आप using HttpResponseMessageExtensionsउस फ़ाइल पर घोषणा कर रहे हैं जिसे आप इस एक्सटेंशन का उपयोग करने का प्रयास कर रहे हैं?
डॉगुहान उलुका

4

ASP.Net कोर के लिए एक आसान समाधान है यदि आप सीधे नियंत्रक विधि में परम का उपयोग करना चाहते हैं: [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 अनुरोध का हिस्सा नहीं है .. यह अशक्त अपवाद देता है।
प्रसाद कानापर्थी

1
@PrasadKanaparthi तो आपको stackoverflow.com/a/25640256/4275342 जैसे अन्य उत्तर का उपयोग करना चाहिए । आप देखते हैं कि कोई अशक्त जाँच नहीं है, तो, क्या requestहै null? यह संभव भी है। या क्या होगा अगर MyCustomIDएक खाली स्ट्रिंग है या नहीं के बराबर है foo? यह संदर्भ पर निर्भर करता है, इसलिए यह उत्तर केवल तरीके का वर्णन करता है, और सभी सत्यापन और व्यावसायिक तर्क जो आपको अपने द्वारा जोड़ने की आवश्यकता है
रोमन Marusyk

क्या आप इस बात से सहमत नहीं हैं कि कोड काम कर रहा है और हेडर मान वापस कर सकता है?
रोमन मारसुक

1
यह ठीक काम करता है .. अगर "MyCustomID" अनुरोध के अनुरोध का हिस्सा है। हां, सभी सत्यापन को ध्यान में रखने की आवश्यकता है
प्रसाद कानापर्थी

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.