ServiceHost responding with different XML

Rada Matěj 200 Reputation points
2023-08-30T16:41:24.4366667+00:00

IIS ASMX is responding with whole document:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <soap:Body>
        <eTimeServiceResponse xmlns="http://anet.eu/webservices">
            <eTimeServiceResult>ACA41A510200160000000000000000005BDFA1E076E2D3B3FD15F6DCF79F12B103F48C8955B3992FFE604FB79F703568</eTimeServiceResult>
        </eTimeServiceResponse>
    </soap:Body>
</soap:Envelope>

But WCF by ServiceHost is responding in OperationContract:

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <eTimeServiceResponse xmlns="http://anet.eu/webservices">ACA41A510200160000000000000000005BDFA1E076E2D3B3FD15F6DCF79F12B103F48C8955B3992FFE604FB79F703568</eTimeServiceResponse>
    </s:Body>
</s:Envelope>

I am required to produce the same result in WCF host. As I read through multiple sources, I understand, that first is response with full XML document, but WCF is responding only with body of document. How can I configure exactly same response as for IIS ASMX? (Even that s alias instead soap could be problematic.) Very thanks.

_server = new ServiceHost(typeof(Service), new Uri(address));
ServiceThrottlingBehavior throttle = new ServiceThrottlingBehavior
{
    MaxConcurrentCalls = maxClient
};
_server.Description.Behaviors.Add(throttle);
_server.Open();
.NET
.NET
Microsoft Technologies based on the .NET software framework.
4,103 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Rada Matěj 200 Reputation points
    2023-08-31T05:49:31.33+00:00

    I've figured out the solution:

    [AttributeUsage(AttributeTargets.Method)]
    internal class EnvelopeFormatMessageAttribute : Attribute, IOperationBehavior
    {
        internal class SoapEnvelopeMessageFormatter : IDispatchMessageFormatter
        {
            private readonly IDispatchMessageFormatter formatter;
    
            public SoapEnvelopeMessageFormatter(IDispatchMessageFormatter formatter)
            {
                this.formatter = formatter;
            }
    
            public void DeserializeRequest(Message message, object[] parameters) =>
                this.formatter.DeserializeRequest(message, parameters);
    
            public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
            {
                Message message = this.formatter.SerializeReply(messageVersion, parameters, result);
                return new SoapEnvelopeMessage(message);
            }
        }
    
        internal class SoapEnvelopeMessage : Message
        {
            private readonly Message message;
    
            public SoapEnvelopeMessage(Message message)
            {
                this.message = message;
            }
            public override MessageHeaders Headers => this.message.Headers;
            public override MessageProperties Properties => this.message.Properties;
            public override MessageVersion Version => this.message.Version;
            protected override void OnWriteStartBody(XmlDictionaryWriter writer) =>
                writer.WriteStartElement("Body", "http://schemas.xmlsoap.org/soap/envelope/"); // Request response
            protected override void OnWriteBodyContents(XmlDictionaryWriter writer) =>
                this.message.WriteBodyContents(writer);
            protected override void OnWriteStartEnvelope(XmlDictionaryWriter writer)
            {
                writer.WriteStartDocument(); // <?xml version="1.0" encoding="utf-8"?>
                writer.WriteStartElement("soap", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/");
                writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
                writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
            }
        }
    
        const string serializerBehaviorType = "datacontractserializeroperationbehavior";
        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            IOperationBehavior serializerBehavior = operationDescription.OperationBehaviors.FirstOrDefault(ob =>
                serializerBehaviorType.Equals(ob.GetType().Name, StringComparison.InvariantCultureIgnoreCase));
    
            if (dispatchOperation.Formatter == null)
            {
                serializerBehavior.ApplyDispatchBehavior(operationDescription, dispatchOperation);
            }
            dispatchOperation.Formatter = new SoapEnvelopeMessageFormatter(dispatchOperation.Formatter);
        }
    

    And then I can use it on any operation I want to be re-formatted.

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.