对情境的第二次操作永无止境。请求范围中的一个上下文两个存储库

时间:2017-06-27 13:58:17

标签: c# entity-framework ninject

我有部分界面

public partial interface ISponsoredService { GetX(), AddX() }
public partial interface ISponsoredService { GetY(), AddY() }

部分实施

public partial class SponsoredService : ISponsoredService {
     public SponsoredService(
        ISponsoredBrandsRepository sponsoredBrandRepository, 
        ISponsoredDiscountsRepository sponsoredDiscountsRepository) { } 
}

public partial class SponsoredService { GetX(); AddX(); }
public partial class SponsoredService { GetY(); AddY(); }

问题在于这些存储库,因为它们使用了与服务和存储库等请求范围中注入相同的context

public class SponsoredDiscountsRepository : BaseSponsoredRepository, ISponsoredDiscountsRepository 
{
    public SponsoredDiscountsRepository(
        Context sponsoredContext) : base(sponsoredContext)
    {
    }
}
public class SponsoredBrandsRepository : BaseSponsoredRepository, ISponsoredBrandsRepository  
    {
        public SponsoredBrandsRepository (
            Context sponsoredContext) : base(sponsoredContext)
        {
        }
    }

Ninject配置:

        kernel.Bind<Context>().ToSelf();
        kernel.Bind<ISponsoredService>().To<SponsoredService>().InRequestScope();
        kernel.Bind<ISponsoredBrandsRepository>().To<SponsoredBrandsRepository>().InRequestScope();
        kernel.Bind<ISponsoredDiscountsRepository>().To<SponsoredDiscountsRepository>().InRequestScope();

问题出在哪里?

当我在相同的HTTP请求中执行AddX()然后GetX()时,第二个操作(GetX())会挂起与基础的连接。它永远持续,永不止息。

但是如果我AddX()然后在其他HTTP请求中GetX()它就可以了。 组合AddY()和同一请求GetX()中的组合也不起作用。

这里发生了什么?上下文未被处理,因为它是在请求范围中创建的。在同一请求范围中创建SponsoredService,其中包含repository1repository2,其中包含已创建的context

编辑:添加存储库的实施 这两个存储库使用一个通用的wchich包含:

    protected readonly Context SponsoredContext;
    protected readonly DbSet<TEntity> DbSet;

以及所有操作:

    public virtual async Task<IEnumerable<TEntity>> GetAsync()
    {
        return await this.DbSet.ToListAsync();
    }

    GetX() { sponsoredBrandsRepository.GetAsync(); }
    AddX() {
       sponsoredBrandsRepository.GetAsync();
       some operations
       sponsoredBrandsRepository.AddAsync();
    }

修改添加完整代码 的的WebAPI:

[RoutePrefix("api/sponsored")]
public partial class SponsoredController : BaseApiController
{
    private readonly ISponsoredService _sponsoredService;

    public SponsoredController(
        ISponsoredService sponsoredService, 
        IBrandService brandService, 
        ICampaignsService discountService)
    {
        _sponsoredService = sponsoredService;
        _discountService = discountService;
        _brandService = brandService;
    }
}
public partial class SponsoredController
{
    private readonly IBrandService _brandService;

    [Route("brands"), HttpGet]
    public async Task<IHttpActionResult> GetBrands()
    {
        try
        {
            var viewModels = await GetBrandViewModels();
            return Ok(viewModels);
        }
        catch (Exception e)
        {
            base.Log(e);
            return InternalServerError();
        }
    }

    [Route("brands"), HttpPost, ValidateModelStateFilter]
    public async Task<IHttpActionResult> Post([FromBody] IEnumerable<SponsoredBrandAddOrUpdateViewModel> viewModels)
    {
        try
        {
            await this._sponsoredService.AddOrUpdate(viewModels.Select(vm => (SponsoredBrand)vm));
            return Created("api/sponsored/brands", GetBrandViewModels());
        }
        catch (Exception e)
        {
            base.Log(e, viewModels);
            return InternalServerError();
        }
    }


    private async Task<List<SponsoredBrandListViewModel>> GetBrandViewModels()
    {
        var dbSponsoredBrands = await this._sponsoredService.GetSponsoredBrandsAsync();
        var viewModels =
            dbSponsoredBrands.Select(sponsoredBrand =>
            {
                var viewModel = (SponsoredBrandListViewModel)sponsoredBrand;
                viewModel.Name = (this._brandService.GetBrandByBrandIdAsync(viewModel.BrandId).Result).Entity.Name;
                return viewModel;
            }).ToList();
        return viewModels;
    }
}

  public partial class SponsoredController
{
    private readonly ICampaignsService _discountService;

