【问题标题】:How to pass DataTable via FromBody to Web API POST method (C#)如何通过 FromBody 将 DataTable 传递给 Web API POST 方法(C#)
【发布时间】:2016-04-10 03:37:51
【问题描述】:

我成功地从 Winforms 客户端调用 Web API 应用程序中的 POST 方法,该客户端为存储过程传递一些参数。

不过,如果可能的话,我希望通过 FromBody 功能将存储过程(我必须首先在客户端上运行)的结果传递给 POST 方法。

通过网络发送大量数据,但我现在这样做的方式是我必须运行 SP 两次 - 首先在客户端 Winforms 应用程序上,然后在 Web API 服务器应用程序上,然后同时调用这个 SP 似乎有时会引起一些问题。

所以,如果可行,我想通过“FromBody”发送数据表,或者如果更可取,发送数据的 XML 化或 json 化版本(然后在另一端解压,我将其转换为调用相应的 GET 方法时检索的 html。

有没有人有任何可以显示的代码?

可以看到我现有的仅通过参数的代码here

更新

好的,根据 Amit Kumar Ghosh 的回答,我将代码更改为:

WebApiConfig.cs

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        // Configure Web API to use only bearer token authentication.
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new    
HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

    // Web API routes
    config.MapHttpAttributeRoutes();

    config.Routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: "api/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );


    config.Formatters.Add(new DataTableMediaTypeFormatter());
}

public class DataTableMediaTypeFormatter : BufferedMediaTypeFormatter
{
    public DataTableMediaTypeFormatter()
        : base()
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("test/dt"));
    }

    public override object ReadFromStream(Type type, Stream readStream,
        HttpContent content, IFormatterLogger formatterLogger, System.Threading.CancellationToken cancellationToken)
    {
        var data = new StreamReader(readStream).ReadToEnd();
        var obj = JsonConvert.DeserializeObject<DataTable>(data);
        return obj;
    }

    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override bool CanWriteType(Type type)
    {
        return true;
    }
}

控制器

[Route("{unit}/{begindate}/{enddate}/{stringifiedjsondata}")]
[HttpPost]
public void Post(string unit, string begindate, string enddate, DataTable stringifiedjsondata)
{
    DataTable dt = stringifiedjsondata;
    . . .

客户

private async Task SaveProduceUsageFileOnServer(string beginMonth, string beginYear, string endMonth, string endYear)
{
    string beginRange = String.Format("{0}{1}", beginYear, beginMonth);
    string endRange = String.Format("{0}{1}", endYear, endMonth);
    HttpClient client = new HttpClient();
    client.BaseAddress = new Uri("http://localhost:52194");
    string dataAsJson = JsonConvert.SerializeObject(_rawAndCalcdDataAmalgamatedList, Formatting.Indented);
    String uriToCall = String.Format("/api/produceusage/{0}/{1}/{2}/{3}", _unit, beginRange, endRange, @dataAsJson);
    HttpResponseMessage response = await client.PostAsync(uriToCall, null);
}

...但是仍然没有到达控制器;具体来说,“DataTable dt = dtPassedAsJson;”中的断点永远达不到。

实际上,它并没有崩溃,这让我有点惊讶,因为正在传递一个字符串,但其中声明的数据类型是“DataTable”

更新 2

我也试过这个,在意识到它不是我从客户端传递的真正的字符串化/jsonized DataTable,而是一个字符串化/jsonized 通用列表之后:

WEB API 控制器

[Route("{unit}/{begindate}/{enddate}/{stringifiedjsondata}")]
[HttpPost]
public void Post(string unit, string begindate, string enddate, List<ProduceUsage> stringifiedjsondata)
{
    List<ProduceUsage> _produceUsageList = stringifiedjsondata;

WebApiConfig.cs

我在注册方法中添加了这个:

config.Formatters.Add(new GenericProduceUsageListMediaTypeFormatter());

...还有这个新课程:

// adapted from DataTableMediaTypeFormatter above
public class GenericProduceUsageListMediaTypeFormatter : BufferedMediaTypeFormatter
{
    public GenericProduceUsageListMediaTypeFormatter()
        : base()
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("test/dt"));
    }

    public override object ReadFromStream(Type type, Stream readStream,
        HttpContent content, IFormatterLogger formatterLogger, System.Threading.CancellationToken cancellationToken)
    {
        var data = new StreamReader(readStream).ReadToEnd();
        var obj = JsonConvert.DeserializeObject<List<ProduceUsage>>(data);
        return obj;
    }

    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override bool CanWriteType(Type type)
    {
        return true;
    }
}

