如何通过 FromBody 将 DataTable 传递给 Web API POST 方法 (C#)
How to pass DataTable via FromBody to Web API POST method (C#)
我从 Winforms 客户端成功调用 Web API 应用程序中的 POST 方法,为存储过程传递一些参数。
不过,如果可能的话,我更愿意通过 FromBody 功能将存储过程的结果(我必须先在客户端 运行 )传递给 POST 方法。
通过网络发送的数据很多,但我现在这样做的方式必须 运行 SP 两次 - 首先在客户端 Winforms 应用程序上,然后在 Web API server app,同时调用这个SP好像有时候会出问题
所以,如果可行的话,我想通过 "FromBody" 发送数据表,或者,如果更可取,发送数据的 XML 化或 json 化版本(然后在另一端解压缩,其中我把它转换成html,以便在调用相应的GET方法时检索
有没有人有任何可以显示的执行此操作的代码?
可以看到我现有的只是传递参数的代码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
我也尝试过这个,在意识到我从客户端传递的并不是真正的 stringified/jsonized DataTable,而是一个 stringified/jsonized 通用列表之后:
网络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());
...以及这个新的 class:
// 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;
...未达到。
或者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"}]
虽然代码现在已被取代,但我以前做过一次,所以我只能从我的 TFS 历史中获取点点滴滴。
在我的控制台应用程序中,我将 post 数据(是我转换为 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.");
}
}
在服务器端,我有以下内容。这里的概念主要基于链接 post 的 Sending Complex Types 部分。我知道您特别关注数据表,但我相信您可能会弄乱示例或将数据提取到 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的形式传递一个数据table,然后webapi运行时根据特殊的媒体类型将json转换为一个数据table ] 再次在服务器。
查看 Hernan Guzman 的回答 。
基本上,你必须在服务器的方法中添加“[FromBody]”,然后从客户端传递数据,在URL参数之后添加它。
我从 Winforms 客户端成功调用 Web API 应用程序中的 POST 方法,为存储过程传递一些参数。
不过,如果可能的话,我更愿意通过 FromBody 功能将存储过程的结果(我必须先在客户端 运行 )传递给 POST 方法。
通过网络发送的数据很多,但我现在这样做的方式必须 运行 SP 两次 - 首先在客户端 Winforms 应用程序上,然后在 Web API server app,同时调用这个SP好像有时候会出问题
所以,如果可行的话,我想通过 "FromBody" 发送数据表,或者,如果更可取,发送数据的 XML 化或 json 化版本(然后在另一端解压缩,其中我把它转换成html,以便在调用相应的GET方法时检索
有没有人有任何可以显示的执行此操作的代码?
可以看到我现有的只是传递参数的代码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
我也尝试过这个,在意识到我从客户端传递的并不是真正的 stringified/jsonized DataTable,而是一个 stringified/jsonized 通用列表之后:
网络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());
...以及这个新的 class:
// 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;
...未达到。
或者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"}]
虽然代码现在已被取代,但我以前做过一次,所以我只能从我的 TFS 历史中获取点点滴滴。
在我的控制台应用程序中,我将 post 数据(是我转换为 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.");
}
}
在服务器端,我有以下内容。这里的概念主要基于链接 post 的 Sending Complex Types 部分。我知道您特别关注数据表,但我相信您可能会弄乱示例或将数据提取到 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的形式传递一个数据table,然后webapi运行时根据特殊的媒体类型将json转换为一个数据table ] 再次在服务器。
查看 Hernan Guzman 的回答
基本上,你必须在服务器的方法中添加“[FromBody]”,然后从客户端传递数据,在URL参数之后添加它。