How can I make multiple SOAP web service calls generic to reduce redundancy?

netsuite suitetalk examples
rest api response best practices
rest api response format best practices
rest api design example
rest api best practices 2019
rest api example
restful api design tutorial
rest api payload example

I have these methods below that call some SOAP web services, all from the same provider, so they all have the same methods/calls/etc. I'm looking for a more OOP/abstract way to call these without writing so many methods? Ideally I'd like one method for each -> GetClaim(), AddClaim(), SearchClaim(), RemoveClaim(), etc.

Question - Should I pass in the parameters specific to the service to make the method more generic, there by eliminating 15 other methods all like this or is there a better more oop/abstract approach? Can somebody please provide me with an example?

    // ex. how can I make these two methods 1?
    public async void ClaimSearchForWRG(string url, string userName, string password) {
        var client = new WebServiceWRGClient(); 
        var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        var endpoint = new EndpointAddress(url); 
        var channelFactory = new ChannelFactory<WebServiceWRG>(binding, endpoint); 
        var webService = channelFactory.CreateChannel();
        var user = new User(); 
        user.UserName = await webService.EncryptValueAsync(userName);
        user.Password = await webService.EncryptValueAsync(password);
        var response = await client.ClaimSearchAsync(user, "", "", 12345, statuscode.NotSet, "");
    }

    // another call (same provider) with the same call ->  ClaimSearchAsync()
    public async void ClaimSearchForAWI(string url, string userName, string password) {
        var client = new WebServiceAWIClient(); 
        var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        var endpoint = new EndpointAddress(url); 
        var channelFactory = new ChannelFactory<WebServiceAWI>(binding, endpoint); 
        var webService = channelFactory.CreateChannel();
        var user = new ArmUser(); 
        user.UserName = await webService.EncryptValueAsync(userName);
        user.Password = await webService.EncryptValueAsync(password);
        var response = await client.ClaimSearchAsync(user, "", "", 12345, ArmStatuscode.NotSet, "");
    }
    // then we have 15 other web service calls from the same provider for ClaimSearchAsync()
    // then we have 15 more calls for ClaimGetAsync()
    // then we have 15 more calls for AddClaimAsync()
    // then we have 15 more calls for RemoveClaimAsync()
    // etc, etc, etc

UPDATED After trying this code below to make things a little more generic (to eliminate redundancy) I'm getting some errors in the code. Specifically related to the compiler not finding the properties associated with the generic entities I'm passing into the method. ex. user.Username is not found -> error message says "'TTwo' does not contain a definition for 'UserName'"

    public class Test {
        public void TestWebService() {
            var ws = new WebService<WebServiceWRG>();
            ws.SearchClaim(new WebServiceWRGClient(), new GraceUser(), 
                "https://trustonline.delawarecpf.com/tows/webservicewrg.svc", "userName", "password");  
        }
    }

    public class WebService<T> {             
        public void SearchClaim<TOne, TTwo>(TOne entity1, TTwo entity2, string url, string userName, string password) 
            where TOne : class
            where TTwo : class
        {
            var client = entity1;
            var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
            var endpoint = new EndpointAddress(url);
            var channelFactory = new ChannelFactory<T>(binding, endpoint);
            var webService = channelFactory.CreateChannel();
            var user = entity2;
            user.UserName = webService.EncryptValue(userName);
            user.Password = webService.EncryptValue(password);
            var response = client.ClaimSearch(user, "", "", 12345, GraceStatuscode.NotSet, "");
        }
    }

UPDATED I was asked to show what "ClaimSearchAsync" does or what it is. I copied this from the web service reference file that was generated from dotnet

System.Threading.Tasks.Task<GRACE_GRACES.WebServiceResult> ClaimSearchAsync(GRACE_GRACES.User user, string ssn, string lastname, int claimnumber, GRACE_GRACES.statuscode statuscode, string assignedto);

as this is a web service, there is no method or code behind that shows what it does.

The provided example methods all violate Single Responsibility Principle (SRP) and Separation of Concerns (SoC) so that is where I started in trying to make them more generic.

The creation of the service and service client should be abstracted out into their own concerns

For example, the web services can be created via a generic factory abstraction

public interface IWebServiceFactory {
    TWebService Create<TWebService>(string uri);
}

and simple implementation which encapsulates the creation of the channel factory using the provided URL.

