Miles B.
Miles B.

Reputation: 600

WCF Service Request is Null when using XmlSerializerFormat

I'm writing an WCF service based on the WSDL from an old soap service. I used svcutil to generate the the service contract and made a few changes to match the site I'm hosting it on, but when I call the service from a test client, the request object is coming in as null.

The response the service is returning is also getting serialized incorrectly which I'm sure is related. But I can't figure why its not serializing and deserializing correctly.

Here's the service contract:

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace = ApuConstants.Namespace)]
public interface IApuService
{
    [System.ServiceModel.OperationContractAttribute(Action = "*", ReplyAction = "*")]
    [System.ServiceModel.XmlSerializerFormatAttribute(Style = System.ServiceModel.OperationFormatStyle.Rpc, Use = System.ServiceModel.OperationFormatUse.Encoded)]
    [System.ServiceModel.ServiceKnownTypeAttribute(typeof(Part))]
    [return: System.ServiceModel.MessageParameterAttribute(Name = "return")]
    Brock.Web.Apu.Response check(Brock.Web.Apu.Request request);
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = ApuConstants.Namespace)]
public partial class Request
{

    private RequestHeader headerField;

    private Lookup lookupField;

    /// <remarks/>
    public RequestHeader header
    {
        get
        {
            return this.headerField;
        }
        set
        {
            this.headerField = value;
        }
    }

    /// <remarks/>
    public Lookup lookup
    {
        get
        {
            return this.lookupField;
        }
        set
        {
            this.lookupField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = ApuConstants.Namespace)]
public partial class RequestHeader
{

    private string accountField;

    private string idField;

    /// <remarks/>
    public string account
    {
        get
        {
            return this.accountField;
        }
        set
        {
            this.accountField = value;
        }
    }

    /// <remarks/>
    public string id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = ApuConstants.Namespace)]
public partial class Part
{

    private string oemField;

    private string hicField;

    private string skuField;

    private string descField;

    private int daysField;

    private string availField;

    private string branchField;

    private float listField;

    private float netField;

    private string typeField;

    private string certField;

    private string statusField;

    /// <remarks/>
    public string oem
    {
        get
        {
            return this.oemField;
        }
        set
        {
            this.oemField = value;
        }
    }

    /// <remarks/>
    public string hic
    {
        get
        {
            return this.hicField;
        }
        set
        {
            this.hicField = value;
        }
    }

    /// <remarks/>
    public string sku
    {
        get
        {
            return this.skuField;
        }
        set
        {
            this.skuField = value;
        }
    }

    /// <remarks/>
    public string desc
    {
        get
        {
            return this.descField;
        }
        set
        {
            this.descField = value;
        }
    }

    /// <remarks/>
    public int days
    {
        get
        {
            return this.daysField;
        }
        set
        {
            this.daysField = value;
        }
    }

    /// <remarks/>
    public string avail
    {
        get
        {
            return this.availField;
        }
        set
        {
            this.availField = value;
        }
    }

    /// <remarks/>
    public string branch
    {
        get
        {
            return this.branchField;
        }
        set
        {
            this.branchField = value;
        }
    }

    /// <remarks/>
    public float list
    {
        get
        {
            return this.listField;
        }
        set
        {
            this.listField = value;
        }
    }

    /// <remarks/>
    public float net
    {
        get
        {
            return this.netField;
        }
        set
        {
            this.netField = value;
        }
    }

    /// <remarks/>
    public string type
    {
        get
        {
            return this.typeField;
        }
        set
        {
            this.typeField = value;
        }
    }

    /// <remarks/>
    public string cert
    {
        get
        {
            return this.certField;
        }
        set
        {
            this.certField = value;
        }
    }

    /// <remarks/>
    public string status
    {
        get
        {
            return this.statusField;
        }
        set
        {
            this.statusField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = ApuConstants.Namespace)]
public partial class ResponseHeader
{

    private string statusField;

    private string reasonField;

    private string accountField;

    private string idField;

    /// <remarks/>
    public string status
    {
        get
        {
            return this.statusField;
        }
        set
        {
            this.statusField = value;
        }
    }

    /// <remarks/>
    public string reason
    {
        get
        {
            return this.reasonField;
        }
        set
        {
            this.reasonField = value;
        }
    }

    /// <remarks/>
    public string account
    {
        get
        {
            return this.accountField;
        }
        set
        {
            this.accountField = value;
        }
    }

    /// <remarks/>
    public string id
    {
        get
        {
            return this.idField;
        }
        set
        {
            this.idField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = ApuConstants.Namespace)]
public partial class Response
{

    private ResponseHeader headerField;

    private Part[] itemsField;

    /// <remarks/>
    public ResponseHeader header
    {
        get
        {
            return this.headerField;
        }
        set
        {
            this.headerField = value;
        }
    }

    /// <remarks/>
    public Part[] items
    {
        get
        {
            return this.itemsField;
        }
        set
        {
            this.itemsField = value;
        }
    }
}

/// <remarks/>
[System.CodeDom.Compiler.GeneratedCodeAttribute("svcutil", "4.0.30319.33440")]
[System.SerializableAttribute()]
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.SoapTypeAttribute(Namespace = ApuConstants.Namespace)]
public partial class Lookup
{

    private string oemField;

    private string hicField;

    private int qtyField;

    private string zipField;

    /// <remarks/>
    public string oem
    {
        get
        {
            return this.oemField;
        }
        set
        {
            this.oemField = value;
        }
    }

