如何使用FlUrl进行XML POST

3

FlUrl 在处理 Json/UrlEncoded 请求方面做得非常好。然而,文档并没有明确说明如何处理其他请求类型,例如 text/xml

使用 FlUrl 如何进行 XML POST 是最佳方式?

这种方法(访问基础的 HttpClient)有点违背使用 FlUrl 的初衷,因为你需要重新构建 URI 和内容:

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

您还可以查看 https://github.com/milesflavel/Flurl.Http.Soap 项目以获取 SOAP 协议支持。 - Dariusz Woźniak
5个回答

6

目前还没有内置XML支持,但这是已记录的内容,并且是我想要在Flurl.Http 1.0中实现的为数不多的剩余功能之一。(令人惊讶的是,直到现在还没有人要求它。)

同时,Flurl很容易扩展, 您可以通过扩展方法自己添加此支持。这应该是您流畅地发布XML字符串所需的全部内容:

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);
    }
}

更新:

我决定不在Flurl中包含XML支持,主要是因为社区成员站出来创建了一个很棒的扩展库来支持它:

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


使用这个扩展库时,有没有一种指定“text/xml”Content-Type的方法?开箱即用似乎所有请求都标记为“application/xml”。 - Matt Koch
@user2710915 .WithHeader("Content-Type", "text/xml")... (请注意,这是代码片段,不是完整的句子。) - Todd Menier

1

浏览源代码后,似乎SendAsync正在进行中。由于最新的软件包尚不支持它,我考虑添加自己的。

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);
    }
}

是的,我采取了一些捷径,比如接受序列化的 XML 而不是自己进行序列化。目前,这对我来说可行。

如果有更好的方法,我全听耳朵!


1
关于 CapturedStringContent,你说得对,我差点忘了。我发现它通常只占用很小的内存空间,如果出了任何问题,能够检查原始请求体是非常有价值的。 - Todd Menier
是的,“SendAsync”算是一个正在进行中的工作。它将稍微改变可扩展性模式,这样您就不必自己执行try/finally/dispose部分了。当准备好时,我会回来更新我的答案,但这不会导致此实现出现故障。 - Todd Menier

1
我是有点晚了,但我已经成功地使用Flurl和Xml(在xml扩展方面遇到了一些麻烦)。
首先,将您的xml数据字符串转换为HTML内容。
var httpContent = new StringContent(xmlDateString, Encoding.UTF8, "text/xml");

然后,在普通的postasync调用中使用该内容。
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);

在这个调用中,我正在设置内容类型。我还设置了SOAP操作(这是我正在调用的Web方法)。
然后它像平常一样工作。

当负载为Encoding.UTF8,"text/xml"时,您必须设置Content-Type头吗? - Pepster

1

对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);
    }
}

0
对于我的情况,我只需要POST我的XML的字符串表示形式,同时能够将Content-Type设置为text/xml并将编码设置为utf-8。不确定是否有更简单的方法可以做到这一点,但是这里有一个扩展方法可以帮助我实现:
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);
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接