Sprawa wygląda tak, że mam kontroler api ,do którego wstrzykuje serwis, do którego wstrzykuje dwa repozytoria, do których wstrzykuje ten sam kontekst entity frameworka.
Serwis, repozytoria i kontekst wstrzykiwany jest w zakresie per request.
Problem jest taki, że jak wykonam metodę API:
Post(IEnumerable<SponsoredDiscountAddOrUpdateViewModel> viewModels)
która
- wykonuje metodę AddOrUpdate serwisu, który:
- Wykonuje metodę GetAsync repozytorium
- Wykonuje Clear na repozytorium
- Wykonuje Add na repozytorium
- Wykonuje metodę GetAsync na repozytorium - w tym miejscu się zawiesza! bez tej linii leci dalej
Co może być powodem zawieszenia? Nie dostaje, żadnego wyjątku, po prostu request do bazy trwa a nieskończoność i nigdy nie wraca odpowiedź.
Kod:
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;
}
}
Service:
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;
}
}
Repositories:
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)
{
}
}
ContexT:
public class Context
{
public virtual DbSet<SponsoredBrand> Brands { get; set; }
public virtual DbSet<SponsoredDiscount> Discounts { get; set; }
public Context()
{
}
}
IoC configuration(Ninject):
kernel.Bind<Context>().ToSelf();
kernel.Bind<ISponsoredService>().To<SponsoredService>().InRequestScope();
kernel.Bind<ISponsoredBrandsRepository>().To<SponsoredBrandsRepository>().InRequestScope();
kernel.Bind<ISponsoredDiscountsRepository>().To<SponsoredDiscountsRepository>().InRequestScope();```csharp