    [Route("discounts"), HttpGet]
    public async Task<IHttpActionResult> GetDiscounts()
    {
        try
        {
            var viewModels = await GetDiscountsViewModels();
            return Ok(viewModels);
        }
        catch (Exception e)
        {
            base.Log(e);
            return InternalServerError();
        }
    }
    [Route("discounts"), HttpPost, ValidateModelStateFilter]
    public async Task<IHttpActionResult> Post([FromBody] IEnumerable<SponsoredDiscountAddOrUpdateViewModel> viewModels)
    {
        try
        {
            await this._sponsoredService.AddOrUpdate(viewModels.Select(vm => (SponsoredDiscount)vm));
            return Created("api/sponsored/discounts", GetDiscountsViewModels());
        }
        catch (Exception e)
        {
            base.Log(e, viewModels);
            return InternalServerError();
        }
    }

    private async Task<List<SponsoredDiscountListViewModel>> GetDiscountsViewModels()
    {
        var dbSponsoredBrands = await this._sponsoredService.GetSponsoredDiscountsAsync();
        var viewModels =
            dbSponsoredBrands.Select(sponsoredBrand =>
            {
                var viewModel = (SponsoredDiscountListViewModel)sponsoredBrand;
                viewModel.Name = (this._discountService.GetCampaignByCampaignIdAsync(viewModel.DiscountId).Result)?.Entity?.Discount?.Name;
                return viewModel;
            }).ToList();
        return viewModels;
    }
}

服务

public partial interface ISponsoredService
{
    Task<IEnumerable<SponsoredDiscount>> GetSponsoredDiscountsAsync();
    Task<IEnumerable<SponsoredDiscount>> AddOrUpdate(IEnumerable<SponsoredDiscount> sponsoredDiscounts);

}
public partial interface ISponsoredService
{
    Task<IEnumerable<SponsoredDiscount>> GetSponsoredDiscountsAsync();
    Task<IEnumerable<SponsoredDiscount>> AddOrUpdate(IEnumerable<SponsoredDiscount> sponsoredDiscounts);
}

 public partial class SponsoredService : ISponsoredService
{
    public SponsoredService(
        ISponsoredBrandsRepository sponsoredBrandRepository, 
        ISponsoredDiscountsRepository sponsoredDiscountsRepository, 
        IBrandService brandService, 
        ICampaignsService discountsService)
    {
        _sponsoredBrandRepository = sponsoredBrandRepository;
        _brandService = brandService;
        _discountsService = discountsService;
        _sponsoredDiscountsRepository = sponsoredDiscountsRepository;
    }
}
public partial class SponsoredService
{
    private readonly ISponsoredBrandsRepository _sponsoredBrandRepository;
    private readonly IBrandService _brandService;

    public async Task<IEnumerable<SponsoredBrand>> GetSponsoredBrandsAsync() => await this._sponsoredBrandRepository.GetAsync();


    public async Task<IEnumerable<SponsoredBrand>> AddOrUpdate(IEnumerable<SponsoredBrand> sponsoredBrands)
    {
        // remove
        var dbSponsored = await this.GetSponsoredBrandsAsync();
        foreach (var dbS in dbSponsored)
        {
            if (!sponsoredBrands.Any(s => s.RelatedEntityId == dbS.RelatedEntityId))
            {
                await this.DeleteSponsoredBrand(dbS.Id);
            }
        }

        // new 
        foreach (var newS in sponsoredBrands)
        {
            var brand = (await this._brandService.GetBrandByBrandIdAsync(newS.RelatedEntityId)).Entity;
            brand.BrandRules = new List<BrandRule>
            {
                new BrandRule
                {
                    IsHighlighted = true, Order = newS.Order, ValidTo = newS.To, ValidFrom = newS.From
                }
            }.ToList();
            await this._brandService.UpdateAsync(brand);
        }

        this._sponsoredBrandRepository.Clear();
        await this._sponsoredBrandRepository.Add(sponsoredBrands);
        return null;
    }

}
 public partial class SponsoredService
{

