วิธีการแยกค่าส่วนหัวที่กำหนดเองในตัวจัดการข้อความ Web API?


150

ขณะนี้ฉันมีตัวจัดการข้อความในบริการ Web 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'

ฉันจะเข้าถึงส่วนหัวคำขอที่กำหนดเองเดียวผ่านอินสแตนซ์HttpRequestMessage( เอกสาร MSDN ) ที่ส่งผ่านไปยังวิธีการแทนที่ได้อย่างไร


เกิดอะไรขึ้นถ้าคุณใช้request.Headers.Get("MyCustomID");?
udidu

2
ไม่มีGet' on the ประเภท HttpRequestHeaders` ข้อความ: "ไม่สามารถแก้ไขสัญลักษณ์ 'รับ'" ได้
atconway

คำตอบ:


252

ลองสิ่งนี้:

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

นอกจากนี้ยังมีวิธีการ TryGetValues ​​บนส่วนหัวที่คุณสามารถใช้ได้หากคุณไม่ได้รับประกันว่าจะสามารถเข้าถึงส่วนหัวได้เสมอ


26
การตรวจสอบค่า null สำหรับ GetValues ​​จะไม่แสดงค่าใด ๆ เนื่องจากจะไม่มีผลตอบแทนใด ๆ หากส่วนหัวไม่มีอยู่คุณจะได้รับ InvalidOperationException คุณต้องใช้ TryGetHeaders หากเป็นไปได้ว่าส่วนหัวอาจไม่มีอยู่ในคำขอและตรวจสอบการตอบกลับที่ผิดพลาดหรือลอง / รับสาย GetValues ​​(ไม่แนะนำ)
Drew Marsh

4
@ ดึงคำขอหัวหน้าผู้เดียว (h => h.Key == "การอนุญาต"); รหัสน้อยลงทำเช่นเดียวกัน!
Elisabeth

17
ทำไมไม่เพียงแค่var id = request.Headers.GetValues("MyCustomID").FirstOrDefault();
Gaui

3
@SaeedNeamati เนื่องจากค่าส่วนหัวไม่ใช่แบบหนึ่งต่อหนึ่ง คุณสามารถมีSome-Header: oneและจากนั้นSome-Header: twoในคำขอเดียวกัน บางภาษาทิ้ง "หนึ่ง" อย่างเงียบ ๆ แต่นั่นไม่ถูกต้อง มันอยู่ใน RFC แต่ฉันขี้เกียจเกินกว่าที่จะหาได้ตอนนี้
Cory Mawhorter

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
FuncและActionเป็นลายเซ็นผู้รับมอบสิทธิ์ทั่วไปที่สร้างขึ้นใน. NET 3.5 ขึ้นไป ฉันยินดีที่จะพูดคุยคำถามเฉพาะเกี่ยวกับวิธีการ แต่ฉันขอแนะนำให้เรียนรู้เกี่ยวกับวิธีการเหล่านั้นก่อน
neontapir

1
@neontapir (และอื่น ๆ ) พารามิเตอร์ตัวที่สองถูกใช้เพื่อระบุค่าเริ่มต้นหากไม่พบคีย์ พารามิเตอร์ที่สามใช้เพื่อ 'แปลง' ค่าที่ส่งคืนให้เป็นชนิดที่ต้องการซึ่งยังระบุประเภทที่จะส่งคืน ตามตัวอย่างถ้าไม่พบ 'X-MyGuid' พารามิเตอร์ 2 แลมบ์ดาจะส่ง guid เริ่มต้นเป็นสตริง (โดยจะดึงจาก Header) และพารามิเตอร์ Guid.Parse จะแปลค่าที่พบหรือค่าสตริงเริ่มต้น เป็น GUID
Mikee

@neontapir คำขอมาจากที่ใดในฟังก์ชั่นนี้ (และหากเป็นโมฆะ HttpRequestMessage ใหม่จะมีส่วนหัวอย่างไร) ไม่เหมาะสมที่จะส่งคืนค่าเริ่มต้นหากคำขอเป็นโมฆะ
mendel

เป็นเวลาสองปีแล้ว แต่ถ้าฉันจำได้ว่ามีการHttpRequestMessageเริ่มต้นใหม่ด้วยคอลเลกชันส่วนหัวที่ว่างเปล่าซึ่งไม่เป็นโมฆะ ฟังก์ชั่นนี้จะจบลงด้วยการคืนค่าเริ่มต้นถ้าคำขอเป็นโมฆะ
neontapir

@ เมนเดล neontapir ฉันได้ลองใช้ตัวอย่างข้างต้นและฉันเชื่อว่า "คำขอ" ในบรรทัดที่ 2 ของวิธีการของร่างกายควรจะเป็นเขตข้อมูลส่วนตัวในชั้นเรียนที่มีวิธีการหรือจะส่งผ่านเป็นพารามิเตอร์ (ประเภท HttpRequestMessage) วิธีการ
Sudhanshu Mishra

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 ไม่ได้เป็นส่วนหนึ่งของการร้องขอ .. มันจะส่งกลับข้อยกเว้นเป็นโมฆะ
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

เพิ่มคลาสสแตติกใหม่แทนที่ Response for Request เรียกว่าจากตัวควบคุม 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 ไม่ได้เป็นส่วนหนึ่งของการร้องขอ .. มันจะส่งกลับข้อยกเว้นเป็นโมฆะ
Prasad Kanaparthi

1
@PrasadKanaparthi แล้วคุณควรใช้คำตอบเหมือนอีกstackoverflow.com/a/25640256/4275342 คุณเห็นว่าไม่มีการตรวจสอบโมฆะดังนั้นมันrequestคือnullอะไร? มันยังเป็นไปได้ หรือถ้าMyCustomIDเป็นสตริงว่างหรือไม่เท่ากับfoo? ขึ้นอยู่กับบริบทดังนั้นคำตอบนี้จะอธิบายวิธีการและการตรวจสอบและตรรกะทางธุรกิจทั้งหมดที่คุณต้องเพิ่มด้วยตัวคุณเอง
Roman Marusyk

คุณไม่เห็นด้วยว่ารหัสกำลังทำงานและสามารถคืนค่าส่วนหัว
Roman Marusyk

1
มันทำงานได้ดี .. ถ้า "MyCustomID" เป็นส่วนหนึ่งของคำขอที่ร้องขอ ใช่การตรวจสอบทั้งหมดจำเป็นต้องได้รับการดูแล
Prasad Kanaparthi

4
request.Headers.FirstOrDefault( x => x.Key == "MyCustomID" ).Value.FirstOrDefault()

ตัวแปรที่ทันสมัย ​​:)


เกิดอะไรขึ้นถ้า MyCustomID ไม่ได้เป็นส่วนหนึ่งของการร้องขอ .. มันจะส่งกลับข้อยกเว้นเป็นโมฆะ
Prasad Kanaparthi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.