0

I'm attempting to prepare my application code to accept an annual change of a third-party wsdl. I cannot make and have no control over the design of this wsdl. Objects within this wsdl may change, have items added, be removed, etc. However, I still need to keep the previous version(s) of the wsdl.

My plan is to add the current wsdl as a Service Reference, as I did with the previous wsdl.

At the moment, I have multiple methods similar to that below (including the one below).

Using a property, TaxYear to determine which wsdl to actually reference: "Service2015" or "Service2016". I am passing in generic objects representing the objects from the wsdl, and passing in a ref parameter for those objects which I use in a parent method.

Refacotring like this, imposes a LOT of bloat, and I can't help but think there has to be a better way to do what I'm trying to do.

Is there a better way at doing this using C#, or is this the best and most inconvenient way of doing what I need to accomplish.

private static void RetrieveRequestObject(ref object objRequest, object objBusinessHeader, object objSecurityHeader, object objManifestHeader, object objFormData)
{
    if (TaxYear.Equals(2015))
    {
        objRequest = new Service2015.BulkRequestTransmitterRequest()
        {
            ACABusinessHeader = (Service2015.ACABulkBusinessHeaderRequestType)objBusinessHeader,
            Security = (Service2015.SecurityHeaderType)objSecurityHeader,
            ACATransmitterManifestReqDtl = (Service2015.ACATrnsmtManifestReqDtlType)objManifestHeader,
            ACABulkRequestTransmitter = (Service2015.ACABulkRequestTransmitterType)objFormData
        };
    }
    else if (TaxYear.Equals(2016))
    {
        objRequest = new Service2016.BulkRequestTransmitterRequest()
        {
            ACABusinessHeader = (Service2016.ACABulkBusinessHeaderRequestType)objBusinessHeader,
            Security = (Service2016.SecurityHeaderType)objSecurityHeader,
            ACATransmitterManifestReqDtl = (Service2016.ACATrnsmtManifestReqDtlType)objManifestHeader,
            ACABulkRequestTransmitter = (Service2016.ACABulkRequestTransmitterType)objFormData
        };
    }
}
Russ
  • 678
  • 8
  • 26
  • I think service request wise you need to use 2016 version of BulkRequestTransmitterRequest. Even for 2015 year filings. Differentiation by year should be applied only to the "payload" xmls(1094\1095 combinations), which is sent in attachment. – fatherOfWine Nov 17 '16 at 20:49
  • You are correct. Some correspondence with the Web Service owners indicated that the endpoint for transmission will not change. Therefore, I would only have to change the XML for the FormData. My solution for this has been to have a "template" XML document for the FormData necessary for each year. The Web Service owners look at the TaxYear of the Manifest in order to determine which schema they need to check against. I forgot that I posted this, and will update this post by adding an answer. – Russ Nov 18 '16 at 17:59
  • I ended up creating classes out of their xsds, then I populate those classes and serialize them into xmls. – fatherOfWine Nov 18 '16 at 20:47
  • I had done something similar initially I think. This seemed to work okay for TY2015. Then I needed to use one schema for TY2015 and a different one for TY2016. I felt it was easier to (re)create the FormData XML each year, then load and populate that file based on the TaxYear of the Manifest. So far so good. Thanks again for the great assistance in this whole mess of a project. – Russ Nov 21 '16 at 18:09
  • I c. There are million ways to skin the cat.:) U r welcome, buddy. I'm always trying to share my 2 cents, when that seems appropriate.:) – fatherOfWine Nov 28 '16 at 19:46
  • There are definitely a million ways to skin the cat. Thanks for all your help and feedback with this whole thing. I can't tell you how much I have appreciated it. – Russ Nov 28 '16 at 19:53

2 Answers2

0

Try doing something like this, using reflection.

Example:

namespace Stackoverflow
{
    class Program
    {
        static void Main(string[] args)
        {
            int objBusinessHeader = 1,
            objSecurityHeader = 2,
            objManifestHeader = 3,
            objFormData = 4;

            var obj = (IService)RetrieveRequestObject(2010, objBusinessHeader,
                objSecurityHeader,
                objManifestHeader,
                objFormData);

            Console.WriteLine(obj.GetValues());


            var obj2 = (IService)RetrieveRequestObject(2011, objBusinessHeader,
                objSecurityHeader,
                objManifestHeader,
                objFormData);

            Console.WriteLine(obj2.GetValues());

            Console.ReadKey();
        }

