3

I have a web service that is configured as one way. Or rather, the SoapDocumentMethod attribute has a property that is called "OneWay". That is set to true.

I'm trying to get the IP address of the client request. I get the fact that I won't get the exact IP address because the client may be behind other networking concepts. That's irrelevant. I want an IP address of whoever initiated the call on the service, so if that's some front end server sitting on top of some clients machine, so be it.

I tried using HttpContext, but that doesn't seem to work. If I hit my web service on the same machine as the web service is running, then HttpContext is populated and I can get the IP address. However, any external use of my web service and the HttpContext is a little messed up. It throws exceptions on many of the properties when trying to find out information on the request. So I cannot get the client IP address. If you enable tracing of the service, It then starts working. But that's only a temporary work around. It's not an acceptable solution.

So.. what's the best way to get the client IP address when you have a one way web service?

I've already looked here: http://msdn.microsoft.com/en-us/library/system.web.services.protocols.soapdocumentmethodattribute.oneway.aspx

John Saunders
  • 160,644
  • 26
  • 247
  • 397
OpenIdsAreDumb
  • 95
  • 2
  • 2
  • 4

1 Answers1

2

Luckily, you have some options.

1) Pass the IP address as a parameter --> NOT recommended. 2) Create a SOAP header for the IP Address and pass it from the client

I wrote you a quick sample for option 2.

First, you need to extend SoapHeader and create a class to pass the IP Address.

using System.Web.Services.Protocols;

namespace SoapHeaders
{
    public class IpAddressHeader : SoapHeader
    {
        public string IpAddress;
    }
}

Next, you need to define a web service with that header, and a web method that uses it.

using System;
using System.IO;
using System.Web.Services.Protocols;
using System.Web.Services;
using SoapHeaders;

namespace WebService
{

    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]

    public class SoapHeaderService : System.Web.Services.WebService
    {
        public IpAddressHeader IpAddressHeader;

        [WebMethod]
        [SoapDocumentMethod(OneWay = true)]
        [SoapHeader("IpAddressHeader")]
        public void LogIpAddress()
        {
            var logFile = string.Format(@"C:\Logs\{0:yyyy-MM-dd HH.mm.ss.ffff}.log", DateTime.Now);

            string ipAddress;

            if (IpAddressHeader == null || string.IsNullOrEmpty(IpAddressHeader.IpAddress))
            {
                ipAddress = "?";
            }
            else
            {
                ipAddress = IpAddressHeader.IpAddress;
            }

            File.WriteAllText(logFile, string.Format("Client Address --> {0}", ipAddress));
        }
    }
}

Finally, you need a client to consume the service and pass the header information. I just made a quick console application, but it could be anything, really:

using System.Net;
using ConsoleApplication.soapHeaderServices;

namespace ConsoleApplication
{
    class Program
    {

        static void Main(string[] args)
        {
            var ipAddressHeader = new IpAddressHeader();
            ipAddressHeader.IpAddress = GetIpAddress();

            var serviceClient = new SoapHeaderService();
            serviceClient.IpAddressHeaderValue = ipAddressHeader;

            serviceClient.LogIpAddress();
        }

        static string GetIpAddress()
        {
            var ipAddress = "?";
            var host = Dns.GetHostEntry(Dns.GetHostName());
            foreach (var address in host.AddressList)
            {
                if (address.AddressFamily.ToString() != "InterNetwork")
                {
                    continue;
                }

                ipAddress = address.ToString();
                break;
            }

            return ipAddress;
        }
    }
}

I deployed the service on a remote test service and called it from my PC. Works fine. Contents of the log file created: Client Address --> 192.168.1.41

I hope you find that helpful!

EDIT: DO NOT USE MY BELOW CODE. It is wrong. I'm leaving it as an example of what NOT to do. Server variables are not available in one-way operations.

ORIGINAL ANSWER. DO NOTE USE: See my updated answer above the EDIT.

I just smoke tested this on a new ASP.Net Web Service Application. Works from every endpoint I have access to.

HttpRequest.UserHostAddress is the document way to get the client's IP address. If that is not working for you, I would look for underlying causes.

[WebMethod]
[SoapDocumentMethod(OneWay = true)]
public void Silent()
{
    var address = HttpContext.Current.Request.UserHostAddress;

    // Do something with address
    Trace.Write(address);
}
bopapa_1979
  • 8,949
  • 10
  • 51
  • 76
  • That's fairly close to a test I'm running, and I get an exception thrown trying to access that property. unless I hit the service on the same computer. – OpenIdsAreDumb Oct 18 '13 at 15:56
  • Can you post the error you're getting here? Also, I'd suggest isolating the error to as simple a scenario as possible. Visual Studio --> New Project --> New ASP.Net Web Service Application --> Copy paste the above method and try to hit it remotely. – bopapa_1979 Oct 18 '13 at 16:00
  • The above is pretty much what I'm testing now. It is a new project. And as far as the exception, the property Context.Request.UserHostAddress is null and my code crashes because of that. Also, the property Context.Request.ServerVariables crashes due to argument exception. Doesn't matter what propery you try to access of ServierVariables. ServerVariables[0], ServierVariable.Count even throws an argument exception. Sorry, I did misspeak before. Accessing UserHostAddress doesn't throw the exception. It is just null. – OpenIdsAreDumb Oct 18 '13 at 16:49
  • Updated my answer. The new version will work. The only thing left is to decide how you want to derive you client IP address. You might want to use the public one, rather than the local one, for some reason. For that, look here for some ideas on that: http://stackoverflow.com/questions/3253701/c-sharp-get-public-external-ip-address/3253726#3253726 – bopapa_1979 Oct 18 '13 at 17:42
  • Well, it is an alternate solution. There is not a way to do what you want if the method is marked with [SoapDocumentMethod(OneWay = true)]. Server variables are not available in one-way operations by design. It's the best workable solution you're going to find, I suspect. OR, you could remove the attribute if you don't really need it. – bopapa_1979 Oct 21 '13 at 14:50