public class ServiceFactory : IWebServiceFactory {
    public TWebService Create<TWebService>(string url) {
        var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport) {
            MaxReceivedMessageSize = Int32.MaxValue,
            MaxBufferSize = Int32.MaxValue
        };
        var endpoint = new EndpointAddress(url);
        var channelFactory = new ChannelFactory<TWebService>(binding, endpoint);
        TWebService webService = channelFactory.CreateChannel();
        return webService;
    }
}

The service clients' creation can also be abstracted out into it own concern.

public interface IClientFactory {
    TClient Create<TClient>() where TClient : class, new();
}

to be implemented based on the common definition of your clients.

Now for the creation of a generic client you need to take the common functionality expected from the types involved with the member to be invoked.

This can allow for a convention to be used for the expected types. Dynamic expressions were used to construct the conventions applied.

Resulting in the following helpers for the SearchClaimAsync

static class ExpressionHelpers {

    public static Func<string, string, TUserResult> CreateUserDelegate<TUserResult>() {
        var type = typeof(TUserResult);
        var username = type.GetProperty("username", BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
        var password = type.GetProperty("password", BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
        //string username =>
        var usernameSource = Expression.Parameter(typeof(string), "username");
        //string password =>
        var passwordSource = Expression.Parameter(typeof(string), "password");
        // new TUser();
        var user = Expression.New(type);
        // new TUser() { UserName = username, Password = password }
        var body = Expression.MemberInit(user, bindings: new[] {
            Expression.Bind(username, usernameSource),
            Expression.Bind(password, passwordSource)
        });
        // (string username, string password) => new TUser() { UserName = username, Password = password }
        var expression = Expression.Lambda<Func<string, string, TUserResult>>(body, usernameSource, passwordSource);
        return expression.Compile();
    }

    public static Func<TService, string, Task<string>> CreateEncryptValueDelegate<TService>() {
        // (TService service, string name) => service.EncryptValueAsync(name);
        var type = typeof(TService);
        // TService service =>
        var service = Expression.Parameter(type, "service");
        // string name =>
        var name = Expression.Parameter(typeof(string), "name");
        // service.EncryptValueAsync(name)
        var body = Expression.Call(service, type.GetMethod("EncryptValueAsync"), name);
        // (TService service, string name) => service.EncryptValueAsync(name);
        var expression = Expression.Lambda<Func<TService, string, Task<string>>>(body, service, name);
        return expression.Compile();
    }

    public static Func<TClient, TUser, Task<TResponse>> CreateClaimSearchDelegate<TClient, TUser, TResponse>() {
        var type = typeof(TClient);
        // TClient client =>
        var client = Expression.Parameter(type, "client");
        // TUser user =>
        var user = Expression.Parameter(typeof(TUser), "user");
        var method = type.GetMethod("ClaimSearchAsync");
        var enumtype = method.GetParameters()[4].ParameterType; //statuscode
        var enumDefault = Activator.CreateInstance(enumtype);
        var arguments = new Expression[] {
            user,
            Expression.Constant(string.Empty), //ssn
            Expression.Constant(string.Empty), //lastname
            Expression.Constant(12345), //claimnumber
            Expression.Constant(enumDefault), //statuscode
            Expression.Constant(string.Empty)//assignto
        };
        // client.ClaimSearchAsync(user, ssn: "", lastname: "", claimnumber: 12345, statuscode: default(enum), assignedto: "");
        var body = Expression.Call(client, method, arguments);
        // (TClient client, TUser user) => client.ClaimSearchAsync(user,....);
        var expression = Expression.Lambda<Func<TClient, TUser, Task<TResponse>>>(body, client, user);
        return expression.Compile();
    }
}

Take some time to review the comments to get a better understanding of what is being done.

The generic web service can then be defined as follows

public class WebService<TWebServiceClient, TWebService, TUser>
    where TWebService : class
    where TWebServiceClient : class, new()
    where TUser : class, new() {

    /// <summary>
    /// Create user object model
    /// </summary>
    private static readonly Func<string, string, TUser> createUser =
        ExpressionHelpers.CreateUserDelegate<TUser>();
    /// <summary>
    /// Encrypt provided value using <see cref="TWebService"/>
    /// </summary>
    private static readonly Func<TWebService, string, Task<string>> encryptValueAsync =
        ExpressionHelpers.CreateEncryptValueDelegate<TWebService>();

    private readonly IWebServiceFactory serviceFactory;
    private readonly IClientFactory clientFactory;
    Lazy<TWebServiceClient> client;

    public WebService(IWebServiceFactory serviceFactory, IClientFactory clientFactory) {
        this.serviceFactory = serviceFactory ?? throw new ArgumentNullException(nameof(serviceFactory));
        this.clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));
        client = new Lazy<TWebServiceClient>(() => clientFactory.Create<TWebServiceClient>());
    }

