System.AccessViolationException WebAPI2 实体框架 6

Posted

技术标签:

【中文标题】System.AccessViolationException WebAPI2 实体框架 6【英文标题】:System.AccessViolationException WebAPI2 Entity Framework 6 【发布时间】:2021-09-01 14:17:46 【问题描述】:

希望有人能帮我找出一个非常隐蔽的问题。我有一个在 .NET Framework 4.7.2 上使用 Web API 2 和 Entity Framework 6 的项目。该项目多年来一直运行良好,我们最近决定在我们的项目中加入几个额外的数据库。事实证明,EF6 不支持不同模型中类似命名的类。他们是一些 hacky 解决方法,自定义工具名称间距和其他类似的东西。或者,MS 和其他一些 SO 帖子建议迁移到 .NET Core 和 Core EF。尝试进行迁移,但事实证明它更多的是端口/重写,因为许多 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 工作进程会继续运行,直到耗尽所有内存并返回以下错误。 我有其他 API 端点使用相同的代码模式,它们工作正常。

未知模块中发生了“System.AccessViolationException”类型的未处理异常。 尝试读取或写入受保护的内存。这通常表明其他内存已损坏。

我不确定如何在此处继续。我已经炸毁了 EDMX 并重新开始,我删除并重新添加了 Customer 类。其他数据库实体已被删除。我将我们当前的 packages.config 与之前的 EF Core 变更集进行了比较,它们是相同的。

这是 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>

【问题讨论】:

您是否有任何非托管或不安全的代码? 据我所知,我不太清楚“托管”与“非托管”到底是什么。我在上面添加了 packages.config 的内容。 你能提供异常的堆栈跟踪吗? 您的项目引用了System.Runtime.CompilerServices.Unsafe,因此您的项目中可能确实有一些不安全的代码。你应该寻找Unsafe静态类的用法 在整个项目中搜索“不安全”返回 3 个结果。参考 - MERP.dll.config 【参考方案1】:

要消除的几件事:

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 在属性和通过导航属性的关系方面的外观,我强烈建议声明一个 DTO 以供 API 返回,而不是发送实体。 EF 为实体构建代理以促进诸如延迟加载之类的事情,序列化程序将拾取这些代理并将其转换为具体类。当序列化程序触及虚拟成员时,它们将触发延迟加载,这既是性能问题,也可能导致异常。 (如循环引用)这些异常可能被Web API执行异常所掩盖。

考虑为包含消费者期望的客户字段的 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;

【讨论】:

Using 语句解开实际错误并禁用 LazyLoading 解决了循环引用。我们在某些地方使用 POCO 对象,但当图表足够时避免使用它们,或者我应该说,用于....我需要调查一些事情。代理和 POCO 的相似之处在于它们可以防止延迟加载?跟进,是由 EF 自动创建的代理还是 Graph 对象的代理?_.Include 仅支持文字字符串。您如何获得 LAMBDA 支持?__我需要更好地了解如何使用 .ProjectTo_大吃一惊,谢谢! Lambda 变体是 Microsoft.EntifyFrameworkCore.QueryableExtensions 的一部分,虽然它应该是可用的 /w using Microsoft.EntifyFrameworkCore; 那是在 EF Core 3.1 中,它可能在更高版本中移动或在早期版本中不可用?我隐约记得有一次需要添加 using 引用或添加 Nuget 包来获取 Lambda 包含而不是字符串版本,但我在我的测试项目中尝试过,它似乎只对 EF 引用感到满意。 【参考方案2】:

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

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

【讨论】:

以上是关于System.AccessViolationException WebAPI2 实体框架 6的主要内容,如果未能解决你的问题,请参考以下文章