7

Core problem: GET works, POST doesn't. I'm new to WebAPI so I'm probably doing something stupid, but I've poked around quite a bit on the 'net trying to figure out why this isn't working.

Fairly simple WebAPI C# app. I've tried to get this down to very simple routes:

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

        // Add a route where action is supplied, i.e. api/csv/LoadToSQL
        config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}"
        );

Controller class:

public class CsvController : ApiController
{
    // GET api/csv
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/csv/name
    public string Get(string csvName)
    {
        return "value";
    }

    // POST - api/csv/LoadToSQL
    // Load a CSV to SQL
    [HttpPost]
    [ActionName("LoadToSQL")]
    public HttpResponseMessage LoadToSQL(
        string storageAccount,
        string accessKey,
        string containerName,
        string csvFileName,
        string connectionString,
        string targetDatabaseName,
        string targetTableName)
    {
        try
        {
            // Retrieve storage account from connection string.
            CloudStorageAccount blobStorage = CloudStorageAccount.Parse(storageAccount);

Start it up locally and connect Fiddler. Try a GET; works:

Fiddler GET output

Try a POST - fails:

Fiddler POST output

My original implementation had just

    // POST - api/csv
    // Load a CSV to SQL
    public HttpResponseMessage Post(

but that didn't work so I started trying to add specific routes and verb decorations.

It just doesn't seem to see the POST action against this controller no matter what I do.

Any thoughts?

UPDATE - per answer below, the correct route to make this work is:

        // Add a route where action is supplied, i.e. api/csv/LoadToSQL
        config.Routes.MapHttpRoute(
            name: "ActionApi",
            routeTemplate: "api/{controller}/{action}/{storageAccount}/{accessKey}/{containerName}/{csvFileName}/{connectionString}/{targetDatabaseName}/{targetTableName}"
        );

This shows all the parameters to the POST request.

Mike Kelly
  • 969
  • 1
  • 12
  • 23
  • 1
    you are expecting multiple parameters but your route only has one, so your method cannot be resolved. Either add all the parameters to the route {storageAccount}/{accessKey}/etc..., or pass a single object that has the properties you need. – dbugger Dec 06 '14 at 03:10
  • Can you please provide your sample post request ? – dotnetstep Dec 06 '14 at 03:14
  • OK, like I said... something stupid. THANK YOU @dbugger... That wss in fact it. I was trying to pass the parameters as query parameters. Will update the Route to show the fix that made this work. – Mike Kelly Dec 06 '14 at 03:17

1 Answers1

2

You can replace your method to be more clear and clean if you like so

1- declare a class with your options

public class LoadToSqlData
{
   public string storageAccount {get; set;}
   public string accessKey {get; set;}
   public string containerName {get; set;}
   public string csvFileName {get; set;}
   public string connectionString {get; set;}
   public string targetDatabaseName {get; set;}
   public string targetTableName {get; set;}
}

2- Declare your method to be :

[HttpPost]
[ActionName("ActionApi")]
[Route("api/Csv/LoadToSQL")]
public HttpResponseMessage LoadToSQL([FromBody]LoadToSqlData data)

Notice the usage of the [Route],[ActionName] and the [FromBody] attributes.

Hope that helps.

Shimnas
  • 13
  • 4
Omar.Alani
  • 4,050
  • 2
  • 20
  • 31
  • This works - as does the earlier suggestion, but this is probably a better way to go as the earlier responder noted. I updated this to fix a minor error - the members of the class should be public. – Mike Kelly Dec 13 '14 at 23:32