首页 > 解决方案 > 自定义集合的 NotSupportedException

问题描述

问题:

我有一个接受 IEmail 输入的 API 端点:

[HttpPost]
[Route("SendAsync")]
public async Task SendAsync(IEmail email)
{
    await this._emailService.SendAsync(email);
}

问题似乎出在此输入的 Attachments 属性的模型绑定上。模型绑定器似乎无法反序列化到我的实现。这很奇怪,因为 IEmail 似乎没问题...

例外:

System.NotSupportedException: The collection type 'IAttachmentCollection' on 'IEmail.Attachments' is not supported.

设置:

请参阅下文了解我的 IEmail 合同和实施:

public interface IEmail
{ 
    string To { get; set; }

    string Subject { get; set; }

    string Body { get; set; }

    IAttachmentCollection Attachments { get; set; }

    bool HasAttachments { get; }
}

public class EmailMessage : IEmail
{
    public EmailMessage()
    {
        this.Attachments = new AttachmentCollection();
    }

    public string To { get; set; }

    public string Subject { get; set; }

    public string Body { get; set; }

    public IAttachmentCollection Attachments { get; set; }

    public bool HasAttachments => this.Attachments != null && this.Attachments.Any(x => x.Content.Length > 0);
}

我创建了一个自定义集合,以便可以将自定义验证添加到集合的 Add() 例程中:

public interface IAttachmentCollection : ICollection<IAttachment>
{
}

public class AttachmentCollection : IAttachmentCollection
{
    private ICollection<IAttachment> _attachments;

    public AttachmentCollection()
    {
        this._attachments = new HashSet<IAttachment>();
    }

    public void Add(IAttachment item)
    {
        // Do some custom validation on the item we are trying to add

        this._attachments.Add(item);
    }

    // Other implemented methods for ICollection<T>...
}

标签: c#asp.net-core-webapimodel-binding.net-core-3.0

解决方案


对于复杂类型,模型默认是具有默认构造函数的具体非抽象类,以便能够绑定操作。它也无法确定接口属性使用什么类Attachments

ASP.NET Core 中的参考模型绑定

创建一个反映所需对象图的模型

public class EmailModel {
    public EmailModel() {
        this.Attachments = new List<AttachmentModel>();
    }

    public string To { get; set; }

    public string Subject { get; set; }

    public string Body { get; set; }

    public List<AttachmentModel> Attachments { get; set; }

    public bool HasAttachments => this.Attachments != null && this.Attachments.Any(x => x.Content.Length > 0);
}

public class AttachmentModel {
    //...members
}

明确地将其用于操作

[HttpPost]
[Route("SendAsync")]
public async Task<IActionResult> SendAsync([FromBody]EmailModel model) {
    if(ModelState.IsValid) {
        IEmain email = new EmailMessage();

        //...code here to map model to the desired type

        await this._emailService.SendAsync(email);

        return Ok();
    }

    return BadRequest(ModelState);
}

确保将发布的数据映射到所需的类型


推荐阅读