Mrchief
Mrchief

Reputation: 76218

How to do XML POST with FlUrl

FlUrl does a great job in dealing with Json/UrlEncoded requests. However, the documentation doesn't really point out how to handle other request types such as text/xml.

What's the best way to do an XML POST using FlUrl?

This (accessing underlying HttpClient) kinda defeats the purpose of using FlUrl since you need to build the URI and content again:

var result = await "http://someUrl"
                   .AppendPathSegment(pathSegment)
                   .SetQueryParam("name", name)
                   .WithBasicAuth(_userName, _apiToken)
                   .HttpClient
                   .PostAsync(<uri>, <content>);

Upvotes: 3

Views: 7560

Answers (5)

codepen
codepen

Reputation: 429

A revision for FlurlRequest

public static class FlurlXmlExtensions
{
    // chain off an existing FlurlRequest:
    public static async Task<HttpResponseMessage> PostXmlAsync(this IFlurlRequest fr, string xml)
    {
        var content = new CapturedStringContent(xml, Encoding.UTF8, "application/xml");
        return await fr.PostAsync(content);
    }

    // chain off a Url object:
    public static Task<HttpResponseMessage> PostXmlAsync(this Url url, string xml)
    {
        return new FlurlRequest(url.Path).PostXmlAsync(xml);
    }

    // chain off a url string:
    public static Task<HttpResponseMessage> PostXmlAsync(this string url, string xml)
    {
        return new FlurlRequest(url).PostXmlAsync(xml);
    }
}

Upvotes: 1

Ashley Jackson
Ashley Jackson

Reputation: 173

I am a little late to this, however, I have manged to use Flurl nativly, with Xml (had trouble with the xml extension)

First, take your xml data string, convert it to Html content

var httpContent = new StringContent(xmlDateString, Encoding.UTF8, "text/xml");

then, use that content in a normal postasync call.

var response = await "http://localhost/Notices/webservices/importer.asmx"
        .WithHeader("Authorization", "Basic ssssserrrrr")
        .WithHeader("Content-Type", "text/xml")
        .WithHeader("SOAPAction", "\"http://tempuri.org/ImportData\"")
        .PostAsync(httpContent);

In this call, I am setting the content type. I am also setting the soap action (this is the web method I am calling).

Then it works as normal.

Upvotes: 1

Matt Koch
Matt Koch

Reputation: 181

For my scenario, I just needed to POST a string representation of my XML while at the same time being able to set the Content-Type to text/xml and the encoding to utf-8. Not sure if there is a simpler way to do this I'm just not seeing, but here's an extension method that got me there:

public static class FlurlXmlExtensions
    {
        /// <summary>
        /// Sends an asynchronous POST request that contains an XML string.
        /// </summary>
        /// <param name="client">The IFlurlClient instance.</param>
        /// <param name="data">Contents of the request body.</param>
        /// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation. Optional.</param>
        /// <param name="completionOption">The HttpCompletionOption used in the request. Optional.</param>
        /// <returns>A Task whose result is the received HttpResponseMessage.</returns>
        public static Task<HttpResponseMessage> PostXmlStringAsync(this IFlurlClient client, string data, CancellationToken cancellationToken = default(CancellationToken), HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead)
        {
            var content = new CapturedStringContent(data, Encoding.UTF8, "text/xml");

            return client.SendAsync(HttpMethod.Post, content: content, cancellationToken: cancellationToken, completionOption: completionOption);
        }

    }

Upvotes: 0

Todd Menier
Todd Menier

Reputation: 39319

XML support is not baked in yet, but this is logged and is one of the few remaining features I'd like to have in place for Flurl.Http 1.0. (Surprisingly, no one's requested it until now.)

In the mean time, Flurl is pretty easy to extend, and you could add this support yourself via extension methods. This should be all you need to post an XML string fluently:

public static class FlurlXmlExtensions
{
    // chain off an existing FlurlClient:
    public static async Task<HttpResponseMessage> PostXmlAsync(this FlurlClient fc, string xml) {
        try {
            var content = new CapturedStringContent(xml, Encoding.UTF8, "application/xml");
            return await fc.HttpClient.PostAsync(fc.Url, content);
        }
        finally {
            if (AutoDispose)
                Dispose();
        }
    }

    // chain off a Url object:
    public static Task<HttpResponseMessage> PostXmlAsync(this Url url, string xml) {
        return new FlurlClient(url, true).PostXmlAsync(xml);
    }

    // chain off a url string:
    public static Task<HttpResponseMessage> PostXmlAsync(this string url, string xml) {
        return new FlurlClient(url, true).PostXmlAsync(xml);
    }
}

UPDATE:

I decided not to include XML support in Flurl, largely because a community member stepped up and created a great extension library for it:

https://github.com/lvermeulen/Flurl.Http.Xml

Upvotes: 6

Mrchief
Mrchief

Reputation: 76218

Digging thru the source, it does seem that a SendAsync is work in progress. Since the latest package doesn't support it yet, I thought of adding my own:

public static class FlurlHttpExtensions
{
    /// <summary>
    /// Sends an asynchronous POST request of specified data (usually an anonymous object or dictionary) formatted as XML.
    /// </summary>
    /// <param name="client">The FlurlClient</param>
    /// <param name="serializedXml">Data to be serialized and posted.</param>
    /// <returns>A Task whose result is the received HttpResponseMessage.</returns>
    public static Task<HttpResponseMessage> PostXmlAsync(this FlurlClient client, string serializedXml)
    {
        var request = new HttpRequestMessage(HttpMethod.Post, client.Url.ToString())
        {
            Content = new CapturedStringContent(serializedXml, Encoding.UTF8, "text/xml"),
            Method = HttpMethod.Post
        };
        return client.HttpClient.SendAsync(request);
    }
}

Yes I took some shortcuts like accepting a serialized XML instead of serializing myself. At the moment, this works for me.

If there's a better approach, I'm all ears!

Upvotes: 1

Related Questions