Simon Price
Simon Price

Reputation: 3261

WCF IDispatchMessageFormatter null

I am passing in a SOAP request, that prior to making some changes to look at changing the out going prefix from s:Envelop to soap-env:Envelope as per this example https://www.vanacosmin.ro/Articles/Read/WCFEnvelopeNamespacePrefix I am passing

<soap-env:Envelope
xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:pro="http://www.xxxx">
<soap-env:Header/>
<soap-env:Body>
    <pro:getProposalList version="6.66">
        <pro:code>323232</pro:code>
    </pro:getProposalList>
</soap-env:Body>

and was getting

<s:Envelope
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <ProposalList Version="3.22"
        xmlns="http://xxxxx">
        <ProposalHeader>
            <RefNum>1</RefNum>
            <Size>24</Size>
            <DateSubmitted>2020-06-18</DateSubmitted>
        </ProposalHeader>
    </ProposalList>
</s:Body>

However I need something like this

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 
    <SOAP-ENV:Body> 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <ProposalList Version="3.22"
            xmlns="http://www.xxxx">
            <ProposalHeader>
                <RefNum>1</RefNum>
                <Size>24</Size>
                <DateSubmitted>2020-06-18</DateSubmitted>
            </ProposalHeader>
        </ProposalList>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>    

When I pass in an object that then instantiates this class

public class ProposalMessageFormatter : IDispatchMessageFormatter
{
    private readonly IDispatchMessageFormatter formatter;

    public ProposalMessageFormatter(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)
    {
        var message = this.formatter.SerializeReply(messageVersion, parameters, result);
        return new ProposalMessage(message);
    }
}

IDispatchMessageFormatter formatter is null I suspect that this could be the cause of the issue

I am using autofac for my DI and my global.asax.cs and have had this not referenced and referenced as these examples

builder.RegisterType<ProposalMessageFormatter>().As<IDispatchMessageFormatter>();
builder.RegisterType<ProposalMessageFormatter>().SingleInstance();
builder.RegisterType<ProposalMessageFormatter>().UsingConstructor(typeof(IDispatchMessageFormatter));

The error that comes back is

The server was unable to process the request due to an internal error. For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the <serviceDebug> configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework SDK documentation and inspect the server trace logs.

a bit more detail on this error now

<s:Envelope
    xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body>
        <s:Fault>
            <faultcode
                xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault
            </faultcode>
            <faultstring xml:lang="en-GB">Object reference not set to an instance of an object.</faultstring>
            <detail>
                <ExceptionDetail
                    xmlns="http://schemas.datacontract.org/2004/07/System.ServiceModel"
                    xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
                    <HelpLink i:nil="true"/>
                    <InnerException i:nil="true"/>
                    <Message>Object reference not set to an instance of an object.</Message>
                    <StackTrace>   at TQ.LPAConnector.Service.MessageFormatter.ProposalMessageFormatter.DeserializeRequest(Message message, Object[] parameters) in C:\Projects\xxx.Service\MessageFormatter\ProposalMessageFormatter.cs:line 17&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.DeserializeInputs(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage41(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage4(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage3(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage2(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage11(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage1(MessageRpc&amp; rpc)&#xD;
   at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)</StackTrace>
                    <Type>System.NullReferenceException</Type>
                </ExceptionDetail>
            </detail>
        </s:Fault>
    </s:Body>
</s:Envelope>

As you can see from the request, this is not null, and was working prior to the change so wonder what I may have missed.

Upvotes: 0

Views: 454

Answers (1)

Ding Peng
Ding Peng

Reputation: 3954

Here is my demo:

public class ProposalMessageFormatter : IDispatchMessageFormatter
{
    private readonly IDispatchMessageFormatter formatter;

    public ProposalMessageFormatter(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)
    {
        var message = this.formatter.SerializeReply(messageVersion, parameters, result);
        return new ProposalMessage(message);
    }
}

This is ProposalMessageFormatter.

public class MyOperationBehavior : IOperationBehavior
{
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {
        return;
    }
    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {
        return;
    }
    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {
        dispatchOperation.Formatter = new ProposalMessageFormatter(dispatchOperation.Formatter);
    }
    public void Validate(OperationDescription operationDescription)
    {
        return;
    }
}

This is MyOperationBehavior.

[AttributeUsage(AttributeTargets.Interface, AllowMultiple = false)]
public class MyContractBehaviorAttribute : Attribute, IContractBehavior
{
    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
        return;
    }

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        return;
    }
    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
        OperationDescription op = contractDescription.Operations[0];
        op.Behaviors.Add(new MyOperationBehavior());

    }
    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
        return;
    }
}

This is MyContractBehaviorAttribute.Add MyOperationBehavior to the endpoint through MyContractBehaviorAttribute.

enter image description here

Finally, we add this attribute to the WCF service.

Upvotes: 1

Related Questions