How to define the LocalEndPoint to use by a WCF client when calling a WCF service (if the client machine has multiple IP addresses) ?
I have a machine loc开发者_运维问答ated in a DMZ with two IP addresses, the external IP address can be reached through the firewall via a VPN connection from our webserver, located at an external service provider. On this machine runs a WCF and Unity-based custom app server, which should act as proxy or application level gateway (ALG). It shall accept the service calls from the web server and uses a wcf client factory to regenerate the service calls, forwarding them to the real app server in the LAN.
When re-creating the service calls on this proxy using a wcf client factory, the wcf client should use the second, internal IP address of this machine, because only messages coming from this internal IP address will be allowed to pass the firewall to reach the app server in the LAN. Unfortunately our wcf client proxies always choose to create the outgoing messages using the first, "external" IP addresses. I am looking for a way to explicitly setting the IP address to use by the wcf client proxies.
I could find only one WCF binding element that allows the definition of a LocalEndPoint or ClientBaseAddress: CompositeDuplexBindingElement. As far as I understand from the documentation this property is meant to tell the server where to send the asynch reply messages, so it's a different setting than what I am looking for.
Any Idea what I can do to come to a workable solution?
Thanks in advance for any helpful advice!!
This seems to be a similar question, just using TcpClient/Sockets instead of WCF: Specify the outgoing IP address to use with TCPClient / Socket in C#
And another one, this time regarding a SoapClient: Binding a new SoapClient to a specific IP address before sending outgoing request
Had a hard time finding the answer to this one myself, so i'll share my solution in case someone else comes by here.
Below is a method that returns a wcf soapservice. The code will try to use a specific ip if available. I did this check to have it working on a test machine as well.
public static proposalSoapClient getService()
{
string serviceurl = "http://somesite.dk/proposal.asmx";
var localIpAddress = IPAddress.Parse("123.123.123.123");
var hasLocalAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Any(ip => ip.AddressFamily == AddressFamily.InterNetwork && ip.Equals(localIpAddress));
var binding = new System.ServiceModel.BasicHttpBinding("proposalSoap"); //name of binding in web.config
var endpoint = new EndpointAddress(serviceurl);
ServicePoint servicePoint = ServicePointManager.FindServicePoint(new Uri(serviceurl));
servicePoint.BindIPEndPointDelegate = (sp, rm, retryCount) => { return new IPEndPoint(hasLocalAddress ? localIpAddress : IPAddress.Any, 0); };
return new proposalSoapClient(binding, endpoint);
}
Also when i am on the test server i had to use a proxy to get to the service. (i used fiddler as proxy on the machine that had access to the service). Below is the same code but with added section for proxy when on the test server.
public static proposalSoapClient getService()
{
string serviceurl = "http://somesite.dk/proposal.asmx";
var localIpAddress = IPAddress.Parse("123.123.123.123");
var hasLocalAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList.Any(ip => ip.AddressFamily == AddressFamily.InterNetwork && ip.Equals(localIpAddress));
var binding = new System.ServiceModel.BasicHttpBinding("proposalSoap"); //name of binding in web.config
var endpoint = new EndpointAddress(serviceurl);
ServicePoint servicePoint = ServicePointManager.FindServicePoint(new Uri(serviceurl));
#if DEBUG
Uri proxyUri = new Uri("http://someothersite.dk:8888");
binding.ProxyAddress = proxyUri;
binding.BypassProxyOnLocal = false;
binding.UseDefaultWebProxy = false;
servicePoint = ServicePointManager.FindServicePoint(serviceurl, new WebProxy(proxyUri, false));
#endif
servicePoint.BindIPEndPointDelegate = (sp, rm, retryCount) => { return new IPEndPoint(hasLocalAddress ? localIpAddress : IPAddress.Any, 0); };
return new proposalSoapClient(binding, endpoint);
}
This is an older thread, but I have a suggestion for anyone finding this one as it lead me to track down a slightly different solution. We have two processes that we needed to run on separate processes on the same server.
The issue was each by default chose the primary address that was bound to the NIC. We couldn't find a way to get the app to bind to a secondary address on the NIC.
The workaround was to add a second NIC to the VM, move the secondary IP to the second NIC as the primary IP of the 2nd NIC. In Windows, you cannot have two default gateways (even if they point to the same address).
So, on the 2nd NIC, we assigned the IP and the Subnet Mask only. To get the traffic to route out the proper interface, we added a route statement in the format of:
route add 4.3.2.1 mask 255.255.255.255 1.2.3.4 IF 0x10002
Where the host we needed the process to talk to is 4.3.2.1
, the local Default Gateway is 1.2.3.4
and the second NIC shows up in the routing table as interface number 0x10002
(from route print).
I hope this helps. I have a few more grey hairs because of this one.
Sounds like the routing tables are a little messed up on the server for what you want to do. Instead of trying to correct for it in the app, tweak the interface metrics and or routing tables on the machine to prefer the internal interface for traffic destined for that network. Here is an old reference, but should be more or less valid.
I don't think .NET sockets will allow you to explicitly choose a source interface- closest thing would be the DontRoute SocketOption, but even there, you'd probably have to roll a custom binding and transport to have that option available.
精彩评论