如何通过FromBody将DataTable传递给Web API POST方法(C#)
我正在从Winforms客户端成功调用Web API应用程序中的POST方法,该客户端为存储过程传递一些参数 不过,如果可能的话,我更愿意通过FromBody功能将存储过程的结果(必须首先在客户机上运行)传递给POST方法 要通过网络发送大量数据,但按照我现在的方式,我必须运行SP两次—首先在客户端Winforms应用程序上运行,然后在Web API服务器应用程序上运行,同时调用此SP有时似乎会导致一些问题 因此,如果可行的话,我想通过“FromBody”发送DataTable,或者,如果更可取的话,发送xml化或jsonized版本的数据(然后在另一端解压,在调用相应的GET方法时将其转换为html进行检索) 有人有任何代码可以显示吗 我的现有代码只通过参数就可以看到 更新 好的,根据Amit Kumar Ghosh的回答,我将代码更改为: WebApiConfig.cs 客户 …但仍未到达控制器;具体而言,从未到达“DataTable dt=dtPassedAsJson;”中的断点 事实上,它没有崩溃让我有点惊讶,因为传递的是字符串,但声明的数据类型是“DataTable” 更新2 我还尝试了这个方法,因为我意识到我从客户端传递的不是一个真正的stringized/jsonized数据表,而是一个stringized/jsonized通用列表: WEB API控制器 …还有这个新类别:如何通过FromBody将DataTable传递给Web API POST方法(C#),c#,winforms,asp.net-web-api,frombodyattribute,C#,Winforms,Asp.net Web Api,Frombodyattribute,我正在从Winforms客户端成功调用Web API应用程序中的POST方法,该客户端为存储过程传递一些参数 不过,如果可能的话,我更愿意通过FromBody功能将存储过程的结果(必须首先在客户机上运行)传递给POST方法 要通过网络发送大量数据,但按照我现在的方式,我必须运行SP两次—首先在客户端Winforms应用程序上运行,然后在Web API服务器应用程序上运行,同时调用此SP有时似乎会导致一些问题 因此,如果可行的话,我想通过“FromBody”发送DataTable,或者,如果更可取
// 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;
}
}
//改编自上面的DataTableMediaTypeFormatter
公共类GenericProduceUsageListMediaTypeFormatter:BufferedMediaTypeFormatter
{
public GenericProduceUsageListMediaTypeFormatter()
:base()
{
SupportedMediaTypes.Add(新的System.Net.Http.Headers.MediaTypeHeaderValue(“test/dt”);
}
公共重写对象ReadFromStream(类型类型、流readStream、,
HttpContent内容,IFormatterLogger格式记录器,System.Threading.CancellationToken CancellationToken)
{
var data=newstreamreader(readStream).ReadToEnd();
var obj=JsonConvert.DeserializeObject(数据);
返回obj;
}
公共覆盖布尔CanReadType(类型)
{
返回true;
}
公共重写bool CanWriteType(类型)
{
返回true;
}
}
尽管如此,控制器中的主断点行:
List<ProduceUsage> _produceUsageList = stringifiedjsondata;
List\u produceUsageList=stringifiedjsondata;
…未到达。或数据的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
我以前做过一次,尽管代码现在已经被取代了,所以我只能从TFS历史记录中获取零碎信息 从我的控制台应用程序中,我将发布数据(是一个数据表,我将其转换为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.");
}
}
在服务器端,我有以下几点。这里的概念主要基于链接文章的部分。我知道您特别关注数据表,但我相信您可能会弄乱示例或将数据提取到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;
}
//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,-第1部分
// http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
[发布(“修订”)]
公共IEnumerable修订(MyDataType数据)
{
if(ModelState.IsValid&&data!=null)
{
返回ProcessData(data.year、data.period、data.DataToProcess).AsEnumerable();
}
返回null;
}
客户端实际上是以json的形式传递数据表,然后根据特殊的媒体类型webapi运行时在服务器上将json再次转换为数据表。参见Hernan Guzman的回答
基本上,您必须将“[FromBody]”添加到服务器上的方法中,然后从客户端传递数据,并将其添加到URL参数之后。您可以发送序列化的json字符串并反序列化回controller。我认为这个难题的答案是Hernan Guzman在“配置”中发布的内容你是说WebApiConfig.cs?DataTableMediaTypeFormatter类也属于其中?还有“config.Formatters.Add()应该进入注册块吗?这看起来很有希望,但我无法检查您的代码;似乎一个DataTable正在从客户端传递,然后在Web API应用程序中转换为Json。这很好,但与顶部的注释(“或数据的jsonized版本(然后在另一端解压)”不匹配。然后如何从Post方法中访问jsonized数据对我来说仍然是个谜,以及如何调用Post方法(如何打包要发送的数据表)。客户端实际上是以json的形式传递一个数据表,然后根据特殊的媒体类型webapi运行时在服务器上将json再次转换为数据表。在我上面的第一条评论中,您仍然没有回答我的问题,关于代码需要放在哪里。是的。它是webapiconfig.csok,但我看不到在您的cod中发生这种情况e、 例如,json在哪里转换为数据表,以及如何从客户端调用它?顺便说一句,这应该是对我的评论的回复(仅限)。媒体类型格式化程序负责。请检查ReadFromStream方法。
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"}]
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.");
}
}
// 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;
}