You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AutoMapper中Null映射到Nullable Float失败问题求助

问题描述

定义的模型

namespace WebApplication1Sample.Models
{
    public class ModelOne
    {
        public int Id { get; set; }
        public float? Prop1 { get; set; }
        public float? Prop2 { get; set; }
    }
}

AutoMapper映射配置

using WebApplication1Sample.Models;
using AutoMapper;
using Newtonsoft.Json.Linq;
using System.Reflection;

namespace App.Mappings
{
    public class AutoMapperModelOne : Profile
    {
        public AutoMapperModelOne()
        {
            CreateMap<JToken, ModelOne>()
            .ForAllMembers(opt =>
            {
                MemberInfo propDestination = opt.DestinationMember;
                string propName = propDestination.Name;

                opt.MapFrom(src => src.SelectToken(propName));

                opt.Condition((src, des, srcMember) =>
                {
                    if (srcMember == null)
                    {
                        return false;
                    }

                    //map all
                    return true;
                });
            });
        }
    }
}

映射调用代码

[HttpPost]
[Route("mo")]
public void ModelOneMap()
{
    JToken tokenSample = new JObject();
    tokenSample["Id"] = 1232323;
    tokenSample["Prop1"] = 1;
    tokenSample["Prop2"] = null;

    ModelOne app =  _mapper.Map<ModelOne>(tokenSample);
    Console.WriteLine(app.Id);
}

抛出的异常

AutoMapper.AutoMapperMappingException: Error mapping types.

Mapping types:
JToken -> ModelOne
Newtonsoft.Json.Linq.JToken -> WebApplication1Sample.Models.ModelOne

Type Map configuration:
JToken -> ModelOne
Newtonsoft.Json.Linq.JToken -> WebApplication1Sample.Models.ModelOne

Destination Member:
Prop2

 ---> System.ArgumentException: Can not convert Null to Single.
   at Newtonsoft.Json.Linq.JToken.op_Explicit(JToken value)
   at lambda_method4(Closure , Object , ModelOne , ResolutionContext )
   --- End of inner exception stack trace ---
   at lambda_method4(Closure , Object , ModelOne , ResolutionContext )
   at WebApplication1Sample.Controllers.WeatherForecastController.ModelOneMap() in C:\Users\prosy.arceno\Desktop\C sharp\WebApplication1Sample\WebApplication1Sample\Controllers\WeatherForecastController.cs:line 35
   at Microsoft.Extensions.Internal.ObjectMethodExecutor.<>c__DisplayClass33_0.<WrapVoidMethod>b__0(Object target, Object[] parameters)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.VoidResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

目标属性Prop2是可空float类型,但传入Null值时仍抛出异常,需实现跳过源中所有Null值映射到目标的需求。


解决方案

问题根源

当前Condition逻辑依赖srcMember参数判断是否为null,但AutoMapper在执行Condition之前,会先尝试将src.SelectToken(propName)的结果转换为目标成员的类型(即float?)。对于JToken中的Null值(JValue.Null),显式转换为float会直接抛出异常,导致Condition根本没机会执行,这就是报错的核心原因。

修复方案

改用PreCondition(在获取源值之前执行判断),直接检查源JToken中的属性值是否为Null,避免触发转换操作:

修改后的AutoMapper配置:

using WebApplication1Sample.Models;
using AutoMapper;
using Newtonsoft.Json.Linq;
using System.Reflection;

namespace App.Mappings
{
    public class AutoMapperModelOne : Profile
    {
        public AutoMapperModelOne()
        {
            CreateMap<JToken, ModelOne>()
            .ForAllMembers(opt =>
            {
                MemberInfo propDestination = opt.DestinationMember;
                string propName = propDestination.Name;

                opt.MapFrom(src => src.SelectToken(propName));

                // 改用PreCondition,在获取源值前判断是否为Null
                opt.PreCondition(src => 
                {
                    var token = src.SelectToken(propName);
                    // 排除Null和JToken类型的Null值
                    return token != null && token.Type != JTokenType.Null;
                });
            });
        }
    }
}

另一种可选方案

如果需要保留Condition,可以直接在判断逻辑中访问源JToken的属性,不依赖srcMember:

opt.Condition((src, des, _, context) => 
{
    var propName = ((MemberInfo)context.MemberMap.DestinationMember).Name;
    var token = src.SelectToken(propName);
    return token != null && token.Type != JTokenType.Null;
});

两种方案都能实现:当源JToken中的属性为Null时,跳过该属性的映射,不会触发转换异常。


内容的提问来源于stack exchange,提问作者Prosy A.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 00:22:02