在ASP.NET MVC中使用AutoMapper QueryableExtensions和Entity Framework会导致“操作可能破坏运行时的稳定性”异常

问题描述 投票:2回答:2

请考虑以下代码:

protected override IEnumerable<IListModel> GetListInternal(
    IQueryModel2<Contact> queryModel) {
    /// Causes exception
    return this.Query(queryModel).Project().To<ContactListModel>().AsEnumerable();

    /// Does not cause exception
    return Mapper.Map<IQueryable<Contact>, IEnumerable<ContactListModel>>(this.Query(queryModel)).ToList();
}

当第一行返回时,我得到异常:操作可能会破坏运行时的稳定性。当第二行返回时它工作得很好。根据我的理解,第二次返回实际上返回一个具体的IEnumerable<ContactListModel>,但第一次返回没有。如果我将.AsEnumerable()ToArray().ToList()追加到第一次回归并不重要,我只是继续获得例外。因此,必须有一些关于Project()返回的东西。无论它返回什么,可能是一个IEnumerable<ContactListModel>因此传递方法的返回要求,但它的具体对象是在它进一步处理管道时导致异常。

具体来说,此方法返回的集合将传递到执行最终处理的ListWrapper<TEntity>类。当我在集合上调用.Count()时,总会抛出异常。

我绝望地寻求关于通过预测解决问题的指导,因为第二次回报非常低效。从MiniProfiler告诉关于这个特定代码使用的页面,我正在制作1204个SQL查询,带有重复项,我想我们所有人都同意这是一个问题...提前感谢任何建议!

这是Query()IQueryModel2<TEntity>的样子:

public IQueryable<TEntity> Query(
    IQueryModel2<TEntity> queryModel = null) {
    return this.QueryInternal(queryModel);
}

private IQueryable<TEntity> QueryInternal(
    IQueryModel2<TEntity> queryModel) {
    IQueryable<TEntity> entities = this.Context.Set<TEntity>();

    if (queryModel != null) {
        if (queryModel.Entities != null) {
            entities = queryModel.Entities.AsQueryable();
        }

        if (queryModel.Predicate != null) {
            entities = entities.AsExpandable().Where(queryModel.Predicate);
        }
    }

    return entities;
}

public interface IQueryModel2<TEntity> {
    IEnumerable<TEntity> Entities { get; set; }

    Expression<Func<TEntity, bool>> Predicate { get; set; }

    SearchPostModel Search { get; set; }
}

更新(1)

public sealed class ContactListModel :
    ListModel {
    [Display(Order = 3)]
    public string Email { get; set; }
    [Display(Order = 1)]
    public string Name { get; set; }
    [Display(Order = 2)]
    public string Phone { get; set; }
    [Display(Order = 4)]
    public ContactType ContactType { get; set; }
}

internal sealed class ContactToContactListModel :
    Profile {
    protected override void Configure() {
        base.Configure();

        base.CreateMap<Contact, ContactListModel>()
            .ForMember(
                d => d.Name,
                o => o.MapFrom(
                    s => (s.FirstName + " " + s.LastName)))
            .IgnoreAllUnmapped();
    }
}

更新(2)

public static class AutoMapperExtensions {
    public static IMappingExpression<TSource, TDestination> IgnoreAllUnmapped<TSource, TDestination>(
        this IMappingExpression<TSource, TDestination> expression) {
        if (expression == null) {
            return null;
        }

        return IgnoreAllUnmappedInternal<TSource, TDestination>(expression, typeof(TSource), typeof(TDestination));
    }

    private static IMappingExpression<TSource, TDestination> IgnoreAllUnmappedInternal<TSource, TDestination>(
        IMappingExpression<TSource, TDestination> expression,
        Type sourceType,
        Type destinationType) {
        IEnumerable<string> unmappedProperties = Mapper.GetAllTypeMaps().First(
            m =>
                m.SourceType.Equals(sourceType)
                && m.DestinationType.Equals(destinationType)).GetUnmappedPropertyNames();

        foreach (string unmappedProperty in unmappedProperties) {
            expression.ForMember(unmappedProperty, o => o.Ignore());
        }

        return expression;
    }
}

更新3

因此,我将项目的程序集加载到LinqPad中并重新编写查询代码。感谢来自LinqPad的惊人的.Dump()方法,我能够观察到返回的物体究竟是什么。因此,第一个返回默认返回DbQuery<T>,第二个返回默认返回IList<T>。具有讽刺意味的是,当我在LinqPad中调用完全相同的代码序列时,它不会抛出异常,我得到了我期待的ListWrapper。我真的不确定为什么它在ASP.NET MVC中不起作用。虽然我甚至不确定它是ASP.NET的错,因为它在代码中崩溃,这是一个不同程序集中的库项目......

由于LinqPad没有出现问题,我仍然对如何修复此异常感到茫然。不确定它是否重要,但我在解决方案的所有项目中都以.NET 4.5.2为目标,所以我不确定它是否与此相关?

c# asp.net-mvc automapper
2个回答
0
投票

将Automapper升级到v3.2.0。

这解决了我遇到的确切问题。


0
投票

对于使用VSTest平台(mstests运行良好)在AzureDevOps的构建管道中运行的测试,回到同样的异常,从Automapper 7.0.1开始。支持这些测试的最后一个版本的Automapper是6.2.2。

从另一个答案和their github issue来看,在我看来这是一个回归错误。

© www.soinside.com 2019 - 2024. All rights reserved.