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.
相关产品推荐
相关产品推荐

