2013-03-26 2 views
4

Я пытаюсь выяснить безумие, лежащее в основе маршрутизации веб-API.Как я могу MapHttpRoute POST выполнить пользовательское действие с помощью WebApi?

При попытке опубликовать данные, как это:

curl -v -d "test" http://localhost:8088/services/SendData 

Я получаю 404, и следующее сообщение об ошибке:

{"Message":"No HTTP resource was found that matches the request URI 'http://localhost:8088/services/SendData'.","MessageDetail":"No action was found on the controller 'Test' that matches the request."} 

Вот код для моего тестового сервера.

public class TestController : ApiController 
{ 

    [HttpPost] 
    public void SendData(string data) 
    { 
     Console.WriteLine(data); 
    } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 

     var config = new HttpSelfHostConfiguration("http://localhost:8088"); 

     config.Routes.MapHttpRoute(
      name: "API Default", 
      routeTemplate:"services/SendData", 
      defaults: new { controller = "Test", action = "SendData"}, 
      constraints: null); 

     using (var server = new HttpSelfHostServer(config)) 
     { 
      server.OpenAsync().Wait(); 
      Console.WriteLine("Press Enter to quit."); 
      Console.ReadLine(); 
     } 

    } 
} 

В целом, почему команда ASP.NET решила сделать метод MapHttpRoute настолько запутанным. Почему требуется два анонимных объекта ... как кто-то должен знать, какие свойства действительно нужны этим объектам?

MSDN не дает никакой помощи: http://msdn.microsoft.com/en-us/library/hh835483(v=vs.108).aspx

Все боль динамически типизированных языка без каких-либо пользы, если вы спросите меня ...

ответ

2

Используйте эту подпись, и она будет работать каждый раз.

public class TestController : ApiController 
{ 
    [HttpPost] 
    [ActionName("SendData")] 
    public HttpResponseMessage SendData(HttpRequestMessage request) 
    { 
     var data = request.Content.ReadAsStringAsync().Result; 
     Console.WriteLine(data); 
    } 
} 
+0

Это работает ... и атрибут ActionName на самом деле не нужен. – Darragh

+1

@ Darragh Имя действия потребуется, если у вас есть несколько методов с атрибутом HttpPost. –

8

с вами согласен, это ад безумие, вам нужно указать, что параметр data должен быть связан с полезной нагрузкой POST, так как веб-API автоматически предполагает, что он должен быть частью строки запроса (поскольку это простой тип):

public void SendData([FromBody] string data) 

И сделать безумие еще хуже вам нужно предварять полезную нагрузку POST с = (да, это не опечатка, это знак равенства):

curl -v -d "=test" http://localhost:8088/services/SendData 

Вы можете прочитать больше о безумии в this article ,

Или остановите безумие и попробуйте ServiceStack.

+0

Да, это может быть проблемой, если вы используете кодировку URL-кода, а не для json. –

+0

Безумие только потому, что все отчаянно пытаются притвориться, что мы не используем HTTP. Если вы не понимаете, какой тип носителя передается, и как Web API имеет дело с переданными типами носителей, почему кто-то удивляется, когда он не волшебным образом работает. –

+0

@DarrelMiller В какой-то момент, когда поведение не работает должным образом, оно перестает быть программистом и начинает быть ошибкой инструментов. Если дизайн инструмента не может удовлетворить метафорию, которую он пытается абстрагировать, это не проблема программиста, это плохой выбор дизайна. – mythz

0

Попробуйте со следующими изменениями,

public class TestController : ApiController 
{ 
    [HttpPost] 
    [ActionName("SendData")] 
    public void SendData(string data) 
    { 
     Console.WriteLine(data); 
    } 
} 

Атрибут ActionName может исправить эту проблему. В противном случае, вы можете также название конвенции «Сообщение»

public void Post(string data) 
{ 
    Console.WriteLine(data); 
} 

И отправить HTTP Post непосредственно «услуг» без SendData.