System.AccessViolationException WebAPI2 Entity Framework 6

System.AccessViolationException WebAPI2 Entity Framework 6

希望有人能帮我找出一个非常隐蔽的问题。我有一个在 .NET Framework 4.7.2 上使用 Web API 2 和 Entity Framework 6 的项目。该项目多年来一直运行良好,我们最近决定在我们的项目中加入几个额外的数据库。事实证明,EF6 在不同的模型中不支持类似命名的 类。他们有一些 hacky 解决方法、自定义工具名称间距和其他类似的东西。或者,MS 和其他一些 SO 帖子建议迁移到 .NET Core 和 Core EF。已尝试迁移,但事实证明它更像是 port/re-write,因为许多 EF6 功能已弃用 EF Core。事实上,我们放弃了并决定完全重新接近。我们回滚了代码并追查了几个细微的问题,一切似乎都正常,除了在我们发布代码之前发现的一个 Class/API 调用。

    [CustomAuthorize(Roles = "admin, sales, parts")]
    [Route("api/Customer/Get")]
    [HttpPost]
    public MERP.Customer GetCustomerProfile([FromBody] Models.Generic.GuidValue _input)
    {
        MARQERPEntities ent = new MARQERPEntities();
        var cst = ent.Customers.FirstOrDefault(w => w.ID == _input.ID);
        return cst;
    }

单步执行代码,cst 变量被数据库对象填充并执行 return 步骤。但是,有效负载永远不会到达客户端。如果我打开任务管理器,IIS Express Worker Process 会一直运行,直到所有内存都用完并且出现以下错误 returned。 我有其他 API 个端点使用相同的代码模式,它们工作正常。

An unhandled exception of type 'System.AccessViolationException' occurred in Unknown Module. Attempted to read or write protected memory. This is often an indication that other memory is corrupt.

我不确定如何进行这里操作。我吹走了 EDMX 并重新开始,我删除并重新添加了客户 class。其他数据库实体已被删除。我将我们当前的 packages.config 与之前的 EF 核心更改集进行了比较,它们是相同的。

这是packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="EntityFramework" version="6.1.3" targetFramework="net472" />
  <package id="jQuery" version="3.1.1" targetFramework="net472" />
  <package id="Microsoft.AspNet.Cors" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.Mvc" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.Razor" version="3.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.Cors" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.HelpPage" version="5.2.4" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNet.WebPages" version="3.2.7" targetFramework="net472" />
  <package id="Microsoft.AspNetCore.WebUtilities" version="2.0.2" targetFramework="net472" />
  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.0.0" targetFramework="net472" />
  <package id="Microsoft.Extensions.Logging" version="2.0.2" targetFramework="net472" />
  <package id="Microsoft.Extensions.Logging.Abstractions" version="2.0.2" targetFramework="net472" />
  <package id="Microsoft.Extensions.Options" version="2.0.2" targetFramework="net472" />
  <package id="Microsoft.Extensions.Primitives" version="2.0.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.JsonWebTokens" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Logging" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Protocols" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Protocols.OpenIdConnect" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Protocols.WsFederation" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Tokens" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Tokens.Saml" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.IdentityModel.Xml" version="5.5.0" targetFramework="net472" />
  <package id="Microsoft.Net.Http.Headers" version="2.0.2" targetFramework="net472" />
  <package id="Microsoft.Owin" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.ActiveDirectory" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.Jwt" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Owin.Security.OAuth" version="4.0.1" targetFramework="net472" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net472" />
  <package id="Newtonsoft.Json" version="10.0.3" targetFramework="net472" />
  <package id="Owin" version="1.0" targetFramework="net472" />
  <package id="PuppeteerSharp" version="1.12.0" targetFramework="net472" />
  <package id="PuppeteerSharp.AspNetFramework" version="1.12.0" targetFramework="net472" />
  <package id="System.Buffers" version="4.4.0" targetFramework="net472" />
  <package id="System.IdentityModel.Tokens.Jwt" version="5.5.0" targetFramework="net472" />
  <package id="System.IO" version="4.3.0" targetFramework="net472" />
  <package id="System.Net.Http" version="4.3.3" targetFramework="net472" />
  <package id="System.Numerics.Vectors" version="4.4.0" targetFramework="net472" />
  <package id="System.Runtime" version="4.3.0" targetFramework="net472" />
  <package id="System.Runtime.CompilerServices.Unsafe" version="4.5.0" targetFramework="net472" />
  <package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net472" />
  <package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net472" />
  <package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net472" />
  <package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net472" />
  <package id="System.Text.Encodings.Web" version="4.4.0" targetFramework="net472" />
  <package id="System.Threading.Tasks.Extensions" version="4.5.1" targetFramework="net472" />
</packages>

要消除的几件事:

DbContext 没有在这样的调用中被释放。

MARQERPEntities ent = new MARQERPEntities();
var cst = ent.Customers.FirstOrDefault(w => w.ID == _input.ID);
return cst;

应该是:

using (MARQERPEntities ent = new MARQERPEntities())
{
    var cst = ent.Customers.FirstOrDefault(w => w.ID == _input.ID);
    return cst;
}

接下来,根据这个 MERP.Customer 在属性和通过导航属性的关系方面的样子,我强烈建议为 API 声明一个 DTO 到 return 而不是发送一个实体。 EF 为实体构建代理以促进诸如延迟加载之类的事情,序列化程序将选择这些代理并将其转换为具体 类。当序列化程序接触虚拟成员时,它们将触发延迟加载,这既是性能问题又可能导致异常。 (比如循环引用)这些异常可能被WebAPI执行异常屏蔽

查看为 DTO 声明一个 POCO C# 对象,其中包含您的消费者期望的客户字段,并使用 Select 或 Automapper 的 ProjectTo 填充此对象,而不是发送客户。

public CustomerDTO GetCustomerProfile([FromBody] Models.Generic.GuidValue _input)

    using (MARQERPEntities ent = new MARQERPEntities())
    {
        var cst = ent.Customers
            .Where(w => w.ID == _input.ID);
            .ProjectTo<CustomerDTO>(config)
            .SingleOrDefault();
        return cst;
    }
}

其中 config 是一个 MapperConfiguration 实例,初始化时包含有关将 Customer 映射到 CustomerDTO(以及任何相关实体到 DTO 映射)的任何详细信息

如果您必须发送整个客户图,则确保预先加载所有必需的导航引用/w Include 结合临时关闭延迟加载:

using (MARQERPEntities ent = new MARQERPEntities())
{
    ent.Configuration.LazyLoadingEnabled = false;
    var cst = ent.Customers
        .Include(w => w.Address) // as an example, Eager fetch anything you want included.
        .FirstOrDefault(w => w.ID == _input.ID);
    return cst;
}

当这第一次发生时,我不确定这种行为是如何开始的,何时开始的,也不确定原因是什么。 EDMX 是从数据库生成的,有时 EDMX 会损坏,最简单的修复方法是完全清除 EDMX 并重新加载它。发生这种情况时,延迟加载启用设置将恢复为 true。

您必须在选项卡中打开 EDMX 并转到“属性”,您将看到 ConceptualEntityModel 属性。如果您转到解决方案资源管理器 select EDMX 并转到属性,您将获得 EDMX 的文件属性。