รับที่อยู่ IP ของโฮสต์ระยะไกล


136

ใน ASP.NET มีSystem.Web.HttpRequestclass ซึ่งมีServerVariablesคุณสมบัติที่สามารถให้ที่อยู่ IP จากREMOTE_ADDRมูลค่าทรัพย์สิน

อย่างไรก็ตามฉันไม่สามารถหาวิธีที่คล้ายกันเพื่อรับที่อยู่ IP ของโฮสต์ระยะไกลจาก ASP.NET Web API

ฉันจะรับที่อยู่ IP ของรีโมตโฮสต์ที่ร้องขอได้อย่างไร

คำตอบ:


189

เป็นไปได้ที่จะทำเช่นนั้น แต่ไม่สามารถค้นพบได้มาก - คุณต้องใช้ถุงคุณสมบัติจากคำขอขาเข้าและคุณสมบัติที่คุณต้องใช้ขึ้นอยู่กับว่าคุณใช้ Web API ภายใต้ IIS (โฮสต์เว็บ) หรือโฮสต์ด้วยตนเอง รหัสด้านล่างแสดงวิธีการนี้สามารถทำได้

private string GetClientIp(HttpRequestMessage request)
{
    if (request.Properties.ContainsKey("MS_HttpContext"))
    {
        return ((HttpContextWrapper)request.Properties["MS_HttpContext"]).Request.UserHostAddress;
    }

    if (request.Properties.ContainsKey(RemoteEndpointMessageProperty.Name))
    {
        RemoteEndpointMessageProperty prop;
        prop = (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessageProperty.Name];
        return prop.Address;
    }

    return null;
}

4
ขอบคุณฉันกำลังมองหาสิ่งนี้เช่นกัน การปรับปรุงเล็กน้อย = ชั้นส่วนขยาย: gist.github.com/2653453
MikeJansen

28
WebAPI นั้นสะอาดเป็นส่วนใหญ่ เป็นเรื่องน่าละอายที่รหัสเช่นนี้เป็นสิ่งจำเป็นสำหรับสิ่งเล็ก ๆ น้อย ๆ ในฐานะที่เป็น IP
คางคก

2
เป็นRemoteEndpointMessagePropertyคลาสในSystem.ServiceModel.Channelsnamespace System.ServiceModel.dllประกอบหรือไม่ นั่นคือการชุมนุมที่เป็นของ WCF หรือไม่?
Slauma

4
@Sluma ใช่พวกเขาเป็น ASP.NET Web API นั้นมีการใช้งานใน "รสชาติ" สองแบบคือโฮสต์ด้วยตนเองและโฮสต์บนเว็บ เวอร์ชันที่โฮสต์บนเว็บนั้นจะถูกนำไปใช้ด้านบนของ ASP.NET ในขณะที่เวอร์ชันที่โฮสต์เองนั้นจะอยู่ด้านบนของตัวฟัง WCF โปรดสังเกตว่าแพลตฟอร์ม (ASP.NET Web API) นั้นเป็นโฮสติ้งซึ่งไม่เชื่อเรื่องพระเจ้าดังนั้นจึงเป็นไปได้ว่าบางคนจะใช้โฮสติ้งที่แตกต่างกันในอนาคตและโฮสต์จะแสดงคุณสมบัตินั้น (ปลายทางปลายทางระยะไกล) แตกต่างกัน
carlosfigueira

3
น่าเสียดายที่นี่ไม่สามารถใช้งานได้หากคุณโฮสต์โดยใช้ Owin (แนะนำให้ใช้กับ Web API 2) ต้องการอีกถ้ามี ...
Nikolai Samteladze

74

โซลูชันนี้ยังครอบคลุมถึง Web API ที่โฮสต์โดยตนเองโดยใช้ Owin บางส่วนจากที่นี่

