Привязка модели ASP.Net Web API не работает, как в MVC 3
У меня создалось впечатление, что привязка к модели в ASP.Net Web API должна поддерживать привязку с тем же минимальным уровнем функциональности, который поддерживается MVC.
Возьмите следующий контроллер:
public class WordsController : ApiController
{
private string[] _words = new [] { "apple", "ball", "cat", "dog" };
public IEnumerable<string> Get(SearchModel searchSearchModel)
{
return _words
.Where(w => w.Contains(searchSearchModel.Search))
.Take(searchSearchModel.Max);
}
}
public class SearchModel
{
public string Search { get; set; }
public int Max { get; set; }
}
Я запрашиваю его с помощью
http://localhost:62855/api/words?search=a&max=2
К сожалению, модель не связывается, как в MVC. Почему это не является обязательным, как я ожидал? В моем приложении у меня будет много разных типов моделей. Было бы неплохо, если бы привязка просто работала, как в MVC.
Ответы
Ответ 1
Взгляните на это: Как WebAPI выполняет привязку параметров
Вам нужно украсить свой сложный параметр следующим образом:
public IEnumerable<string> Get([FromUri] SearchModel searchSearchModel)
ИЛИ
public IEnumerable<string> Get([ModelBinder] SearchModel searchSearchModel)
Ответ 2
Я нашел, что весь Web API 2 является сложной кривой обучения с большим количеством "Gotchas". Я прочитал несколько ключевых книг, которые охватывают многие тайные нюансы этого богатого предложения продуктов. Но в основном, я думал, что должна быть какая-то основная функциональность, которая могла бы воспользоваться лучшими функциями. Итак, я решил выполнить четыре прямые задачи.
1. Примите строку запроса из браузера в Api2 Client и заполните простую .NET-модель.
2. Попросите клиента отправить сообщение async на сервер Api2, закодированный в JSON, извлеченный из предыдущей модели
3. Попросите сервер сделать тривиальное преобразование в почтовом запросе от Клиента.
4. Передайте все обратно в браузер. Это он.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Combined.Controllers // This is an ASP.NET Web Api 2 Story
{
// Paste the following string in your browser -- the goal is to convert the last name to lower case
// The return the result to the browser--You cant click on this one. This is all Model based. No Primitives.
// It is on the Local IIS--not IIS Express. This can be set in Project->Properties=>Web http://localhost/Combined with a "Create Virtual Directory"
// http://localhost/Combined/api/Combined?FirstName=JIM&LastName=LENNANE // Paste this in your browser After the Default Page it displayed
//
public class CombinedController : ApiController
{
// GET: api/Combined This handels a simple Query String request from a Browser
// What is important here is that populating the model is from the URI values NOT the body which is hidden
public Task<HttpResponseMessage> Get([FromUri]FromBrowserModel fromBrowser)
{
//
// The Client looks at the query string pairs from the Browser
// Then gets them ready to send to the server
//
RequestToServerModel requestToServerModel = new RequestToServerModel();
requestToServerModel.FirstName = fromBrowser.FirstName;
requestToServerModel.LastName = fromBrowser.LastName;
// Now the Client send the Request to the Server async and everyone awaits the Response
Task<HttpResponseMessage> response = PostAsyncToApi2Server("http://localhost/Combined/api/Combined", requestToServerModel );
return response; // The response from the Server should be sent back to the Browser from here.
}
async Task<HttpResponseMessage> PostAsyncToApi2Server(string uri, RequestToServerModel requestToServerModel)
{
using (var client = new HttpClient())
{
// Here the Method waits for the Request to the Server to complete
return await client.PostAsJsonAsync(uri, requestToServerModel)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
}
}
// POST: api/Combined This Handles the Inbound Post Request from the Client
// NOTICE THE [FromBody] Annotation. This is the key to extraction the model from the Body of the Post Request-- not the Uri ae in [FromUri]
// Also notice that there are no Async methods here. Not required, async would probably work also.
//
public HttpResponseMessage Post([FromBody]RequestToServerModel fromClient)
{
//
// Respond to an HttpClient request Synchronously
// The model is serialised into Json by specifying the Formatter Configuration.Formatters.JsonFormatter
// Prep the outbound response
ResponseToClientModel responseToClient = new ResponseToClientModel();
//
// The conversion to lower case is done here using the Request Body Data Model
//
responseToClient.FirstName = fromClient.FirstName.ToLower();
responseToClient.LastName = fromClient.LastName.ToLower();
//
// The Client should be waiting patiently for this result
//
using (HttpResponseMessage response = new HttpResponseMessage())
{
return this.Request.CreateResponse(HttpStatusCode.Created, responseToClient, Configuration.Formatters.JsonFormatter); // Respond only with the Status and the Model
}
}
public class FromBrowserModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class RequestToServerModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class ResponseToClientModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}
}