    public async Task<TResponse> SearchClaimAsync<TResponse>(WebServiceOptions options) {
        TWebService webService = serviceFactory.Create<TWebService>(options.URL);
        TUser user = createUser(
            await encryptValueAsync(webService, options.UserName),
            await encryptValueAsync(webService, options.Password)
        );
        Func<TWebServiceClient, TUser, Task<TResponse>> claimSearchAsync =
            ExpressionHelpers.CreateClaimSearchDelegate<TWebServiceClient, TUser, TResponse>();
        TResponse response = await claimSearchAsync.Invoke(client.Value, user);
        return response;
    }

    //...other generic members to be done
}

public class WebServiceOptions {
    public string URL { get; set; }
    public string UserName { get; set; }
    public string Password { get; set; }
}

The code it self is decoupled enough from implementation concerns to allow for it to be tested in isolation to ensure that it behaves as expected.

As demonstrated in the following unit tested

[TestClass]
public class GenericWebServiceTests {
    [TestMethod]
    public void Should_Create_New_WebService() {
        //Arrange
        var serviceFactory = Mock.Of<IWebServiceFactory>();
        var clientFactory = Mock.Of<IClientFactory>();

        //Act
        var actual = new WebService<WebServiceWRGClient, IWebService, User1>(serviceFactory, clientFactory);

        //Assert
        actual.Should().NotBeNull();
    }

    [TestMethod]
    public async Task Should_ClaimSearchAsync() {
        //Arrange

        var service = Mock.Of<IWebService>();
        Mock.Get(service)
            .Setup(_ => _.EncryptValueAsync(It.IsAny<string>()))
            .ReturnsAsync((string s) => s);

        var serviceFactory = Mock.Of<IWebServiceFactory>();
        Mock.Get(serviceFactory)
            .Setup(_ => _.Create<IWebService>(It.IsAny<string>()))
            .Returns(service);

        var clientFactory = Mock.Of<IClientFactory>();
        Mock.Get(clientFactory)
            .Setup(_ => _.Create<WebServiceWRGClient>())
            .Returns(() => new WebServiceWRGClient());

        string url = "url";
        string username = "username";
        string password = "password";

        var options = new WebServiceOptions {
            URL = url,
            UserName = username,
            Password = password
        };

        var webService = new WebService<WebServiceWRGClient, IWebService, User1>(serviceFactory, clientFactory);

        //Act
        var actual = await webService.SearchClaimAsync<WebServiceResult>(options);

        //Assert
        //Mock.Get(serviceFactory).Verify(_ => _.Create<IService1>(url));
        //Mock.Get(service).Verify(_ => _.EncryptValue(username));
        //Mock.Get(service).Verify(_ => _.EncryptValue(password));
        //Mock.Get(clientFactory).Verify(_ => _.Create<Client1>());
        actual.Should().NotBeNull();
    }

    #region Support

    public class User1 {
        public string UserName { get; set; }
        public string Password { get; set; }
    }

    public class User2 {
        public string UserName { get; set; }
        public string Password { get; set; }
    }

    public class WebServiceWRGClient {
        public Task<WebServiceResult> ClaimSearchAsync(User1 user, string ssn, string lastname, int claimnumber, statuscode statuscode, string assignedto) {
            return Task.FromResult(new WebServiceResult());
        }
    }

    public enum statuscode {
        NotSet = 0,
    }

    public class Client2 { }

    public interface IWebService {
        Task<string> EncryptValueAsync(string value);
    }

    public interface IService2 {
        Task<string> EncryptValueAsync(string value);
    }

    public class Service1 : IWebService {
        public Task<string> EncryptValueAsync(string value) {
            return Task.FromResult(value);
        }
    }

    public class WebServiceResult {

    }
    #endregion
}

This should be enough to get you started in reviewing the other members to be made generic. The above provided code has been tested and works as expected based on what was provided in the original question.