คุณสามารถสร้างวิธีการส่วนตัวในการApiControllerที่จะส่งคืนที่อยู่ IP ระยะไกลไม่ว่าคุณโฮสต์เว็บ API ของคุณ:

 private const string HttpContext = "MS_HttpContext";
 private const string RemoteEndpointMessage =
     "System.ServiceModel.Channels.RemoteEndpointMessageProperty";
 private const string OwinContext = "MS_OwinContext";

 private string GetClientIp(HttpRequestMessage request)
 {
       // Web-hosting
       if (request.Properties.ContainsKey(HttpContext ))
       {
            HttpContextWrapper ctx = 
                (HttpContextWrapper)request.Properties[HttpContext];
            if (ctx != null)
            {
                return ctx.Request.UserHostAddress;
            }
       }

       // Self-hosting
       if (request.Properties.ContainsKey(RemoteEndpointMessage))
       {
            RemoteEndpointMessageProperty remoteEndpoint =
                (RemoteEndpointMessageProperty)request.Properties[RemoteEndpointMessage];
            if (remoteEndpoint != null)
            {
                return remoteEndpoint.Address;
            }
        }

       // Self-hosting using Owin
       if (request.Properties.ContainsKey(OwinContext))
       {
           OwinContext owinContext = (OwinContext)request.Properties[OwinContext];
           if (owinContext != null)
           {
               return owinContext.Request.RemoteIpAddress;
           }
       }

        return null;
 }

การอ้างอิงที่จำเป็น:

  • HttpContextWrapper - System.Web.dll
  • RemoteEndpointMessageProperty - System.ServiceModel.dll
  • OwinContext - Microsoft.Owin.dll (คุณจะมีอยู่แล้วหากคุณใช้แพ็คเกจของ Owin)

ปัญหาเล็กน้อยเกี่ยวกับวิธีแก้ไขปัญหานี้คือคุณต้องโหลดไลบรารี่สำหรับทั้ง 3 กรณีเมื่อคุณจะใช้ไลบรารี่เพียงอันเดียวในระหว่างรันไทม์ ตามที่แนะนำที่นี่สิ่งนี้สามารถเอาชนะได้โดยใช้dynamicตัวแปร คุณยังสามารถเขียนGetClientIpAddressวิธีเป็นส่วนขยายHttpRequestMethodได้

using System.Net.Http;

public static class HttpRequestMessageExtensions
{
    private const string HttpContext = "MS_HttpContext";
    private const string RemoteEndpointMessage =
        "System.ServiceModel.Channels.RemoteEndpointMessageProperty";
    private const string OwinContext = "MS_OwinContext";

    public static string GetClientIpAddress(this HttpRequestMessage request)
    {
       // Web-hosting. Needs reference to System.Web.dll
       if (request.Properties.ContainsKey(HttpContext))
       {
           dynamic ctx = request.Properties[HttpContext];
           if (ctx != null)
           {
               return ctx.Request.UserHostAddress;
           }
       }

       // Self-hosting. Needs reference to System.ServiceModel.dll. 
       if (request.Properties.ContainsKey(RemoteEndpointMessage))
       {
            dynamic remoteEndpoint = request.Properties[RemoteEndpointMessage];
            if (remoteEndpoint != null)
            {
                return remoteEndpoint.Address;
            }
        }

       // Self-hosting using Owin. Needs reference to Microsoft.Owin.dll. 
       if (request.Properties.ContainsKey(OwinContext))
       {
           dynamic owinContext = request.Properties[OwinContext];
           if (owinContext != null)
           {
               return owinContext.Request.RemoteIpAddress;
           }
       }

        return null;
    }
}

ตอนนี้คุณสามารถใช้มันได้เช่นนี้:

public class TestController : ApiController
{
    [HttpPost]
    [ActionName("TestRemoteIp")]
    public string TestRemoteIp()
    {
        return Request.GetClientIpAddress();
    }
}

1
โซลูชันนี้ควรใช้เนมสเปซ "System.Net.Http" เพื่อทำงาน เนื่องจากนี่คือชื่อคลาสบน Assembly System.Web.Http.dll, v5.2.2.0
แว็กเนอร์ Bertolini จูเนียร์

@WagnerBertolini ของคุณถูกต้องคุณจะต้องเข้าแถวเพราะคุณกำลังขยายusing System.Net.Http; HttpRequestMessageหากคุณไม่ได้กำหนดนามสกุลของคุณในSystem.Net.Httpเนมสเปซซึ่งเป็นที่น่าสงสัยมาก ไม่แน่ใจว่าเป็นสิ่งจำเป็นเพราะจะถูกเพิ่มโดยอัตโนมัติด้วย IDE หรือเครื่องมือเพิ่มประสิทธิภาพ คุณคิดอย่างไร?
Nikolai Samteladze

