我有一个简单的 web 应用程序,客户端有 angular,服务器端有 asp.net core web-api。我使用 InMemoryDatabase

services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));

存储数据以简化开发。但我遇到了一个问题。我在 web-api 上有一个 Controller 来响应用户的请求:
[Route("api/[controller]")]
public class ItemsController : Controller
{
    private readonly IApiService apiService;

    public ItemsController(IApiService apiService)//using DI from Startup.cs
    {
       this.apiService = apiService;
    }

    [HttpPost, Route("addItem")]
    public async Task<Response> Add([FromBody]Item item)
    {
        return await apiService.Add(item);
    }

    [HttpDelete("{id}")]
    public async Task<Response> Delete(int id)
    {
        return await apiService.Delete(id);
    }

    [HttpPut]
    public async Task<Response> Put([FromBody]Item item)
    {
         return await apiService.Put(item);
    }
}

以及以下 Startup.cs 配置:
public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddDbContext<ItemsContext>(options => options.UseInMemoryDatabase("ItemsDB"));
    services.AddSingleton<IUnitOfWork, UnitOfWork>(provider => {
        var context = services.BuildServiceProvider().GetService<ItemsContext>();
        return new UnitOfWork(context);
    });
    services.AddSingleton<IApiService, ApiService>(provider => {
        return new ApiService(services);
    });
}

问题是,当我添加新项目时,一切都很好......但是然后我发布了另一个删除该项目的请求,它可能会显示根本没有这样的项目,或者有时它可能会删除它......所以换句话说,数据库存在然后消失,我不确定什么时候。这是引用上述的一些附加代码
public class ApiService: IApiService
{
    private readonly IUnitOfWork database;
    private readonly IServiceProvider provider;

    public ApiService(IServiceCollection serviceCollection)
    {
        provider = serviceCollection.BuildServiceProvider();
    }

    public IUnitOfWork Database
    {
        get
        {
            return provider.GetService<IUnitOfWork>();
        }
    }

    public async Task<Response> Add(Item item)
    {
        Database.Items.Add(item);
        await Database.SaveAsync();

        var id = Database.Items.LastItem().Id;
        return new Response() { Result = true, ItemId = id };
    }

    public async Task<Response> Delete(int id)
    {
        var item = await db.Items.Find(id);
        Database.Items.Remove(item);
        await Database.SaveAsync();

        return new Response() { Result = true };
    }

    public async Task<Response> Put(Item item)
    {
        Database.Items.Update(item);
        await Database.SaveAsync();
        return new Response() { Result = true };
    }
}

更新:
UnitOfWork 实现:

 public class UnitOfWork: IUnitOfWork
{
    private readonly DbContext context;
    private IRepository<Item> itemsRepository;

    public UnitOfWork(DbContext dbContext)
    {
        context = dbContext;
    }

    public IRepository<Item> Items
    {
        get
        {
            return itemsRepository ?? (itemsRepository = new Repository<Item>(context));
        }
    }

    public void Dispose()
    {
        context.Dispose();
    }

    public void Save()
    {
        context.SaveChanges();
    }

    public async Task SaveAsync()
    {
        await context.SaveChangesAsync();
    }
}

最佳答案

你的代码有多个严重的问题,让我们来看看它们。

  • services.AddDbContext 添加了一个 Scoped 服务,这意味着将在每个请求上创建和处理实例。 services.AddSingleton 添加了一个 Singleton 服务,因此只会创建一个实例。您不能将范围服务添加到单例服务中,因为单例服务使用的引用将被释放,并且最终会得到一个已释放的上下文。
  • 这段代码:
    return provider.GetService<IUnitOfWork>();
    

    表示服务定位器反模式。您可以猜到,反模式是您想要避免的。我也不知道为什么你想要一个服务来构建整个 DI 容器,也不知道为什么你想要一个服务有责任获取它自己需要的依赖项。
  • 这部分是您的问题的实际来源:
    Database.SaveAsync();
    

    您正在调用异步函数而不是 await 来完成它。任务可能完成也可能没有完成,它可能会抛出错误或不,你永远不会知道发生了什么。

  • 最好的事情是,如果人们不再尝试在另一个工作单元和存储库上创建一个工作单元 + 存储库模式,那么所有这些都可以避免。 Entity Framework Core 已经实现了这些:
    DbContext => Unit of Work
    DbSet => Repository (generic)
    

    为什么你想要另一个抽象?您真的会从项目中丢弃 EF Core 以证明代码的维护成本是合理的吗?

    整个问题代码可能是这样的:
    [Route("api/[controller]")]
    public class ItemsController : Controller
    {
        private readonly YourContext _context;
    
        public ItemsController(YourContext context)
        {
           _context = context;
        }
    
        [HttpPost]
        public async Task<IActionResult> Add([FromBody]Item item)
        {
            context.Items.Add(item);
            await context.SaveChangesAsync();
    
            return Ok(item.Id);
        }
    
        [HttpDelete("{id}")]
        public async Task<IActionResult> Delete(int id)
        {
            context.Items.Remove(item);
            await context.SaveChangesAsync();
    
            return Ok();
        }
    
        [HttpPut]
        public async Task<IActionResult> Put([FromBody]Item item)
        {
            context.Items.Update(item);
            await context.SaveChangesAsync();
    
            return Ok();
        }
    }
    

    关于c# - 内存数据库不保存数据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/50457007/

    10-11 01:39
    查看更多