使用IEnumerable <interface>类型参数</interface> POST到Web API操作

时间:2013-11-20 18:12:48

标签: c# asp.net asp.net-mvc asp.net-web-api dotnet-httpclient

我正在尝试从客户端发布到Web API方法,如下所示:

// Create list of messages that will be sent
IEnumerable<IMessageApiEntity> messages = new List<IMessageApiEntity>();
// Add messages to the list here. 
// They are all different types that implement the IMessageApiEntity interface.

// Create http client
HttpClient client = new HttpClient {BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiUrl"])};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

// Post to web api
HttpResponseMessage response = client.PostAsJsonAsync("Communications/Messages", messages).Result;

// Read results
IEnumerable<ApiResponse<IMessageApiEntity>> results = response.Content.ReadAsAsync<IEnumerable<ApiResponse<IMessageApiEntity>>>().Result;

我的Web API控制器操作如下所示:

public HttpResponseMessage Post([FromBody]IEnumerable<IMessageApiEntity> messages)
{
    // Do stuff
}

我遇到的问题是,当进入Web API控制器操作时, messages始终为空(但不为空)。我在调试器中验证了客户端上的messages对象在发布之前确实包含了项目。

我怀疑它可能与在尝试传递对象时没有转换为具体类型的接口类型有关,但我不知道如何使其工作。我怎样才能做到这一点?

3 个答案:

答案 0 :(得分:7)

我想出了如何在没有自定义模型绑定器的情况下完成它。发布答案以防其他人有此问题......

客户端:

// Create list of messages that will be sent
IEnumerable<IMessageApiEntity> messages = new List<IMessageApiEntity>();
// Add messages to the list here. 
// They are all different types that implement the IMessageApiEntity interface.

// Create http client
HttpClient client = new HttpClient {BaseAddress = new Uri(ConfigurationManager.AppSettings["WebApiUrl"])};
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

// Post to web api (this is the part that changed)
JsonMediaTypeFormatter json = new JsonMediaTypeFormatter
{
    SerializerSettings =
    {
        TypeNameHandling = TypeNameHandling.All
    }
};
HttpResponseMessage response = client.PostAsync("Communications/Messages", messages, json).Result;

// Read results
IEnumerable<ApiResponse<IMessageApiEntity>> results = response.Content.ReadAsAsync<IEnumerable<ApiResponse<IMessageApiEntity>>>().Result;

在WebApiConfig.cs中添加Register方法:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

关键是将类型作为json的一部分发送并打开自动类型名称处理,以便Web API可以确定它是什么类型。

答案 1 :(得分:0)

为什么在方法中使用接口类型?看起来像Web API,不知道应该使用什么样的实例来实现消息参数。似乎您必须为此操作编写自定义模型绑定器。

答案 2 :(得分:0)

几周前我使用.NET Core WebAPI遇到了类似的问题。 建议的添加以下行的解决方案对我不起作用:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

我最终创建了一个可以携带我的IEnumerable的通用对象,其中T是我想要的类

[Serializable]
public class GenericListContainer<T> where T : class
{
    #region Constructors

    public GenericListContainer()
    {

    }

    public GenericListContainer(IEnumerable<T> list)
    {
        List = list;
    }
    #endregion

    #region Properties

    public IEnumerable<T> List { get; set; }

    #endregion
}

然后我将我的webapi方法更改为:

[Route("api/system-users/save-collection-async")]
[HttpPost]
[ProducesResponseType(typeof(string), 200)]       
public async Task<IActionResult> SaveSystemUserCollectionAsync([FromBody] GenericListContainer<SystemUser> dto)
{
    var response = await _systemUserService.SaveSystemUserCollectionAsync(dto.List);
    return Ok(response);
}

此方法返回已保存用户的ID(在我的情况下为Guid)。

希望这有助于其他人!