ฉันรีบพยายามทำงานให้เสร็จที่นี่และใช้เวลามากกว่า 20 นาทีเพื่อดูว่าเกิดข้อผิดพลาดในการสร้างอะไร ฉันเพิ่งคัดลอกรหัสและสร้างคลาสสำหรับมันเมื่อรวบรวมมันไม่ได้แสดงวิธีการเมื่อฉันใช้ "go to definition" บน VS มันพาฉันไปที่ชั้นเรียนของฉันและฉันก็ไม่เข้าใจว่าเกิดอะไรขึ้นจนกระทั่งฉัน พบชั้นเรียนอื่น ส่วนขยายเป็นคุณสมบัติใหม่ที่สวยและไม่ได้ใช้งานตลอดเวลาเนื่องจากฉันคิดว่ามันจะเป็นความคิดที่ดีที่จะประหยัดเวลานี้
แว็กเนอร์ Bertolini จูเนียร์

1
เมื่อใช้ OWIN คุณสามารถใช้ OwinHttpRequestMessageExtensions เพื่อรับบริบท OWIN เช่น: request.GetOwinContext () Request.RemoteIpAddress
Stef Heyenrath

1
จริง ๆ แล้วควรเป็น var ctx = request.Properties [MsHttpContext] เป็น HttpContextWrapper; E ถ้าคุณแคสต์คุณไม่จำเป็นต้องตรวจสอบโมฆะเพราะหากนักแคลร์ล้มเหลวคุณจะได้รับการยกเว้น
Stef Heyenrath

31

หากคุณต้องการซับในและไม่ได้วางแผนที่จะโฮสต์เว็บ API ด้วยตนเอง:

((System.Web.HttpContextWrapper)Request.Properties["MS_HttpContext"]).Request.UserHostAddress;

13

คำตอบข้างต้นจำเป็นต้องมีการอ้างอิงไปยัง System.Web เพื่อให้สามารถส่งคุณสมบัติไปที่ HttpContext หรือ HttpContextWrapper หากคุณไม่ต้องการการอ้างอิงคุณสามารถรับ IP โดยใช้ไดนามิกได้:

var host = ((dynamic)request.Properties["MS_HttpContext"]).Request.UserHostAddress;

-1

วิธีการแก้ปัญหาของ carlosfigueira ทำงานได้ดีกว่า แต่ปลอดภัยดีกว่า: เพิ่มการusing System.Webเข้าถึงHttpContext.Current.Request.UserHostAddressในวิธีการของคุณ


26
-1 สิ่งนี้ไม่สามารถเชื่อถือได้ใน web api เพราะHttpContext.Currentไม่ได้ยืนยันอย่างถูกต้องตลอดทั้งขั้นตอนงาน เนื่องจากการจัดการคำขอทั้งหมดไม่ตรงกัน HttpContext.Currentควรหลีกเลี่ยงเกือบตลอดเวลาเมื่อเขียนรหัส Web API
Andras Zoltan

@ อังเดรฉันต้องการทราบรายละเอียดเพิ่มเติมว่าทำไมการใช้ HttpContext.Current นั้นไม่ดีคุณรู้จักทรัพยากรที่มีค่าสำหรับสิ่งนี้หรือไม่?
cuongle

13
สวัสดี @CuongLe; ในความเป็นจริง - ในขณะที่ปัญหาเกลียวอาจเป็นปัญหา (แม้ว่าจะไม่ได้โดยตรงถ้าSynchronizationContextไหลอย่างถูกต้องระหว่างงาน); ปัญหาที่ใหญ่ที่สุดคือถ้ารหัสบริการของคุณมีแนวโน้มว่าจะโฮสต์ด้วยตนเอง (ตัวอย่างเช่นการทดสอบ) - HttpContext.Currentเป็นโครงสร้าง Asp.Net ล้วนๆและไม่มีอยู่เมื่อคุณโฮสต์ด้วยตนเอง
Andras Zoltan

ความปลอดภัยประเภทไม่ใช่ทุกอย่าง รหัสนี้จะแสดงให้เห็นถึงการแก้จุดบกพร่องยากNullReferenceExceptionหากใช้จากเธรด (เช่นผู้รอคอยงาน, พบเห็นได้ทั่วไปในรหัส Web API ที่ทันสมัย) หรือในบริบทที่โฮสต์เอง อย่างน้อยที่สุดของคำตอบอื่น ๆ nullก็จะกลับมา
Aaronaught
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.