简体   繁体   English

AutoMapper ProjectTo <>()找不到地图

[英]AutoMapper ProjectTo<>() not finding map

I have a ASP.NET 5 (running on 4.6.2, not Core) application. 我有一个ASP.NET 5(运行在4.6.2,而不是Core)应用程序。 I wanted to use the ProjectTo<>() method of AutoMapper to project the results from the database to my viewmodels. 我想使用AutoMapper的ProjectTo <>()方法将数据库的结果投影到我的viewmodels。

I've tried alot of tests, but it seems that the map solely cannot be found when using the ProjectTo<>(). 我已经尝试了很多测试,但似乎在使用ProjectTo <>()时无法找到地图。 Using mapper.Map<>() on different locations with the same model and viewmodel perfectly works. 在具有相同模型和viewmodel的不同位置上使用mapper.Map <>()非常有效。

I guess there is something wrong with how AutoMapper works with my DI (Autofac), but I can't figure out what. 我想AutoMapper如何与我的DI(Autofac)一起工作有问题,但我无法弄清楚是什么。

Anyway, the code: 无论如何,代码:

Startup.Cs Startup.Cs

 public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            (...)

            // Autofac DI
            AutofacContainer = AutofacLoader.Configure(services).Build();

            return AutofacContainer.Resolve<IServiceProvider>();
        }

AutofacLoader.cs AutofacLoader.cs

public static ContainerBuilder Configure(IServiceCollection services)
        {
            var builder = new ContainerBuilder();

(...)


            // AutoMapper
            builder.RegisterModule<AutoMapperModule>();

            if (services != null)
            { 
                builder.Populate(services);

            }
            return builder;
        }

AutoMapperModule.cs AutoMapperModule.cs

public class AutoMapperModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        var mapping = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile(new Core.Mappings.AutoMapperProfileConfiguration());
            cfg.AddProfile(new Dieet.Core.Mappings.AutoMapperProfileConfiguration());
        });
        builder.RegisterInstance(mapping.CreateMapper()).As<IMapper>().AutoActivate();
    }
}

The test that fails with 'Missing map from Patient to PatientViewModel. 测试因“从患者到患者视图缺失地图”而失败。 Create using Mapper.CreateMap'. 使用Mapper.CreateMap创建'。

   [Fact]
    public async void InfohosServiceReturnsPatientViewModels()
    {
        var db = _container.Resolve<IInfohosDb>();

        var search = new PaginatedSearchBase();
        search.OrderBy = "Naam";

        var mapper = _container.Resolve<IMapper>();

        var result = await search.PagedResultAsAsync<Patient,PatientViewModel >(null,db.Patienten,mapper);
    }

PaginatedSearchBase PaginatedSearchBase

public class PaginatedSearchBase
{
    public string OrderBy { get; set; }
    public bool OrderDescending { get; set; }
    public int Page { get; set; } = 1;
    public int PageSize { get; set; } = 10;
}

And finally the extension that calls the ProjectTo 最后是调用ProjectTo的扩展

public static class PagedResultExtensions
{
    public static async Task<PagedResult<T>> PagedResultAsync<T>(this PaginatedSearchBase vm, ICollection<Expression<Func<T, bool>>> whereCollection, IEnumerable<T> context) where T : class
    {
        int totalCount;
        var query = PrepareQuery(vm, whereCollection, context, out totalCount);

        return new PagedResult<T>
        {
            Results = await query.ToListAsync(),
            Page = vm.Page,
            PageSize = vm.PageSize,
            Total = totalCount
        };
    }
    public static async Task<PagedResult<TAs>> PagedResultAsAsync<T, TAs>(this PaginatedSearchBase vm, ICollection<Expression<Func<T, bool>>> whereCollection, IEnumerable<T> context, IMapper mapper) where T : class
    {
        int totalCount;
        var query = PrepareQuery(vm, whereCollection, context, out totalCount);

        return new PagedResult<TAs>
        {
----------> Results = await query.ProjectTo<TAs>(mapper).ToListAsync(),
            Page = vm.Page,
            PageSize = vm.PageSize,
            Total = totalCount
        };
    }

