我正在处理.NET Core 6,但我被卡住了。我正在使用自动映射器,并且设置了依赖注入。
我的实现:
public class LSif : ISif
{
private readonly DataContext _db;
private readonly IMemoryCache _memoryCache;
public LSif(DataContext db, IMemoryCache memoryCache)
{
_db = db;
_memoryCache = memoryCache;
}
public List<DropDown> MjernaJedinicaDD(int selected)
{
string key = "MjernaJedinicaDD" + selected;
List<DropDown> dd = new List<DropDown>();
if (!_memoryCache.TryGetValue(key, out dd))
{
var model = GetAllMjernaJedinica();
if (model != null)
{
foreach (var item in model)
{
dd.Add(
new DropDown()
{
Id = item.Id,
Name = item.Name,
Selected = selected
}
);
}
}
var cacheEntryOptions = new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromSeconds(30));
_memoryCache.Set(key, dd, cacheEntryOptions);
}
return dd;
}
}
我的目标是从自动映射器解析器调用该实现方法:
.ForMember(d => d.MjernaJedinicaDD, o => o.MapFrom<MjernaJedinicaDDArtikal>());
解析器如下所示:
public class MjernaJedinicaDDArtikal : IValueResolver<Artikal, ArtikalVM, List<DropDown>>
{
public List<DropDown> Resolve(Artikal source, ArtikalVM destination, List<DropDown> member, ResolutionContext context)
{
var services = new ServiceCollection(); // With this i shoud work
services.AddScoped<ISif, LSif>(); // but i doesn't
using ServiceProvider serviceProvider = services.BuildServiceProvider(validateScopes: true);
using (IServiceScope scope = serviceProvider.CreateScope())
{
ISif reff = scope.ServiceProvider.GetRequiredService<ISif>();
if (reff != null)
{
return reff.MjernaJedinicaDD(source.MjernaId);
}
}
return null;
// This is how I did it in .NET Framework 4.5
var lSif = new LSif();
return lSif.MjernaJedinicaDD(source.MjernaId);
}
}
问题:如何从AutoMapper自定义解析器实例化/访问具有依赖注入组件(参数)的类?
附加信息:我使用
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
}
然后
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
ApplyMappingsFromAssembly(Assembly.GetExecutingAssembly());
}
private void ApplyMappingsFromAssembly(Assembly assembly)
{
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Any(i =>
i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IMapFrom<>)))
.ToList();
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("Mapping") ??
type.GetInterface("IMapFrom`1").GetMethod("Mapping");
methodInfo?.Invoke(instance, new object[] { this });
}
}
}
和节目中的结局.cs
builder.Services.AddAutoMapper(Assembly.GetExecutingAssembly());
在启动期间对 NuGet 包提供的IServiceCollection
调用AddAutoMapper
扩展方法之一AutoMapper.Extensions.Microsoft.DependencyInjection
时,这将执行多项操作,包括:
- 添加自定义值解析程序(例如
MjernaJedinicaDDArtikal
) 到依赖注入 (DI) 容器 - 配置
Mapper
以解析实现AutoMapper
接口(如IValueResolver
)的自定义组件所需的容器中的依赖项
(有关AddAutoMapper
方法的功能的其他详细信息,请参阅 NuGet 包的自述文件。
这允许您使用构造函数注入直接提供自定义值解析程序所需的依赖项。这些依赖项将从 DI 容器解析,并且它们还可以要求容器本身的其他依赖项。
您的自定义值解析程序变为:
public class MjernaJedinicaDDArtikal : IValueResolver<Artikal, ArtikalVM, List<DropDown>>
{
private readonly ISif _isif;
public MjernaJedinicaDDArtikal(ISif isif)
{
_isif = isif ?? throw new ArgumentNullException(nameof(isif));
}
public List<DropDown> Resolve(Artikal source, ArtikalVM destination, List<DropDown> member, ResolutionContext context)
{
return _isif.MjernaJedinicaDD(source.MjernaId);
}
}
以下是使用自定义值解析程序的自动映射器配置文件的简化版本:
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Artikal, ArtikalVM>()
.ForMember(dest => dest.MjernaJedinicaDD, src => src.MapFrom<MjernaJedinicaDDArtikal>());
}
}
最后,使用LSif
类以及LSif
类所需的任何依赖项将ISif
服务添加到容器中。
对具有 .NET 6 或更高版本的 ASP.NET Core 应用使用最小托管模型时,请将以下代码片段添加到Program.cs
(默认 .NET 模板中包含的某些行包含在内以提供上下文):
// TODO: add 'using' directives for namespace(s) containing ISif and LSif
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews(); // or other similar method
// Register DataContext, which is injected into LSif
// TODO: Fill in app-specific implementation
// Register IMemoryCache implementation for injection into LSif
builder.Services.AddMemoryCache(options =>
{
// TODO: fill in desired cache options
});
// Register ISif service using LSif implementation
builder.Services.AddTransient<ISif, LSif>();
builder.Services.AddAutoMapper(Assembly.GetExecutingAssembly());
// ...
var app = builder.Build();
对于可能想要使用类似方法但使用没有最小托管模型的早期版本的 ASP.NET Core 的其他人(例如,ASP.NET Core 3.1 或 5.0 与通用主机),请将自定义服务注册添加到Startup.ConfigureServices(IServiceCollection)
,而不是使用builder.Services.AddXyz
将它们添加到Program.cs
中。例如:
public void ConfigureServices(IServiceCollection services)
{
// ...
// Register DataContext, which is injected into LSif
// TODO: Fill in app-specific implementation
// Register IMemoryCache implementation for injection into LSif
services.AddMemoryCache(options =>
{
// TODO: fill in desired cache options
});
// Register ISif service using LSif implementation
services.AddTransient<ISif, LSif>();
services.AddAutoMapper(Assembly.GetExecutingAssembly());
// ...
}
AutoMapper
可以使用应用程序的默认 DI 容器解析依赖项的方式是,AddAutoMapper
扩展方法将 IServiceProvider.GetService(Type) 方法作为serviceCtor
参数传递给Mapper
构造函数(源,v11.0.0)。
旁注:您可能还想调整您的LSif.MjernaJedinicaDD
方法,以避免将NullReferenceException
扔在线以进行dd.Add(...)
。调用_memoryCache.TryGetValue(key, out dd)
后,当TryGetValue
返回false
时,dd
将为 null,因为null
是任何 C# 引用类型(如类)的默认值,List<T>
是(引用)。