When invoking a Web Service from C# (where the external service might be WCF, ASMX, Java, etc. - you just don't know), it is common practice to point your modern development tool of choice (Visual Studio in my case) at the service's WSDL to generate a proxy class for calling the service. You can also create a proxy "by hand" using CreateChannel. This code review posting is to seek feedback on a simple proxy class built using CreateChannel. A couple of supporting classes are shown for completeness & context.
Interface for Service & Proxy:
This interface is also passsed to ChannelFactory.
public interface IService
{
ServiceResponse DoSomething(ServiceRequest request);
}
Example usage:
var proxy = new ServiceProxy("http://123.45.67.89/foo");
var request = new ServiceRequest { Number = 33, Name = "Larry Bird" };
ServiceResponse response = proxy.DoSomething(request);
Code of interest: - Any comments/improvements/feedback appreciated
For readers wondering about the use of factory.Abort in the finally block, see answer to this question. Regarding the following casting business (which appears twice): ((IClientChannel)service).Close(); see MSDN document on How To: Use the ChannelFactory which demonstrates its use. The two are hacks that appear to be related and date from early WCF/Indigo days.
public class ServiceProxy : IService
{
public string EndpointUrl { get; set; }
public ServiceProxy(string endpointUrl) { EndpointUrl = endpointUrl; }
public ServiceResponse DoSomething(ServiceRequest request)
{
Contract.Requires(request != null);
Contract.Requires(! String.IsNullOrEmpty(EndpointUrl));
var endpointAddress = new EndpointAddress(EndpointUrl);
ChannelFactory<IService> factory = null;
IService service = null;
try
{
// Just picking a simple binding here to focus on other aspects
Binding binding = new BasicHttpBinding();
#if DEBUG // boost timeouts, otherwise can cause lots of timeouts in the debugger
binding.SendTimeout = binding.ReceiveTimeout = TimeSpan.FromMinutes(10);
#endif
factory = new ChannelFactory<IService>(binding);
service = factory.CreateChannel(endpointAddress);
if (service == null)
{
throw new CommunicationException(
String.Format("Unable to connect to service at {0}", endpointUrl));
}
ServiceResponse response = service.DoSomething(request);
((IClientChannel)service).Close();
service = null;
factory.Close();
factory = null;
return response;
}
finally
{
if (service != null) ((IClientChannel)service).Close();
if (factory != null) factory.Abort();
}
}
}
Supporting Objects (for completeness)
Not much of interest in ServiceRequest and ServiceResponse classes, other than this is the prevailing style of calling services - one object in, one object out.
public class ServiceRequest // stuff we send to the service
{
public int Number { get; set; }
public string Name { get; set; }
}
public class ServiceResponse // stuff we get back from the service
{
public int SomeStat { get; set; }
public string SomeString { get; set; }
}