如何通过FromBody将DataTable传递给Web API POST方法(C#)

本文关键字:POST API 方法 Web FromBody 何通过 DataTable | 更新日期: 2023-09-27 18:29:04

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

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

要通过连线发送大量数据,但按照我现在的方式,我必须运行SP两次——首先是在客户端Winforms应用程序上,然后是在Web API服务器应用程序上。同时调用此SP有时似乎会导致一些问题。

因此,如果可行的话,我想通过"FromBody"发送DataTable,或者如果愿意,通过数据的XML化或jsonized版本发送DataTable(然后在另一端对其进行解压缩,在调用相应的GET方法时,我将其转换为html进行检索。

有人有任何代码可以显示吗?

在这里可以看到我现有的只通过params的代码。

更新

好吧,根据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,而是一个字符串式/jsonied的泛型列表:

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

我将此添加到Register方法中:

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

尽管如此,控制器中的主要突破线:

List<ProduceUsage> _produceUsageList = stringifiedjsondata;

未联系到。

如何通过FromBody将DataTable传递给Web API POST方法(C#)

或jsonized版本的数据(然后在另一端解压缩)

我最终得到了这个-

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"}]

我以前做过一次,尽管代码现在已经被取代了,所以我只能从我的TFS历史中获得一些零碎的东西。

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

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

在服务器端,我有以下内容。这里的概念主要基于链接帖子的"发送复杂类型"部分。我知道您特别关注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;
    }

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

请参阅Hernan Guzman的答案。

基本上,您必须将"[FromBody]"添加到服务器上的方法中,然后从客户端传递数据,并将其添加到URL参数之后。