简体   繁体   中英

Consuming a web service using a different interface

I have a wsdl file that is constructed in an extremely unhelpful way. It is huge,in some cases several megabytes in size, and when I use the various Visual Studio tools to generate a wrapper from it, the resulting codebase is so large that it tends to crash Visual Studio on weaker machines. The compilation time is ludicrous, and the resulting class uses properties where a more dynamic mode of access is absolutely necessary (ie some sort of indexer). There is no option of any changes on the server side.

The wsdl files are far larger than could be processed by hand, and there is an arbitrary number of them. The solution I've employed so far, is to use reflection or late binding with the resulting, auto-generated class. However, since I'm dealing here with a wrapper that wraps what's basically a client for SOAP messages it would make sense if there is another way.

Essentially, I want to create a wrapper that exposes a more dynamic interface, especially where fields are concerned. The task isn't entirely straightforward, so I'm looking for suggestions regarding what to do, and various classes, customizable code generators, WSDL explorers/parsers, etc, that will make the task less time-consuming. Should I construct my own SOAP client? What would I base it on? What .NET features can help me with this task?

You could hand craft an interface that supports a subset of the methods available on the WebService and do away with the need to generate a service reference.

You would have to create the right soap signature for the methods including dto's and namespaces. The downside of this is that you would be forced to manage any changes to the service manually.

Here is a simple example showing a proxy client created with the ISubsetInterface communication with a service exposing the IServiceInterface . To achieve this the Name property has to match the name of the IServiceInterface contract which in this case defaults to "IServiceInterface" but your implementation might require manipulation of the Namespace and Actions. The simplest way to know what you need to manipulate is to look at the generated wsdl.

[TestFixture]
public class When_using_a_subset_of_a_WCF_interface
{
    [Test]
    public void Should_call_interesting_method()
    {
        var serviceHost = new ServiceHost(typeof(Service));

        serviceHost.AddServiceEndpoint( typeof(IServiceInterface), new BasicHttpBinding(), "http://localhost:8081/Service" );
        serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>().IncludeExceptionDetailInFaults = true;

        serviceHost.Open();

        using( var channelFactory = new ChannelFactory<ISubsetInterface>( new BasicHttpBinding(), "http://localhost:8081/Service") )
        {
            var client = channelFactory.CreateChannel();

            client.InterestingMethod().Should().Be( "foo" );
        }

        serviceHost.Close();
    }

    [ServiceContract]
    interface IServiceInterface
    {
        [OperationContract]
        string InterestingMethod();
        [OperationContract]
        string UninterestingMethod();
    }

    [ServiceContract(Name = "IServiceInterface")]
    interface ISubsetInterface
    {
        [OperationContract]
        string InterestingMethod();
    }

    class Service : IServiceInterface
    {
        public string InterestingMethod() { return "foo"; }

        public string UninterestingMethod() { throw new NotImplementedException(); }
    }
}

I suggest to use a shared assembly which contains the DataContracts .

Then use the ChannelFactory<T> class to create an instance of the server Interface. Then you can make calls to the Server without any WSDL.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM