You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用IdentityDbContext时BreezeJS AspNetCore无法返回元数据

问题:使用IdentityDbContext时Breeze返回元数据抛出空引用异常

我在结合IdentityDbContext和Breeze使用时,访问元数据接口时遇到了空引用错误,相关代码和错误信息如下:

上下文代码

public partial class MyContext : IdentityDbContext<ApplicationUser, ApplicationRole, string> {
    public MyContext(DbContextOptions options) : base(options) { }
    protected override void OnModelCreating(ModelBuilder modelBuilder) {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<ApplicationUser>().HasMany(u => u.Claims).WithOne().HasForeignKey(c => c.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
        modelBuilder.Entity<ApplicationUser>().HasMany(u => u.Roles).WithOne().HasForeignKey(r => r.UserId).IsRequired().OnDelete(DeleteBehavior.Cascade);
        modelBuilder.Entity<ApplicationRole>().HasMany(r => r.Claims).WithOne().HasForeignKey(c => c.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);
        modelBuilder.Entity<ApplicationRole>().HasMany(r => r.Users).WithOne().HasForeignKey(r => r.RoleId).IsRequired().OnDelete(DeleteBehavior.Cascade);
    }
}

ConfigureServices配置

// add identity
services.AddIdentity<ApplicationUser, ApplicationRole>()
    .AddEntityFrameworkStores<MyContext>()
    .AddDefaultTokenProviders();

Breeze控制器代码

[Route("breeze/[action]")]
[BreezeQueryFilter]
public class DefaultController : Controller {
    private readonly NyContext _context;
    private readonly UnitOfWork _unitOfWork;
    private readonly MyPersistenceManager _persistenceManager;
    // called via DI
    public DefaultController(MyContext context) {
        _context = context;
        _unitOfWork = new UnitOfWork(context);
        _persistenceManager = new MyPersistenceManager(context);
    }
    [HttpGet]
    public IActionResult Metadata() {
        return Ok(_persistenceManager.Metadata());
    }
    [HttpPost]
    public SaveResult SaveChanges([FromBody] JObject saveBundle) {
        return _unitOfWork.Commit(saveBundle);
    }
}

错误信息

{"$id":"1","$type":"Breeze.AspNetCore.ErrorDto, Breeze.AspNetCore.NetCore","Code":0,"Message":"Object reference not set to an instance of an object.","StackTrace":" at Breeze.Persistence.EFCore.MetadataBuilder.BuildAssocName(INavigation prop) in C:\git\Breeze\breeze.server.net\AspNetCore\Breeze.Persistence.EFCore\MetadataBuilder.cs:line 138\r\n at Breeze.Persistence.EFCore.MetadataBuilder.CreateNavProperty(INavigation p) in C:\git\Breeze\breeze.server.net\AspNetCore\Breeze.Persistence.EFCore\MetadataBuilder.cs:line 128\r\n at System.Linq.Enumerable.WhereSelectEnumerableIterator2.ToList()\r\n at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n at Breeze.Persistence.EFCore.MetadataBuilder.CreateMetaType(IEntityType et, Dictionary2 dbSetMap) in C:\\git\\Breeze\\breeze.server.net\\AspNetCore\\Breeze.Persistence.EFCore\\MetadataBuilder.cs:line 89\r\n at System.Linq.Enumerable.WhereSelectEnumerableIterator2.ToList()\r\n at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n at Breeze.Persistence.EFCore.MetadataBuilder.GetMetadataFromContext(DbContext dbContext) in C:\\git\\Breeze\\breeze.server.net\\AspNetCore\\Breeze.Persistence.EFCore\\MetadataBuilder.cs:line 21\r\n at Breeze.Persistence.EFCore.EFPersistenceManager1.BuildJsonMetadata() in C:\git\Breeze\breeze.server.net\AspNetCore\Breeze.Persistence.EFCore\EFPersistenceManager.cs:line 109\r\n at Breeze.Persistence.PersistenceManager.Metadata() in C:\git\Breeze\breeze.server.net\AspNetCore\Breeze.Persistence\PersistenceManager.cs:line 34\r\n at DictionaryPortalServer.Controllers.DefaultController.Metadata() in C:\Users\MrTou\Documents\Visual Studio 2017\Projects\Dictionary Project\DP Server\DictionaryPortalServer\Controllers\DefaultController.cs:line 32\r\n at lambda_method(Closure , Object , Object[] )\r\n at Microsoft.Extensions.Internal.ObjectMethodExecutor.Execute(Object target, Object[] parameters)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14."


问题分析与解决方案

从堆栈信息可以看出,错误发生在Breeze的MetadataBuilder.BuildAssocName方法中,这是因为EF Core模型中的导航属性缺少对应的逆导航关联信息,导致Breeze无法构建关联名称时抛出空引用。

核心原因

你在OnModelCreating中手动重复配置了Identity默认的实体关系,但IdentityDbContext的基类已经为ApplicationUser.Claims、ApplicationUser.Roles、ApplicationRole.Claims、ApplicationRole.Users这些导航属性配置了完整的关联(包括逆导航)。手动使用.WithOne()而不指定逆导航,会覆盖基类的配置,导致EF Core模型中丢失了这些导航属性的关联元数据,Breeze在解析时就会报错。

修复步骤

  1. 移除重复的Identity关系配置
    修改你的MyContext类,删除OnModelCreating中重复的Identity实体关系配置,保留基类的默认配置即可:

    public partial class MyContext : IdentityDbContext<ApplicationUser, ApplicationRole, string> {
        public MyContext(DbContextOptions options) : base(options) { }
        protected override void OnModelCreating(ModelBuilder modelBuilder) {
            base.OnModelCreating(modelBuilder);
            // 这里只保留你自定义的其他实体配置(如果有的话),不要重复配置Identity默认的关系
        }
    }
    
  2. 确认PersistenceManager的继承关系
    确保你的MyPersistenceManager正确继承自EFPersistenceManager<MyContext>,这样Breeze才能正确处理你的Identity实体元数据:

    public class MyPersistenceManager : EFPersistenceManager<MyContext> {
        public MyPersistenceManager(MyContext context) : base(context) { }
    }
    
  3. 验证Identity实体的继承
    确认ApplicationUser和ApplicationRole正确继承自Identity的基类,没有错误修改默认导航属性:

    public class ApplicationUser : IdentityUser<string> {
        // 你的自定义属性
    }
    
    public class ApplicationRole : IdentityRole<string> {
        // 你的自定义属性
    }
    

完成这些修改后,重新启动服务,访问http://localhost:3333/Breeze/MetaData应该就能正常获取元数据了。

内容的提问来源于stack exchange,提问作者MrTouya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 06:19:52