        private static object RetrieveRequestObject(int taxYear, object objBusinessHeader,
            object objSecurityHeader, object objManifestHeader, object objFormData)
        {
            var serviceInstance = Activator.CreateInstance("Stackoverflow",
                "Stackoverflow.Service" + taxYear).Unwrap();

            var serviceInstanceType = serviceInstance.GetType();

            var aCABusinessHeaderInfo = serviceInstanceType.GetProperty("ACABusinessHeader");
            var securityInfo = serviceInstanceType.GetProperty("Security");
            var aCATransmitterManifestReqDtlInfo = serviceInstanceType.GetProperty("ACATransmitterManifestReqDtl");
            var aCABulkRequestTransmitterInfo = serviceInstanceType.GetProperty("ACABulkRequestTransmitter");

            aCABusinessHeaderInfo.SetValue(serviceInstance, objBusinessHeader, null);
            securityInfo.SetValue(serviceInstance, objSecurityHeader, null);
            aCATransmitterManifestReqDtlInfo.SetValue(serviceInstance, objManifestHeader, null);
            aCABulkRequestTransmitterInfo.SetValue(serviceInstance, objFormData, null);

            return serviceInstance;
        }
    }

    interface IService
    {
        string GetValues();
    }

    class Service2011 : IService
    {
        public int ACABusinessHeader { get; set; }
        public int Security { get; set; }
        public int ACATransmitterManifestReqDtl { get; set; }
        public int ACABulkRequestTransmitter { get; set; }

        public string GetValues()
        {
            return $@"Service 2011 - {ACABusinessHeader} {Security} {ACATransmitterManifestReqDtl}
                {ACABulkRequestTransmitter}";
        }
    }

    class Service2010 : IService
    {
        public int ACABusinessHeader { get; set; }
        public int Security { get; set; }
        public int ACATransmitterManifestReqDtl { get; set; }
        public int ACABulkRequestTransmitter { get; set; }

        public string GetValues()
        {
            return $@"Service 2010 - {ACABusinessHeader} {Security} {ACATransmitterManifestReqDtl}
                {ACABulkRequestTransmitter}";
        }
    }
}

PS - Might exist a better solution, for now I can't think about any better

user1845593
  • 1,736
  • 3
  • 20
  • 37
  • I did a quick test of this, and my assembly name is `"test project"` and the reference the `CreateInstance` method is looking for is `"test_project.BulkRequestService_" + TaxYear + ".BulkREquestTransmitterRequest"`. It didn't like using the alias for the `using` of `"Service2015"` or `"Service" + TaxYear`. It looks like the `serviceInstance.GetType()` returns an `ObjectHandle` type rather than the type I'm expecting, which I think is BulkRequestTransmitterRequest. – Russ Sep 09 '16 at 15:20
  • Ok, that's normal you have to call Unwrap method. I will update my answer with a full functional example. – user1845593 Sep 10 '16 at 16:13
0

After some correspondence with the Web Service owners, it turns out that I do not have to juggle different endpoints or year-to-year versions of the .wsdl files. Transmission occurs on the same endpoint regardless of year, and in order to validate the schema between years, the owners of the Web Service check the TaxYear element in the Transmission Manifest in order to determine the schema to validate against.

To accommodate this, I have 2 separate XML "template" documents, one for each required Tax Year: 2015 and 2016. My application will then determine which template to use based on the data we are attempting to transmit (via the value for the TaxYear used in the Manifest).

I created these templates from hand based on all of the elements that could be in the Form Data XML. Any repeating element groups only have a singular instance. Multiple instances of these are created within the application.

My application reads the XML Template and replaces the dummy values found within with values retrieved from our data. I remove any unused or invalid elements from the XML dictated by the schema version; and create/clone any elements we have to repeat (such as Part 3 of the 1095-C and 1094-C Forms). So far, this approach appears to be working quite well through initial testing.

Russ
  • 678
  • 8
  • 26