views:

394

answers:

8

I have a scenario in which I'm going to need an arbitrary number of servers to provide the same SOAP web service. I would like to generate one set of proxy classes and be able to supply them with a location to point them at the different servers at runtime. Unfortunately, it looks as though the wsdl:port node (child of wsdl:service) requires the address of a specific server to be hardcoded. It appears that due to this the url will be baked into my proxy classes. I know that I could potentially modify this by hand-editing the generated proxy classes, or modifying the code generation, but I'd really prefer not to resort to that. I feel like there's got to be a better way to solve this problem. I just want to decouple the interface definition from the location that the service will be residing at. I'm using VS2008 and C# .net if that's of any help though best would be a language-agnostic (SOAP or WSDL specific) general solution to this problem.

A: 

When you add a web reference to your project, it places the address of the web service into the .config file of your application / web application. You can then simply change this setting in the config file to point to a different web service location, assuming of course that the services are identical.

NYSystemsAnalyst
I don't think this will work for me since I need to switch the server that I'm talking to at runtime. The config file would seem to restrict me to compile (or at least config) time.
sgibbons
+1  A: 

No, in .NET you can change the url at run time.

Service svc = new Service ();
svc.url = "Value read from config. file or some such"
output = svc.method (input);

nzpcmad
+1  A: 

If you're using a WebReference (pre-WCF) to get to the web service, you can simply set the Url property on the web service proxy class after you create it.

For WCF, you can provide a different endpoint address to the proxy class constructor, rather than using the default (among other possible solutions).

Eric Rosenberger
+1  A: 

Why don't you load balance the web servers and then create a DNS entry for the load balanced IP address....essentially creating a web farm. This will allow you to reference the hostname rather than the static IP addresses and if you ever need to change the IP address of the load balancer or the web servers it is a one time change. Plus you then have redundancy and performance control.

Matt
Exactly what I was going to say. Use a reverse proxy. +1
ConcernedOfTunbridgeWells
A: 

Client proxies have Url property you can set at runtime. To make it simpler, wsdl.exe utility has /appsettingurlkey key. When you generate a client proxy, it's constructor will check the key in appSettings and set the service url accordingly. I believe WCF has this feature as well.

However, I would agree with Matt and suggest you consider load balancing as it's the best solution in the long run.

DreamSonic
A: 

1) Is this for scaling (each server provides the same data) or 2) for same API different data on each server

For two, then you can do as above, just change the service URL in code.

For 1, you could use round robin dns. (eg you see multiple servers with at the command line type 'nslookup www.google.com')

david valentine
A: 

The easiest solution would be to use a software load balancer such as HAProxy. At more cost, you could use a hardware solution such as Big-IP.

John Channing
A: 

Heres a hint how to decide the url i WSDL is done. I´m just changing the port but it´s of course possible to make it more advanced.

public class PortChangeReflector : SoapExtensionReflector
{     
    public override void ReflectDescription()
    {
        ServiceDescription description = ReflectionContext.ServiceDescription;
        foreach (Service service in description.Services)
        {
            foreach (Port port in service.Ports)
            {
                foreach (ServiceDescriptionFormatExtension extension in port.Extensions)
                {
                    SoapAddressBinding binding = extension as SoapAddressBinding;
                    if (binding != null && !binding.Location.Contains("8092"))
                    {
                        binding.Location = binding.Location.Replace("92", "8092");
                    }
                }
            }
        }
    }
}

Put that in your Add_Code and add the following reference to your web.config.

<webServices>
     <soapExtensionReflectorTypes>
          <add type="Dev.PortChangeReflector,App_Code"/>
     </soapExtensionReflectorTypes>
</webServices>

I hope you can get new ideas of this.

Glenn