Do note that this does seem like a large task depending on the amount of members to be refactored. You should take some time to make sure the effort is even worth it.

Hottest 'svcutil.exe' Answers, can I make multiple SOAP web service calls generic to reduce redundancy? To generate code run svcutil /t:metadata [yourfiles], which will create wsdl/xsd  The provided example methods all violate Single Responsibility Principle (SRP) and Separation of Concerns (SoC) so that is where I started in trying to make them more generic. The creation of the service and service client should be abstracted out into their own concerns. For example, the web services can be created via a generic factory

You have classical Divergent Change smell here.

Signs and Symptoms. You find yourself having to change many unrelated methods when you make changes to a class. For example, when adding a new product type you have to change the methods for finding, displaying, and ordering products.

I suggest to make refactoring to Abstract Factory pattern. You will separate web service and object creation logic.

Abstract Factory is a creational design pattern that lets you produce families of related objects without specifying their concrete classes.

So you will have something like:

And some code:

    public interface IFactory
    {
        Client CreateClient();
        User CreateUser();
        Channel CreateChannel(BasicHttpBinding binding, EndpointAddress endpoint);
    }

    abstract public class AbstractFactory<T> : IFactory
    {
        public abstract Client CreateClient()
        public abstract User CreateUser();
        public Channel CreateChannel(BasicHttpBinding binding, EndpointAddress endpoint)
        {
            var channelFactory = new ChannelFactory<T>(binding, endpoint);
            return channelFactory.CreateChannel();
        }
    }

    public class AWIFactory : AbstractFactory<WebServiceAWI>
    {
        public override Client CreateClient()
        {
            return new WebServiceAWIClient();
        }

        public override User CreateUser()
        {
            return new ArmUser();
        }
    }

    public class WRGFactory : AbstractFactory<WebServiceWRG>
    {
        public override Client CreateClient()
        {
            return new WebServiceWRGClient();
        }

        public override User CreateUser()
        {
            return new User();
        }
    }

    public class WebService
    {
        private readonly IFactory _factory;

        public WebService(IFactory factory)
        {
            _factory = factory;
        }

        public async void ClaimSearchAsync(string url, string userName, string password)
        {
            var client = _factory.CreateClient();
            var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
            var endpoint = new EndpointAddress(url);
            var channel = _factory.CreateChannel(binding, endpoint);
            var user = _factory.CreateUser();
            user.UserName = await channel.EncryptValueAsync(userName);
            user.Password = await channel.EncryptValueAsync(password);
            var response = await client.ClaimSearchAsync(user, "", "", 12345, statusCode, "");
        }

        ...
    }

And here is how you create WebService:

var wrgWebService = new WebService(new WRGFactory());

Best practices for REST API design, REST APIs are one of the most common kinds of web services multiple ways a networked application can break, we should make and then we can call the res​.json method with the object that we want to 500 Internal server error – This is a generic server error. This site uses Akismet to reduce spam. How can I make multiple SOAP web service calls generic to reduce redundancy? The provided example methods all violate Single Responsibility Principle (SRP) and Separation of Concerns (SoC) so that is where I started in trying to make them more generic.

I did something similar when I had several different soap endpoints, where every endpoint had some types that were completely the same, only with a different class name. Automatically generated classes contain the partial modifier, which enables you to add additional logic to the generated class.

In your case:

"'TTwo' does not contain a definition for 'UserName'"

You have to create an interface that contains a property Username and a property Password:

public interface IUser {
    string UserName { get; }
    string Password { get; }
}

public partial User : IUser { }  //must be in the correct namespace for partial to work
public partial ArmUser : IUser { } //must be in the correct namespace for partial to work

public class Test {
    public void TestWebService() {
        var ws = new WebService<WebServiceWRG>();
        ws.SearchClaim(new WebServiceWRGClient(), new GraceUser(), 
            "https://trustonline.delawarecpf.com/tows/webservicewrg.svc", "userName", "password");  
    }
}

