来自Angular Angular的多个实例的多个API调用-线程安全吗?

时间:2019-05-08 08:19:58

标签: c# angular asp.net-web-api

我有一个Angular 7前端,它调用一个.NET Core Web API,该API本质上可以转换我的EF-Core层。我是Angular的新手,但实际上我收到以下错误:

A second operation started on this context before a previous operation completed. 
This is usually caused by different threads using the same instance of DbContext

我要打2个电话,一个要获取记录计数,另一个要检查周数据是否已处理。导航中使用了计数,另一个模块中调用了星期数据。

Angular服务

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { map, catchError, tap } from 'rxjs/operators';
import { environment } from '../environments/environment';

@Injectable({
  providedIn: 'root'
})
export class ConsumerService {

  constructor(private http: HttpClient) { }

  private extractData(res: Response) {
    let body = res;
    return body || { };
  }

  private endpoint = environment.API_URL + "/webapi/Report/";
  private httpOptions = {
    headers: new HttpHeaders({
      'Content-Type':  'application/json'
    })
  };

  getCount(): Observable<any> {
        return this.http.get(this.endpoint + 'items/count').pipe(map(this.extractData));
    }

    getOverview(): Observable<any> {
      return this.http.get(this.endpoint + 'Overview').pipe(map(this.extractData));
    }

导航栏模块

import { Component, OnInit } from "@angular/core";
import { ConsumerService } from "../../services/consumer.service";

@Component({
  selector: "app-navbar",
  templateUrl: "./navbar.component.html",
  styleUrls: ["./navbar.component.css"]
})
export class NavbarComponent implements OnInit {

  counts: any;
  new: any;
  modified: any;
  discontinued: any;

  constructor(public consumer: ConsumerService) {}

  ngOnInit() {
    this.consumer.getCount().subscribe((data: {}) => {
      this.counts = data;
      this.new = this.counts.New;
      this.discontinued = this.counts.Deleted;
      this.modified = this.counts.Modified;
    });

  }
}

控制器模块

import { Component, OnInit } from "@angular/core";
import { Subject } from "rxjs";
import { ConsumerService } from "../../services/consumer.service";

@Component({
  selector: "app-controller",
  templateUrl: "./controller.component.html",
  styleUrls: ["./controller.component.css"]
})
export class ControllerComponent implements OnInit {

  counts: any;
  new: any;
  modified: any;
  discontinued: any;
  currentWeek: any;
  allWeeks$: any;
  dtOptions: DataTables.Settings = {};
  dtTrigger: Subject<any> = new Subject();

  constructor(public consumer: ConsumerService) {}

  ngOnInit() {
    this.dtOptions = {
      searching: false,
      paging: false,
      processing: true,
      ordering: false
    };

    this.consumer.getOverview().subscribe((data: {}) => {
      this.counts = data["count"];
      this.new = this.counts.New;
      this.discontinued = this.counts.Deleted;
      this.modified = this.counts.Modified;

      this.currentWeek = data["latestEntry"];


      this.allWeeks$ = data["allEntries"];
      this.dtTrigger.next();

    });

  }

}

.NET Core API控制器

namespace ReportApi.Controllers
{
    [Route("webapi/[controller]")]
    [ApiController]
    public class ReportController : ControllerBase
    {
        private StagedReporting _reporting;

        public ReportController(StagedReporting reporting)
        {
            _reporting = reporting;
        }

        [EnableCors("MyPolicy")]
        [HttpGet("Overview")]
        public object Overview()
        {
            var response = new OverviewViewModel();

            response.LatestEntry = _reporting.GetLatestEntry();
            response.AllEntries = _reporting.GetAllEntries().OrderByDescending(a => a.id).ToList();
            response.Count = _reporting.GetChangeCount();

            return response;
        }

        [EnableCors("MyPolicy")]
        [HttpGet("items/count")]
        public object Report()
        {
             response = new Dictionary<string, int>();
             response = _reporting.GetChangeCount();
             return response;
        }
    }

分段报告

    public class StagedReporting : IDisposable
    {
        private bool _disposed;
        private IItemsDbContext _itemsDbContext;
        private entry _entry;

        public StagedReporting (IItemsDbContext itemsDbContext)
        {
            _itemsDbContext= itemsDbContext;
            _entry = GetLatestEntry();
        }

        public entry GetLatestEntry()
        {
            return _itemsDbContext.entry.OrderByDescending(e => e.id).FirstOrDefault();
        }

        public List<entry> GetAllEntries()
        {
            return _itemsDbContext.entry.OrderBy(e => e.id).ToList();
        }

        public virtual Dictionary<string, int> GetChangeCount()
        {
            var response = new Dictionary<string, int>();
            response.Add("New", GetNewEntries().Count);
            response.Add("Modified", GetModifiedEntries().Count);
            response.Add("Deleted", GetDeletedEntries().Count);

            return response;
        }

        public virtual List<ReportStagedImportNewEntries> GetNewEntries()
        {
            var newEntries = new List<ReportStagedImportNewEntries>();

            if (!_entry.processed.HasValue)
            {
                newEntries.AddRange(_itemsDbContext.ReportStagedImportNewEntries);
            }

            return newEntries;
        }

}





很显然,我希望能够从Angular进行这些调用而没有问题,但是如上所述,由于EF是线程安全的,因此出现了错误。

当我从导航栏中删除呼叫时,问题停止了。关于如何改进我的代码,接收两次调用结果的任何建议?

谢谢。

1 个答案:

答案 0 :(得分:0)

我已经回答了我自己的问题。我将我的StagedReporting创建为Singleton,将其更改为Transient,从而为每个请求创建了一个,这解决了我的问题。