【问题标题】:ASP.NET MVC4 WebAPI and Posting XML dataASP.NET MVC4 WebAPI 和发布 XML 数据
【发布时间】:2012-05-03 09:02:03
【问题描述】:

我错过了新 webapi 的一个技巧 - 我正在尝试通过 post 请求提交一个 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 字符串?

【问题讨论】:

    标签: xml asp.net-mvc asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

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

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

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

    【讨论】:

      【解决方案2】:

      您发送的内容类型为text/xml,但您已将参数定义为string。理想情况下,您的 XML 应该映射到 class 以便它可以被反序列化

      所以如果你需要 raw xml 那么它还不被支持。 Web API 目前已为序列化 MediaTypeFormatters 和缺少简单的类型格式化程序做好准备,但它们可以很容易地构建。

      这是一个 minimal 实现这种格式化程序,仅支持在您的情况下读取并基于 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());
      

      【讨论】:

      • 您可以使用var reader = new StreamReader(readStream);var text = await reader.ReadToEndAsync();简化阅读流
      【解决方案3】:

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

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

      【讨论】:

      • 我可以和你聊天吗?
      【解决方案4】:

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

      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 输入。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-07-04
        • 1970-01-01
        • 1970-01-01
        • 2016-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-05
        相关资源
        最近更新 更多