public class WebService<T> {             
    public void SearchClaim<TOne, TTwo>(TOne entity1, TTwo entity2, string url, string userName, string password) 
        where TOne : class
        where TTwo : IUser  // limits the TTwo class to implement IUser
    {
        var client = entity1;
        var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        var endpoint = new EndpointAddress(url);
        var channelFactory = new ChannelFactory<T>(binding, endpoint);
        var webService = channelFactory.CreateChannel();
        var user = entity2;
        user.UserName = webService.EncryptValue(userName);
        user.Password = webService.EncryptValue(password);
        var response = client.ClaimSearch(user, "", "", 12345, GraceStatuscode.NotSet, "");
    }
}

Instead of passing TTwo, you can then also add the new modifier to the TTwo condition (where T : TTwo, new()), then you can generate an instance of TTwo inside the SearchClaim function, which would make it look like the following:

public interface IUser {
    string UserName { get; set; }
    string Password { get; set; }
}

public partial User : IUser { }  //must be in the correct namespace for partial to work
public partial ArmUser : IUser { } //must be in the correct namespace for partial to work

public class Test {
    public void TestWebService() {
        var ws = new WebService<WebServiceWRG>();
        ws.SearchClaim(new WebServiceWRGClient(), new GraceUser(), 
            "https://trustonline.delawarecpf.com/tows/webservicewrg.svc", "userName", "password");  
    }
}

public class WebService<T> {             
    public void SearchClaim<TOne, TTwo>(TOne entity1, string url, string userName, string password) 
        where TOne : class
        where TTwo : IUser, new()  // limits the TTwo class to implement IUser
    {
        var client = entity1;
        var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
        var endpoint = new EndpointAddress(url);
        var channelFactory = new ChannelFactory<T>(binding, endpoint);
        var webService = channelFactory.CreateChannel();
        var user = new TTwo();
        user.UserName = webService.EncryptValue(userName);
        user.Password = webService.EncryptValue(password);
        var response = client.ClaimSearch(user, "", "", 12345, GraceStatuscode.NotSet, "");
    }
}

You might also have to make some interface for your TOne, but you should be able to figure that out on your own.

3 Understanding Web Service Security Concepts, This chapter describes the concepts behind Web services security. This section primarily describes Web services over SOAP. and validation, and identity propagation across multiple Web services used to complete a single transaction. It is sufficient to have the root certificate in the keystore to verify the certificate chain  The APEX_WEB_SERVICE package enables you to integrate other systems with Oracle Application Express by allowing you to interact with Web services anywhere you can use PL/SQL in your application. The API contains procedures and functions to call both SOAP and RESTful style Web services.

Not sure how is your code structure, but I'll just focus on the provided sample.

From what I've seen, if this method and the other related methods are used in different classes, I would suggest to create a class that will handle it, and then use this class instead of the methods. But if this method and other related methods are used in a specific class, I would recommend to create a generic methods that will substitute the redundant methods. You'll need to compare all related methods first, and get the common numerator between them, make this a start point for your generic approach.

Here is untested example (based on what I understood from your sample) :

public class CallWebService<T> // don't forget to inherit IDisposal.
{

    private WebServiceWRGClient Client {get; set;}

    private BasicHttpBinding HttpBinding {get; set;}

    private EndpointAddress  Endpoint {get; set;}

    private ChannelFactory Channel {get; set;}

    // if needed outside this class, make it public to be accessed globally. 
    private User UserAccount {get; set;}

    public CallWebService<T>(string url)
    {
        Client      = new WebServiceWRGClient(); 

        //See which Binding is the default and use it in this constructor. 
        HttpBinding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);

        Endpoint    = new EndpointAddress(url); 

        // T is generic, WebServiceWRG in this example 
        Channel     = new ChannelFactory<T>(HttpBinding, Endpoint).CreateChannel();

        UserAccount = new User();
    }

    // another constructor with BasicHttpBinding
    public CallWebService<T>(string url, BasicHttpSecurityMode securityMode)
    {
        Client      = new WebServiceWRGClient(); 

        //See which Binding is the default and use it in this constructor. 
        HttpBinding = new BasicHttpBinding(securityMode);

        Endpoint    = new EndpointAddress(url); 

        // T is generic, WebServiceWRG in this example 
        Channel     = new ChannelFactory<T>(HttpBinding, Endpoint).CreateChannel();

        UserAccount = new User();

    }

    // Change this method to return the response. Task<Response> is just a placeholder for this example 
    public async Task<Response> Call(string userName, string password)
    {
        UserAccount.UserName = await Channel.EncryptValueAsync(userName);

        UserAccount.Password = await Channel.EncryptValueAsync(password);

        var response = await Client.ClaimSearchAsync(User, "", "", 12345, statuscode.NotSet, "");       
    }

    /*
        [To-Do] : gather all other releated methods into this class, then try to simplify them. 

    */

}

