title: How to pass DataTable via FromBody to Web API POST method (C#)
body: <p>I am successfully calling a POST method in a Web API app from a Winforms client that passes some parameters for a Stored Procedure.</p>
  
  <p>I would prefer, though, to pass the results of the Stored Procedure (which I have to run on the client first) to the POST method via the FromBody functionality, if possible.</p>
  
  <p>It's a lot of data to send over the wire, but the way I'm doing it now I have to run the SP twice - first on the client Winforms app, then on the Web API server app, and the simultaneous calling of this SP seems to sometimes cause some problems.</p>
  
  <p>So, I'd like to, if feasible, either send the DataTable via "FromBody" or, if preferable, an XMLized or jsonized version of the data (and then unpack it on the other end, where I convert it into html for retrieval when the corresponding GET method is called.</p>
  
  <p>Does anybody have any code that does this that they could display?</p>
  
  <p>My existing code that just passes the params can be seen <a href="https://stackoverflow.com/questions/34618315/why-does-assigning-a-value-to-an-unused-variable-make-a-difference-in-the-functi">here</a>.</p>
  
  <h2>UPDATE</h2>
  
  <p>Okay,based on Amit Kumar Ghosh's answer, I changed my code to this:</p>
  
  <h2>WebApiConfig.cs</h2>
  
  <pre><code>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&lt;DataTable&gt;(data);
          return obj;
      }
  
      public override bool CanReadType(Type type)
      {
          return true;
      }
  
      public override bool CanWriteType(Type type)
      {
          return true;
      }
  }
  </code></pre>
  
  <h2>CONTROLLER</h2>
  
  <pre><code>[Route("{unit}/{begindate}/{enddate}/{stringifiedjsondata}")]
  [HttpPost]
  public void Post(string unit, string begindate, string enddate, DataTable stringifiedjsondata)
  {
      DataTable dt = stringifiedjsondata;
      . . .
  </code></pre>
  
  <h2>CLIENT</h2>
  
  <pre><code>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);
  }
  </code></pre>
  
  <p>...but the Controller is still not reached; specifically, the breakpoint in "DataTable dt = dtPassedAsJson;" is never reached.</p>
  
  <p>Actually, it kind of surprises me that it doesn't crash, as a string is being passed, yet the data type there declared is "DataTable"</p>
  
  <h2>UPDATE 2</h2>
  
  <p>I also tried this, after realizing it's not really a stringified/jsonized DataTable that I'm passing from the client, but a stringified/jsonized generic list:</p>
  
  <h2>WEB API CONTROLLER</h2>
  
  <pre><code>[Route("{unit}/{begindate}/{enddate}/{stringifiedjsondata}")]
  [HttpPost]
  public void Post(string unit, string begindate, string enddate, List&lt;ProduceUsage&gt; stringifiedjsondata)
  {
      List&lt;ProduceUsage&gt; _produceUsageList = stringifiedjsondata;
  </code></pre>
  
  <h2>WebApiConfig.cs</h2>
  
  <p>I added this to the Register method:</p>
  
  <pre><code>config.Formatters.Add(new GenericProduceUsageListMediaTypeFormatter());
  </code></pre>
  
  <p>...and this new class:</p>
  
  <pre><code>// 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&lt;List&lt;ProduceUsage&gt;&gt;(data);
          return obj;
      }
  
      public override bool CanReadType(Type type)
      {
          return true;
      }
  
      public override bool CanWriteType(Type type)
      {
          return true;
      }
  }
  </code></pre>
  
  <p>Still, though, the main breakpointed line in the Controller:</p>
  
  <pre><code>List&lt;ProduceUsage&gt; _produceUsageList = stringifiedjsondata;
  </code></pre>
  
  <p>...is not reached.</p>