Uncategorized

Modifying a SOAP request on the client

Backstory: I’m connecting to a dinosaur of an ASMX webservice. It’s been working fine, but all of a sudden they tell us they are implementing 2FA on their service. Now, their service takes in and responds with XML that is encoded inside of a SOAP envelope. Had they included those things in the XML, I would have finished the changes in 30 minutes and washed my hands of the whole thing… but they needed it in the header.

This kind of stuff is easy with WCF, but you really have to work to modify the SOAP envelope in ASMX. Here’s my template, to save you some time in doing this in the future. You will have to open up reference.cs in your ASMX client code and add the attribute to the methods you want the output to be transformed.

Also check out https://www.hanselman.com/blog/ASMXSoapExtensionToStripOutWhitespaceAndNewLines.aspx for more details. That one is more of a server-side implementation but it did help me out.

 

    public class TransformSomethingExtension : SoapExtension
    {
        private Stream newStream;
        private Stream oldStream;
        string BodyString;

        public override object GetInitializer(Type serviceType)
        {
            return typeof(TransformSomethingExtension);
        }

        public override object GetInitializer(LogicalMethodInfo methodInfo, SoapExtensionAttribute attribute)
        {
            return attribute;
        }

        public override void Initialize(object initializer)
        {
            // get attribute
            TransformSomethingAttribute attr = initializer as TransformSomethingAttribute;
        }

        public override void ProcessMessage(SoapMessage message)
        {
            switch (message.Stage)
            {
                case SoapMessageStage.AfterSerialize:
                    Transform();
                    break;
                case SoapMessageStage.AfterDeserialize:
                    break;
                case SoapMessageStage.BeforeDeserialize:
					// You need this because you're using the new stream as the main stream now. 
					// I left this out at first, and it caused me a lot of headache to figure it out.
                    oldStream.CopyTo(newStream);
                    newStream.Position = 0L;
                    break;
                case SoapMessageStage.BeforeSerialize:
                    break;
                default:
                    break;
            }
        }

        public override Stream ChainStream(Stream stream)
        {
            this.oldStream = stream;
            this.newStream = new MemoryStream();
            return this.newStream;
        }

        void Transform()
        {
            newStream.Position = 0L;
            TextReader reader = new StreamReader(newStream);
            BodyString = reader.ReadToEnd();

            // This is where you transform BodyHeader as a string to what you need

            newStream.Position = 0L;
            newStream.SetLength(BodyString.Length);
            TextWriter writer = new StreamWriter(oldStream);
            writer.WriteLine(BodyString);
            writer.Flush();

            //oldStream.Position = 0L;
            
        }


    }


    [AttributeUsage(AttributeTargets.Method)]
    public class TransformSomethingAttribute : SoapExtensionAttribute
    {
        // Fields
        private int priority;

        // Properties
        public override Type ExtensionType
        {
            get { return typeof(TransformSomethingExtension); }
        }

        public override int Priority
        {
            get { return this.priority; }
            set { this.priority = value; }
        }
    }
Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s