You can also configure the constructors as needed, for instance, you can make constructors that takes WebServiceWRGClient and BasicHttpBinding ..etc. So, it's more open to you.

You could do similar approach if it'll be used across the project, but if it's only used in one class, then you could do something like this :

// Configure it as needed, but avoid using `void` with async, as the exceptions in sync and async methods handled differently. 
// Also, try to make sense here, make the method return the results.
public async Task CallWebService<T>(WebServiceWRGClient client,  string url, string userName, string password) 
{

    var channelFactory = new ChannelFactory<T>(new BasicHttpBinding(BasicHttpSecurityMode.Transport, new EndpointAddress(url)).CreateChannel(); 
    var user = new User(); // coming from service reference

    user.UserName = await channelFactory.EncryptValueAsync(userName);
    user.Password = await channelFactory.EncryptValueAsync(password);
    var response  = await client.ClaimSearchAsync(user, "", "", 12345, statuscode.NotSet, "");
}

[PDF] SuiteTalk SOAP Web Services Platform Guide, Support Has Ended for SOAP Web Services 2009.2 and Earlier Endpoints . The governance limit for concurrent requests is based on the service tier I have multiple user accounts being used for concurrent SOAP web services based on If you are building a generic SOAP web services application,  This is a Java, SSL-based client which facilitates both RESTFul and SOAP web service calls to different servers. To better understand the topic at hand, you should also have knowledge of the below

[PDF] Guide to secure web services, The following sections discuss several Web services security challenges in redundancy can ensure access to critical data in the event of a fault. In most Web services, there are two types of SOAP messages: requests and responses.7 The SAML specification defines a framework for creating and exchanging generic  Denis Zakharov. Senior Developer at BSS 1 Nested for Loops to Make a Triangle Pattern in Python Sep 27 '19. 0 How can I make multiple SOAP web service calls

SOAP Web Service Sources, Create a base view to sends requests to its operations. Importing SOAP Web Service Sources¶. To create a new Web service data source, right-click on a  If you read Producing a SOAP web service, you might wonder why this guide does not use spring-boot-starter-ws? That Spring Boot starter is only for server-side web services. That starter brings on board such things as embedded Tomcat, which is not needed to make a web call.

gSOAP user guide, These stand-alone Web Services handle multiple SOAP requests by spawning a thread The latter approach does not use C++ namespaces and actually reduces the overall This option generates less documentation by removing generic @note However, the use of SOAP_ENC XML types is obsolete and redundant  Introduction. This article takes you through the basics of submitting a Enterprise Scheduler Service job request using a web service call. This may be useful for various functional requirements, such as kicking-off specific processes, run extract or import jobs, or to generating BI Publisher reports.

Comments
  • In order for you to know what "ClaimSearch()" does or what the "client" object is you'll have to look at the web service "trustonline.delawarecpf.com/tows/webservicewrg.svc" and what it generates when you add it as a web service to your project. Unless there is another way to show you, that's the only way I know. But I will post what I see in the web service file that gets generated.
  • you have to say that entity two has the properties UserName and Password -> either by defining a base class or by assigning an interface that has the two properties. If your TTwo is generated by the soap interface, it has the partial modifier -> you can simply add another file with the same partial class (=same namespace and name, different file name) and add the interface to your partial calss.
  • This might be useful Source
  • hi Nkosi. thanks for all the help. It's going to take me some time to look over this and understand it. I'll be working on it tomorrow as it's Sunday night and I'm pretty tired. I'll let you know if there are any problems and if it's what I need and helped me. Either way I'll prob award you the points for the detailed response.
  • So your second idea is where I'm at, with just one class, but here's where you are incorrect and where I need help. The "User" class is different for each of the different services, so that would have to be passed into the method and you're trying to pass in "WebServiceWRGClient" which is service specific as well (ex. WebServiceWRGClient, WebServiceAMIClient, WebServiceFCCClient), so that would need to be generic too.
  • @user1186050, use the class, and implemented as CallWebService<T1, T2, T3> add as much Ts as you want to pass into the class. You can rename the Ts to something meaningful like TWRGClient, TUser, T...etc