ASP.NET API: Get XML from content

511 views Asked by At

I have following ApiController method in my ASP.NET (.NET Framework 4.5.1) app:

    [HttpPost]
    public void Post([FromBody]XElement value)
    {   
        ...
    }

But when I try to post raw xml in the content via Postman the value is always null.

Here is more information from Fiddler:

POST http://localhost:54193/api/punchoutsetup/post HTTP/1.1
Content-Type: text/xml
cache-control: no-cache
Postman-Token: e2d5563a-061b-4ddc-b03b-6f9d4835c535
User-Agent: PostmanRuntime/7.2.0
Accept: */*
Host: localhost:54193
accept-encoding: gzip, deflate
content-length: 1441
Connection: keep-alive

<?xml version="1.0"?>
<!DOCTYPE cXML SYSTEM "http://xml.cxml.org/schemas/cXML/1.2.014/cXML.dtd">
<cXML payloadID="1211221788.71299@ip-10-251-122-83" timestamp="Mon May 19 18:29:48 +0000 2008" xml:lang="en-US">
  <Header>
    <From>
      <Credential domain="DUNS">
        <Identity>test</Identity>
      </Credential>
    </From>
    <To>
      <Credential domain="DUNS">
        <Identity>test</Identity>
      </Credential>
    </To>
    <Sender>
      <Credential domain="DUNS">
        <Identity>test</Identity>
        <SharedSecret>test</SharedSecret>
      </Credential>
      <UserAgent>Coupa Procurement 1.0</UserAgent>
    </Sender>
  </Header>
  <Request>
    <PunchOutSetupRequest operation="create">
      <BuyerCookie>c64af92dc27e68172e030d3dfd1bc944</BuyerCookie>
      <Extrinsic name="FirstName">Jim</Extrinsic>
      <Extrinsic name="LastName"></Extrinsic>
      <Extrinsic name="UniqueName">jim</Extrinsic>
      <Extrinsic name="UserEmail"></Extrinsic>
      <Extrinsic name="User">jim</Extrinsic>
      <Extrinsic name="BusinessUnit"></Extrinsic>
      <Contact role="endUser">
        <Name xml:lang="en-US">jim</Name>
        <Email></Email>
      </Contact>
      <BrowserFormPost>
        <URL></URL>
      </BrowserFormPost>
    </PunchOutSetupRequest>
  </Request>
</cXML>

Why does it not recognize the xml information?

I see following Exceptions being thrown in the Debug output:

Exception thrown: 'System.Web.HttpException' in System.Web.dll
Exception thrown: 'System.Xml.XmlException' in System.Runtime.Serialization.dll
Exception thrown: 'System.Runtime.Serialization.SerializationException' in System.Runtime.Serialization.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll
Exception thrown: 'Microsoft.CSharp.RuntimeBinder.RuntimeBinderException' in Microsoft.CSharp.dll

And is there a more detailed log available in Visual Studio to check what went wrong?

2

There are 2 answers

7
Nkosi On

An alternative can be to load the XML as a raw string and parse it into the XElement

[HttpPost]
public IHtpActionResult Post([FromBody]string value) {
    if(string.IsNullOrWhiteSpace(value))
        return BadRequest();

    Xelement element = XElement.Parse(value);

    //...
}

The main problem is that the model binder is unable to bind the provided raw data into the desired model (in this case the XElement) and thus sets it to its default value of null.

To bind by default, models must have a default parameterless constructor in order for the the model binder to initialize the model. XElement does not. Otherwise you would probably need to create a custom parameter binder that knows how to handle XElement

0
spierce On

I was able to accomplish this by doing something similar to what @Nkosi was doing by using the XMLDocument class (System.XML).

What worked for me was:

[HttpPost]
public async Task<IHttpActionResult> SomeEndpoint()
{
    // parse the string content from the request
    var content = await Request.Content.ReadAsStringAsync();
    var xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(content);
    var root = xmlDoc.DocumentElement;

    // next, get your values using the XML path relative to the root node in the request
    var example = GetXmlNodeValue(root, "Path/To/Value");
    // then do something with your values and return
    return Ok();
}