    private readonly ISponsoredDiscountsRepository _sponsoredDiscountsRepository;
    private readonly ICampaignsService _discountsService;

    public async Task<IEnumerable<SponsoredDiscount>> GetSponsoredDiscountsAsync()
        => await this._sponsoredDiscountsRepository.GetAsync();

    public async Task<IEnumerable<SponsoredDiscount>> AddOrUpdate(IEnumerable<SponsoredDiscount> sponsoredDiscounts)
    {
        // remove
        var dbSponsored = await this.GetSponsoredDiscountsAsync();
        foreach (var dbS in dbSponsored)
            if (!sponsoredDiscounts.Any(s => s.RelatedEntityId == dbS.RelatedEntityId))
                await this.DeleteSponsoredDiscount(dbS.Id);

        // new 
        foreach (var newS in sponsoredDiscounts)
            if (!await this._discountsService.X(newS.RelatedEntityId, newS))
                return null;

        this._sponsoredDiscountsRepository.Clear();
        await this._sponsoredDiscountsRepository.Add(sponsoredDiscounts);
        return null;
    }   
}

存储库:

    public interface ISponsoredRepository<TEntity> : IBaseRepository<TEntity, int>
        where TEntity : Sponsored.Sponsored
    {
        void Clear();
        Task Add(IEnumerable<TEntity> entities);
    }
    public interface ISponsoredBrandsRepository : ISponsoredRepository<SponsoredBrand> { }
    public interface ISponsoredDiscountsRepository : ISponsoredRepository<SponsoredDiscount> { }


public abstract class SponsoredRepository<TEntity> : ISponsoredRepository<TEntity>
        where TEntity : Domain.Sponsored.Sponsored
    {
        protected readonly Context SponsoredContext;
        protected readonly DbSet<TEntity> DbSet;

        protected SponsoredRepository(Context sponsoredContext)
        {
            SponsoredContext = sponsoredContext;
            DbSet = this.SponsoredContext.Set<TEntity>();
        }

        public virtual async Task<IEnumerable<TEntity>> GetAsync()
        {
            return await this.DbSet.ToListAsync();
        }



        public virtual void Clear()
        {
            this.DbSet.RemoveRange(this.DbSet);
            this.SponsoredContext.SaveChanges();
        }

        public virtual async Task Add(IEnumerable<TEntity> entities)
        {
            this.DbSet.AddRange(entities);
            await this.SponsoredContext.SaveChangesAsync();
        }
    }

      public class SponsoredBrandsRepository : SponsoredRepository<SponsoredBrand>, ISponsoredBrandsRepository
    {
        public SponsoredBrandsRepository(
            Context sponsoredContext) : base(sponsoredContext)
        {
        }
    }

     public class SponsoredDiscountsRepository : SponsoredRepository<SponsoredDiscount>, ISponsoredDiscountsRepository
    {
        public SponsoredDiscountsRepository(
            Context sponsoredContext) : base(sponsoredContext)
        {
        }
    }

上下文

public class Context
{
    public virtual DbSet<SponsoredBrand> Brands { get; set; }
    public virtual DbSet<SponsoredDiscount> Discounts { get; set; }


    public Context()
    {

    }

}

IoC配置(Ninject):

       kernel.Bind<Context>().ToSelf();
        kernel.Bind<ISponsoredService>().To<SponsoredService>().InRequestScope();
        kernel.Bind<ISponsoredBrandsRepository>().To<SponsoredBrandsRepository>().InRequestScope();
        kernel.Bind<ISponsoredDiscountsRepository>().To<SponsoredDiscountsRepository>().InRequestScope();

1 个答案:

答案 0 :(得分:1)

您没有绑定上下文InRequestScope,因此默认情况下它会被创建为Transient范围,因此可能没有被处理/关闭。

更多关于范围: https://github.com/ninject/ninject/wiki/Object-Scopes

管理请求中的单个DbContext很难。您可能有许多不同的类请求它作为依赖项并以不同的方式使用它。我最终得到了一个复杂的范围机制来管理DbContexts。但是,注入DbContext工厂可能更容易/更好,并使用using来控制DbContext(工作单元模式)的生命周期,或者仅在存储库中new处理它(并将其置于其中) )。

如果您使用Google&#34;实体框架dbcontext请求&#34;,您会发现很多关于此事的讨论和意见。这是一个很好的概述/介绍:http://mehdi.me/ambient-dbcontext-in-ef6/