不过,Controller 中的主要断点行仍然是:

List<ProduceUsage> _produceUsageList = stringifiedjsondata;

...未达到。

【问题讨论】:

标签: c# winforms asp.net-web-api frombodyattribute


【解决方案1】:

或json化版本的数据(然后在另一端解包

我就这样结束了 -

public class ParentController : ApiController
{
    public string Post(DataTable id)
    {
        return "hello world";
    }
}

在配置中

config.Formatters.Add(new DataTableMediaTypeFormatter());

还有——

public class DataTableMediaTypeFormatter : BufferedMediaTypeFormatter
{
    public DataTableMediaTypeFormatter()
        : base()
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("test/dt"));
    }

    public override object ReadFromStream(Type type, System.IO.Stream readStream,
        System.Net.Http.HttpContent content, IFormatterLogger formatterLogger, System.Threading.CancellationToken cancellationToken)
    {
        var data = new StreamReader(readStream).ReadToEnd();
        var obj = JsonConvert.DeserializeObject<DataTable>(data);
        return obj;
    }

    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override bool CanWriteType(Type type)
    {
        return true;
    }
}

header of my request -
User-Agent: Fiddler
Host: localhost:60957
Content-Type : test/dt
Content-Length: 28

身体 -

[{"Name":"Amit","Age":"27"}]

【讨论】:

  • “在配置中”是指 WebApiConfig.cs 吗? DataTableMediaTypeFormatter 类也属于那里吗?并且“config.Formatters.Add()”应该进入Register块?
  • 这看起来很有希望,但我无法理解您的代码;似乎从客户端传递了一个 DataTable,然后在 Web API 应用程序中转换为 Json。这很好,但它与顶部的注释不匹配(“或数据的 json 化版本(然后在另一端解压缩”)。然后如何从 Post 方法中访问该 json 化数据仍然是对我来说是个谜,以及如何调用 Post 方法(如何打包 DataTable 发送)。
  • 客户端实际上是在传递一个json形式的数据表,然后webapi运行时根据特殊的媒体类型将json再次转换为服务端的数据表。
  • 你还没有回答我在上面的第一条评论中的问题,关于代码需要去哪里。
  • 是的。它是 webapiconfig.cs
【解决方案2】:

我以前做过一次,虽然代码现在已被取代,所以我只能从我的 TFS 历史记录中获取点点滴滴。

从我的控制台应用程序中,我将发布数据(我转换为 POCO 的 DataTable),如下所示;

            using (HttpClient httpClient = new HttpClient())
            {
                MyDataType data = BogusMethodToPopulateData();

                httpClient.BaseAddress = new Uri(Properties.Settings.Default.MyService);
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response;

                // Add reference to System.Net.Http.Formatting.dll
                response = await httpClient.PostAsJsonAsync("api/revise", data);

                if (response.IsSuccessStatusCode)
                {
                    Console.WriteLine("File generation process completed successfully.");
                }
            }

在服务器端,我有以下内容。这里的概念主要基于链接帖子的Sending Complex Types 部分。我知道您专门在查看 DataTables,但我相信您可能会弄乱示例或将数据提取到 POCO 中;

    // https://damienbod.wordpress.com/2014/08/22/web-api-2-exploring-parameter-binding/
    // http://www.asp.net/web-api/overview/advanced/sending-html-form-data,-part-1
    // http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
    [POST("revise")]
    public IEnumerable<Revised_Data> Revise(MyDataType data)
    {
        if (ModelState.IsValid && data != null)
        {
            return ProcessData(data.year, data.period, data.DataToProcess).AsEnumerable();
        }
        return null;
    }

【讨论】:

    【解决方案3】:

    客户端实际上是在传递一个json形式的数据表,然后webapi运行时根据特殊的媒体类型在服务器端再次将json转换为数据表。

    【讨论】:

    • 好的,但我没有看到您的代码中发生了这种情况;例如,json 在哪里转换为 DataTable,如何从客户端调用它?顺便说一句,这应该是对我的评论的回复,而不是另一个答案。
    • 媒体类型格式化程序对此负责。检查 ReadFromStream 方法。
    【解决方案4】:

    查看 Hernan Guzman 的回答 here

    基本上,你必须在服务器端的方法中添加“[FromBody]”,然后从客户端传递数据,添加到 URL 参数之后。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-08-07
      • 2018-08-22
      • 2018-05-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-12
      • 1970-01-01
      相关资源
      最近更新 更多