12

我错过了新 webapi 的一个技巧——我试图通过发布请求提交一个 xml 字符串,但运气不佳。

前端使用 jQuery,如下所示:

    $(document = function () {
    $("#buttonTestAPI").click(function () {

        var d = " <customer><customer_id>1234</customer_id></customer>";
        $.ajax({
            type: 'POST',
            contentType: "text/xml",
            url: "@Url.Content("~/api/Customer/")",
            data: d,
            success: function (result) {
                var str = result;
                $("#output").html(str);
            }
        });
    });
});

我的控制器目前非常简单 - 只是 post 操作的默认值 - 试图返回传入的内容:

    public string Post(string value)
    {
        return value;
    }

但是,“值”反复为空。奇怪的是,当我将 jquery 中的数据更改为以下内容时:

d = "<customer_id>1234</customer_id>";

然后我在控制器中得到“值”为 1234。

如何访问控制器中更复杂的 xml 字符串?

4

4 回答 4

18

下面将允许您通过 POST 到 Web API 方法读取原始 XML 消息:

public void PostRawXMLMessage(HttpRequestMessage request)
{
   var xmlDoc = new XmlDocument();
   xmlDoc.Load(request.Content.ReadAsStreamAsync().Result);   
}

您可以调试和检查正文、标题等,并将看到发布的原始 XML。我使用 Fiddler's Composer 制作了一个 HTTP POST,效果很好。

于 2013-01-11T21:56:46.257 回答
13

您正在发送内容类型,text/xml但您已将参数定义为string. 理想情况下,您的 XML 应该映射到一个,以便可以对其进行反序列化

因此,如果您需要原始 xml,那么它尚不受支持。Web API 目前已为序列化 MediaTypeFormatters 做好了准备,缺少简单的类型格式化程序,但它们很容易构建。

这是此类格式化程序的最小实现,仅支持在您的情况下读取并基于beta 安装程序(而不是夜间源代码,因为它已经发生了很大变化):

public class TextMediaTypeFormatter : MediaTypeFormatter
{
    public TextMediaTypeFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
    }

    protected override bool CanReadType(Type type)
    {
        return type == typeof (string);
    }

    protected override System.Threading.Tasks.Task<object> OnReadFromStreamAsync(Type type, Stream stream, 
        HttpContentHeaders contentHeaders, 
        FormatterContext formatterContext)
    {
        var taskCompletionSource = new TaskCompletionSource<object>();
        try
        {
            var memoryStream = new MemoryStream();
            stream.CopyTo(memoryStream);
            var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
            taskCompletionSource.SetResult(s);
        }
        catch (Exception e)
        {
            taskCompletionSource.SetException(e);           
        }
        return taskCompletionSource.Task;
    }
}

要使用它,只需将其添加到格式化程序集合中:

GlobalConfiguration.Configuration.Formatters.Insert(0, new TextMediaTypeFormatter());
于 2012-05-03T10:42:04.490 回答
6

从 beta 版到 asp.net mvc 4 web api 的 RC 的任何人都在寻找上述 Aliostad 答案的更新版本(微小的变化导致我的轻微返工)。

public class TextMediaTypeFormatter : MediaTypeFormatter
{

    public TextMediaTypeFormatter()
    {
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/xml"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/plain"));
        SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript"));
    }

    public override bool CanReadType(Type type)
    {
        if (type == typeof(String))
            return true;
        else
            return false;
    }

    public override bool CanWriteType(Type type)
    {
        if (type == typeof(String))
            return true;
        else
            return false;

    }

    public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, System.Net.Http.HttpContent content, IFormatterLogger formatterLogger)
    {
        var taskCompletionSource = new TaskCompletionSource<object>();
        try
        {
            var memoryStream = new MemoryStream();
            readStream.CopyTo(memoryStream);
            var s = System.Text.Encoding.UTF8.GetString(memoryStream.ToArray());
            taskCompletionSource.SetResult(s);
        }
        catch (Exception e)
        {
            taskCompletionSource.SetException(e);
        }
        return taskCompletionSource.Task;
    }
}
于 2012-08-31T16:07:49.307 回答
0

为我解决问题的是添加以下内容:

static SubscriberController()
{
    //Needed for xml deserialization to work
    var xml = GlobalConfiguration.Configuration.Formatters.XmlFormatter;
    xml.UseXmlSerializer = true;
}

SubscriberController是我的扩展类,ApiController上面是静态构造函数,所以它会运行一次)。

不确定是否也有必要,但我将[FromBody]属性添加到我的参数中,如下所示:

public async Task<HttpResponseMessage> SynchronizeImax( [FromBody] SynchronizeRequest synchronizeRequest )
{
    //...
}

这样做的好处是您可以无缝地处理 XML 和 JSON 输入。

于 2016-01-28T06:15:18.947 回答