C# 自动映射器和父类型列表未映射子类型

C# Automapper and List of parent type not mapping childs

提问人:ICos 提问时间:11/17/2023 最后编辑:Qiang FuICos 更新时间:11/17/2023 访问量:64

问:

我尝试映射 FirewallRule 的子级,当控制器收到有效负载时,firewallDto 不会与 DestinationPorts 映射。 数据被剪裁,结构在 FirewallRule 处停止。

我尝试了 AutoMapper 的多个映射配置文件,但它不起作用,搜索了所有内容,但没有得到预期的结果。 如果我读取正文并删除 firewallDto,则有效负载看起来符合预期,因此我认为我尝试过的映射不够好,或者我错过了一些我看不到的东西。

总而言之,如果 DestinationPorts 位于有效负载中,则映射到 NetworkRule,如果 FqdnTags 位于标记中,则映射到 ApplicationRule。

如果我在帖子中遗漏了某些内容,我会对其进行编辑。

有效载荷:

{
  "id": 0,
  "name": "string",
  "priority": 0,
  "action": "string",
  "rules": [
        {
            "ruleType": "NetworkRule",
            "name": "myName",
            "description": "mydescription",
            "DestinationPorts": [""]
        }
  ]
}

它在控制器中的外观:

{
  "id": 0,
  "name": "string",
  "priority": 0,
  "action": "string",
  "rules": [
        {
            "ruleType": "NetworkRule",
            "name": "myName",
            "description": "mydescription"
        }
  ]
}

法典:

// Classes
public class Firewall 
{
    public string Name { get; set; }
    public int Priority { get; set; }
    public string Action { get; set; }
    public List<FirewallRule> Rules { get; set; }
}

public class FirewallRule
{
    public string RuleType { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class ApplicationRule : FirewallRule
{
    public string[] FqdnTags { get; set; }
}

public class NetworkRule : FirewallRule
{
    public string[] DestinationPorts { get; set; }
}

public class FirewallDto
{
    public string Name { get; set; }
    public int Priority { get; set; }
    public string Action { get; set; }
    public List<FirewallRuleDto> Rules { get; set; }
}

public class FirewallRuleDto
{
    public string RuleType { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}

public class NetworkRuleDto : FirewallRuleDto
{
    public string[] DestinationPorts { get; set; }
}

public class ApplicationRuleDto : FirewallRuleDto
{
    public string[] FqdnTags { get; set; }
}
// Mapping
CreateMap<Firewall, FirewallDto>().
    ReverseMap();

CreateMap<FirewallRule, FirewallRuleDto>()
    .Include<NetworkRule, NetworkRuleDto>()
    .Include<ApplicationRule, ApplicationRuleDto>().
    ForMember(dest => dest.RuleType, opt => opt.MapFrom(src => src.RuleType));

CreateMap<NetworkRule, NetworkRuleDto>()
    .ReverseMap();

CreateMap<ApplicationRule, ApplicationRuleDto>()
    .ReverseMap();

CreateMap<FirewallRuleDto, FirewallRule>()
    .Include<NetworkRuleDto, NetworkRule>()
    .Include<ApplicationRuleDto, ApplicationRule>();

CreateMap<FirewallDto, Firewall>().
    ForMember(d => d.Rules, op => op.MapFrom(s => s.Rules));
// Controller
public async Task<ActionResult<Firewall>> NewFirewall(FirewallDto firewallDto) 
{
    // code
}

尝试了自动映射器的多个映射配置文件、简单的类、在谷歌上抓取自动映射器配置、搜索 stackoverflow 以及从 chat-gipity 中搜索想法但没有成功。

C# ASP.Net-Core .net-core 自动映射器

评论

0赞 Qiang Fu 11/21/2023
有效负载中的 DestinationPorts 是否为空?
0赞 ICos 12/1/2023
是的。我发现我可以在课堂上使用类型描述符,但这并不完全是我想要的......

答:

0赞 Qiang Fu 11/27/2023 #1

我认为模型过于复杂。在控制器中,FirewallDto 不会收到足够的有效负载,因为它没有“DestinationPorts”或“FqdnTags”的属性。您可以使它们为空属性,以便使这些属性接收。然后有条件地将它们映射到正确的模型。您可以尝试以下操作:
防火墙规则库.cs
NewFirewall(FirewallDto firewallDto)

    public class FirewallRuleBase
    {
        public string RuleType { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
    }

防火墙规则.cs

    public class FirewallRule : FirewallRuleBase
    {
        public string[]? DestinationPorts { get; set; }
        public string[]? FqdnTags { get; set; }
    }

应用程序规则 .cs

    public class ApplicationRule : FirewallRuleBase
    {
        public string[] DestinationPorts { get; set; }
    }

网络规则.cs

    public class NetworkRule : FirewallRuleBase
    {
        public string[] FqdnTags { get; set; }
    }

条件图

if (firewallRule.GetType().GetProperty("DestinationPorts"))
{
    result = _mapper.map<ApplicationRule>(userInfo);
}
if (firewallRule.GetType().GetProperty("FqdnTags"))
{
    result = _mapper.map<NetworkRule>(userInfo);
}