    private static IQueryable<T> PrepareQuery<T>(PaginatedSearchBase vm, ICollection<Expression<Func<T, bool>>> whereCollection, IEnumerable<T> context,
        out int totalCount) where T : class
    {
        var query = context.AsQueryable();
        if (whereCollection != null)
        {
            foreach (var w in whereCollection)
            {
                if (w != null)
                {
                    query = query.Where(w);
                }
            }
        }
        // Order by
        query = query.OrderBy($"{vm.OrderBy} {(vm.OrderDescending ? "DESC" : "ASC")}");

        // Total rows
        totalCount = query.Count();

        // Paging
        query = query.Skip((vm.Page - 1)*vm.PageSize).Take(vm.PageSize);
        return query;
    }
}

For information, I'm using versions: 有关信息,我正在使用版本:

  • "Autofac": "4.0.0-rc1-177" “Autofac”:“4.0.0-rc1-177”
  • "Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177" “Autofac.Extensions.DependencyInjection”:“4.0.0-rc1-177”
  • "AutoMapper": "4.2.1" “AutoMapper”:“4.2.1”

Edit: 编辑:

A new test that I did to check if the mappings really work: 我做的一个新测试,用于检查映射是否真的有效:

var mapper = _container.Resolve<IMapper>();
        var p = new Patient();
        p.Naam = "Test";
        var vm = mapper.Map<PatientViewModel>(p);

        vm.Naam.ShouldBeEquivalentTo("Test");

This test passes 这个测试通过

Edit 2: 编辑2:

When I use the Map<> in a Select() instead, it works too, so it's really the ProjectTo<>() that fails: 当我在Select()中使用Map <>时,它也可以工作,所以它实际上是ProjectTo <>()失败:

var results = await query.ToListAsync();
        return new PagedResult<TAs>
        {
            Results = results.Select(mapper.Map<TAs>).ToList(),
            Page = vm.Page,
            PageSize = vm.PageSize,
            Total = totalCount
        };

This works, but it requires the mapper to be included and not be injected and it doesn't use the ProjectTo that Automapper has for database access... 这是有效的,但它需要包含映射器而不是注入,并且它不使用Automapper用于数据库访问的ProjectTo ...

I ran into the same issue but managed to get it working. 我遇到了同样的问题,但设法让它工作。 This is happening due to the recent move, by Automapper, away from having the entire API use static methods. 这是由于Automapper最近采取的措施,而不是让整个API使用静态方法。 Now that everything is instance-based, the static extension methods no longer know about the mapping configuration and they now have to be passed into the method. 现在一切都是基于实例的,静态扩展方法不再知道映射配置,现在必须将它们传递给方法。 I ended up registering an instance of the MapperConfiguration as IConfigurationProvider (I'm using Unity) 我最终注册了一个MapperConfiguration实例作为IConfigurationProvider(我正在使用Unity)

container.RegisterInstance(typeof (IConfigurationProvider), config);

This is injected into my query handler: 这被注入我的查询处理程序:

[Dependency]
public IConfigurationProvider MapperConfigurationProvider { get; set; }

Finally, the MapperConfigurationProvider is passed to the call to ProjectTo: 最后,将MapperConfigurationProvider传递给对ProjectTo的调用:

.ProjectTo<Payment>(MapperConfigurationProvider);

Hope this helps. 希望这可以帮助。

You don't have to specifically add ConfigurationProvider to DI. 您无需专门将ConfigurationProvider添加到DI。 If you already added the IMapper to DI, than you can read ConfigurationProvider from the Mapper itself. 如果您已经将IMapper添加到DI,那么您可以从Mapper本身读取ConfigurationProvider。 Example: I had the same problem and created a base class containing IMapper that got injected: 示例:我遇到了同样的问题并创建了一个包含IMapper的基类:

public abstract class ServiceBase { public IMapper Mapper { get; set; } }

This class was inherited in all my Services that used AutoMapper. 这个类在我使用AutoMapper的所有服务中继承。 Now every time any of my services needed to Map something, they did so: 现在,每当我的任何服务需要映射某些内容时,他们都会这样做:

    return context.SomeEntity
        .Where(e => e.Id == filter.Id)
        .ProjectTo<EntityDto>(Mapper.ConfigurationProvider).ToList();

With Mapper being injected. 随着Mapper被注入。 As long as you put the completely configured Mapper in DI, you're ok. 只要你把完全配置的Mapper放在DI中,你就可以了。

container.Register(Component.For<IMapper>().UsingFactoryMethod(x =>
    {
        return new AutoMapperConfig().ConfigureMapper();
    })
    );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM