[英]AutoMapper problem with custom convert from source to destination
我正在使用 AutoMapper 將我的 db 模型與我的 api 模型映射。 但是我對自定義映射有疑問。 我將嘗試解釋我的問題:
所以我有這樣的 db 和 api 模型:
public class ApiModel
{
public List<ApiSubModel> Colors { get; set; }
}
public class DbModel
{
public string Type { get; set; }
public string Settings { get; set; }
}
通常DbModel
Settings
屬性是ApiModel
的序列化版本。 所以我想在創建映射時通過自定義轉換來實現這一點:
啟動.cs:
services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies())
映射器配置文件類:
internal class DbToApiMapping : Profile
{
public DbToApiMapping()
{
CreateMap<ApiModel, DbModel>()
.ConvertUsing((source, dest, context) => new DbModel
{
Type = context.Items["Type"].ToString(),
Settings = JsonConvert.SerializeObject(source)
});
CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return new ApiModel
{
Colors = res.Colors
};
});
}
}
對於第一張地圖,我這樣使用它:
var settings = modelMapper.Map<DbModel>(req.Settings, opt => opt.Items["Type"] = "Setpoint");
對於第二張地圖,我這樣使用它:
var ss = modelMapper.Map<ApiModel>(settings.Settings);
嘗試映射時出現的錯誤如下:
Message:
AutoMapper.AutoMapperMappingException : Missing type map configuration or unsupported mapping.
Mapping types:
Object -> ApiModel
System.Object -> CommonLibrary.Models.ApiModel
我確定我做錯了什么......但我無法完全理解到底該看什么。 對於我嘗試使用.ConvertUsing()
方法的第二個映射,但錯誤是相同的。
有人可以幫忙解決這個問題。
提前致謝
朱利安
--- 編輯---正如我在沒有 DI 的情況下嘗試的評論中所建議的那樣。 這是代碼:
class Program
{
static void Main(string[] args)
{
var config = new MapperConfiguration( cfg =>
{
cfg.CreateMap<ApiModel, DbModel>()
.ConvertUsing((source, dest, context) => new DbModel
{
Type = context.Items["Type"].ToString(),
Settings = JsonConvert.SerializeObject(source)
});
cfg.CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return new ApiModel
{
Colors = res.Colors
};
});
});
var modelMapper = config.CreateMapper();
var apiObj = new ApiModel
{
Colors = new List<ApiSubModel>
{
new ApiSubModel
{
SomeProp = "Test",
SubModel = new ApiSubSubModel
{
IntProp = 3,
StringProp = "Alabala"
}
}
}
};
DbModel dbRes = modelMapper.Map<DbModel>(apiObj, opt => opt.Items["Type"] = "Setpoint");
var dbObj = new DbModel
{
Type = "Setpoint",
Settings = "{\"Colors\":[{\"SomeProp\":\"Test\",\"SubModel\":{\"IntProp\":3,\"StringProp\":\"Alabala\"}}]}"
};
var apiRes = modelMapper.Map<ApiModel>(dbObj);
Console.WriteLine(dbRes.Settings);
Console.WriteLine(apiRes.Colors[0].SomeProp);
Console.WriteLine(apiRes.Colors[0].SubModel.StringProp);
Console.ReadLine();
}
}
public class ApiModel
{
public List<ApiSubModel> Colors { get; set; }
}
public class DbModel
{
public string Type { get; set; }
public string Settings { get; set; }
}
public class ApiSubModel
{
public string SomeProp { get; set; }
public ApiSubSubModel SubModel { get; set; }
}
public class ApiSubSubModel
{
public int IntProp { get; set; }
public string StringProp { get; set; }
}
它正在工作,但是有些奇怪,當我想調試程序並在var apiRes = modelMapper.Map<ApiModel>(dbObj);
之后放置一個斷點時並嘗試調試apiRes
的值,它說apiRes error CS0103: The name 'apiRes' does not exist in the current context
我稍微調整了你的代碼,現在它可以工作了(雖然我必須使用我自己的 JSON 和我自己的 SubApiModel)但是如果你不確定,你可以在評論中問我
我的模型
public class ApiModel
{
public List<ApiSubModel> Colors { get; set; }
}
public class ApiSubModel
{
public string Name { get; set; }
}
public class DbModel
{
public DbModel(string type, string settings)
{
Type = type;
Settings = settings;
}
public string Type { get; set; }
public string Settings { get; set; }
}
和我的 JSON
{
Colors:
[
{
"Name": "AMunim"
}
]
}
這是我的映射配置:
.CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return res;
});
這基本上反序列化了整個 JSON,並且由於它有一個屬性 Color,它是 ApiSubModel 的列表,我可以簡單地將整個字符串轉換為 Object(ApiModel 類型)。
這是我完整的測試代碼
using AutoMapper;
using Newtonsoft.Json;
using StackAnswers;
using StackAnswers.Automapper;
using System.Numerics;
DbModel dbModel = new DbModel("very important type", "{Colors: [{\"Name\": \"AMunim\"}]}");
MapperConfiguration config = new(cfg =>
{
cfg.CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return res;
});
});
Mapper mapper = new(config);
ApiModel apiModel = mapper.Map<DbModel, ApiModel>(dbModel);
Console.WriteLine(apiModel.Colors.Count);
Console.WriteLine(apiModel.Colors.FirstOrDefault()?.Name);
Console.Read();
編輯您可以單獨注冊您的配置文件/映射並強制 DI 使用它,即注冊
var config = new MapperConfiguration(c => {
//profile
c.AddProfile<DbToApiMapping>();
//mappings
c.CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return res;
});
});
//now register this instance
services.AddSingleton<IMapper>(s => config.CreateMapper());
現在,當您請求此服務時,您將獲得在您的 ctor 中應用配置的實例
public class BadClass
{
private readonly IMapper _mapper;
BadClass(IMapper mapper)
{
_mapper = mapper;
}
public void HandleFunction()
{
//here you can use this
ApiModel apiModel = _mapper.Map<DbModel, ApiModel>(dbModel);
}
}
我設法找到了我的錯誤,我不得不承認這是一個愚蠢的錯誤,但我花了很多時間來弄清楚。 問題在於var ss = modelMapper.Map<ApiModel>(settings.Settings);
看到我有這樣的Profile
:
CreateMap<DbModel, ApiModel>()
.ConstructUsing((source, context) =>
{
var res = JsonConvert.DeserializeObject<ApiModel>(source.Settings);
return new ApiModel
{
Colors = res.Colors
};
});
它期望源是一個DbModel
對象,但實際上我傳遞了這個對象的一個屬性,它實際上是一個字符串。 而且我沒有定義那種映射,這就是我得到錯誤的原因。
正確的用法必須是: var ss = modelMapper.Map<ApiModel>(settings);
所以感謝您的所有建議!
問候,朱利安
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.