    /// <remarks/>
    public string hic
    {
        get
        {
            return this.hicField;
        }
        set
        {
            this.hicField = value;
        }
    }

    /// <remarks/>
    public int qty
    {
        get
        {
            return this.qtyField;
        }
        set
        {
            this.qtyField = value;
        }
    }

    /// <remarks/>
    public string zip
    {
        get
        {
            return this.zipField;
        }
        set
        {
            this.zipField = value;
        }
    }
}

And the Implementation:

[ServiceBehavior(Namespace = ApuConstants.Namespace)]
public class ApuService : IApuService
{
    private readonly IApuServiceHandler _handler;
    private readonly ISettingService _settingService;

    public ApuService()
    {
        _handler = EngineContext.Current.Resolve<IApuServiceHandler>();
        _settingService = EngineContext.Current.Resolve<ISettingService>();
    }

    public Response check(Request request)
    {
        if (Authorized(request))
            return _handler.ProcessRequest(request);
        return _handler.ErrorResponse("Invalid credentials");
    }

    protected bool Authorized(Request request)
    {
        if (request == null || request.header == null)
            return false;

        var settings = _settingService.LoadSetting<ApuSettings>(0);

        if (!string.Equals(request.header.account, settings.Username, StringComparison.InvariantCultureIgnoreCase))
            return false;

        if (!string.Equals(request.header.id, settings.Password))
            return false;

        return true;
    }
}

The Configuration:

<configuration>
  <system.web>
    <compilation targetFramework="4.5.1" />
  </system.web>

  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="ApuBehavior">
          <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <bindings>
    </bindings>
    <services>
      <service name="Apu.WebService.ApuService" behaviorConfiguration="ApuBehavior">
        <endpoint address="" binding="basicHttpBinding" contract="Web.Apu.IApuService" bindingNamespace="http://www.testurl.com/apu" />
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
      </service>
    </services>
  </system.serviceModel>
</configuration>

The request received by the service (from OperationContext.Current.RequestContext.RequestMessage):

<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Header xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <To s:mustUnderstand="1" xmlns="http://schemas.microsoft.com/ws/2005/05/addressing/none">http://localhost:15555/Plugins/Brock.Apu/Remote/ApuService.svc</To>
  </s:Header>
  <Body>
        <check xmlns="http://www.testurl.com/apu">
            <request>
                <header>
                    <account>apu</account>
                    <id>apu001!</id>
                </header>
                <lookup>
                    <hic>323-01327</hic>
                    <oem>5014351AB</oem>
                    <qty>2</qty>
                    <zip>85304</zip>
                </lookup>
            </request>
        </check>
    </Body>
</Envelope>

The Response sent by the service (which is serialized incorrectly):

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
    <s:Body s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
        <q1:checkResponse xmlns:q1="http://www.testurl.com/apu">
            <return href="#id1"/>
        </q1:checkResponse>
        <q2:Response id="id1" xsi:type="q2:Response" xmlns:q2="http://www.testurl.com/apu">
            <header href="#id2"/>
        </q2:Response>
        <q3:ResponseHeader id="id2" xsi:type="q3:ResponseHeader" xmlns:q3="http://www.testurl.com/apu">
            <status xsi:type="xsd:string">no</status>
            <reason xsi:type="xsd:string">Invalid credentials</reason>
            <account xsi:type="xsd:string"/>
            <id xsi:type="xsd:string"/>
        </q3:ResponseHeader>
    </s:Body>
</s:Envelope>

Upvotes: 6

Views: 2149

Answers (3)

change this :

 [System.ServiceModel.XmlSerializerFormatAttribute(Style = System.ServiceModel.OperationFormatStyle.Rpc, Use = System.ServiceModel.OperationFormatUse.Encoded)]

by :

 [System.ServiceModel.XmlSerializerFormatAttribute(Style = System.ServiceModel.OperationFormatStyle.Document, Use = System.ServiceModel.OperationFormatUse.Literal)]

Upvotes: 0

Miles B.
Miles B.

Reputation: 600

Follow up: It turns out the service contract as I originally posted it just fine. It's the format of the request that was wrong. Instead of a simple inline xml structure, the deserializer was expecting this:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>
        <ns1:check xmlns:ns1="http://www.testurl.com/apu" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
            <request href="#id0"/>
        </ns1:check>
        <multiRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://www.testurl.com/apu" id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:Request">
            <header href="#id1"/>
            <lookup href="#id2"/>
        </multiRef>
        <multiRef xmlns:ns3="http://www.testurl.com/apu" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns3:RequestHeader">
            <account xsi:type="xsd:string"></account>
            <id xsi:type="xsd:string"></id>
        </multiRef>
        <multiRef xmlns:ns4="http://www.testurl.com/apu" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id2" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns4:Lookup">
            <oem xsi:type="xsd:string">6C3Z13008BB</oem>
            <hic xsi:type="xsd:string"/>
            <qty href="#id3"/>
            <zip xsi:type="xsd:string">70764</zip>
        </multiRef>
        <multiRef xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" id="id3" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:int">1</multiRef>
    </soapenv:Body>
</soapenv:Envelope>

I figured this out after having our customer log the raw request getting sent by their client.

Upvotes: 0

John Meyer
John Meyer

Reputation: 2356

It looks like the Response is a partial class. Is there another piece, perhaps in another file? Is that other piece serializable? Same questions for ResponseHeader and Part?

I usually use the [Serializable] decorator.

There could be an issue with the keyword list on public float list within the Part class.

Upvotes: 1

Related Questions