我有一个WebApi,它使用EFCore2.0和2个客户端试图同时访问一个操作方法...一个客户端一切正常。但是当2个或更多尝试同时访问一个特定的操作方法时,我在Microsoft.EntityFrameworkCore得到了这个错误:
在前一个操作完成之前,在此上下文上开始了第二个操作。任何实例成员都不能保证是线程安全的
我使用 DI 和存储库进行网络Api。我定义了IUnitOfWork的范围,我定义了瞬态,但没有任何工作。
这是我的创业公司:
....
services.AddSingleton(provider => Configuration);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<IUnitOfWork, ApplicationDbContext>();
services.AddTransient<IRoleService, RoleService>();
services.AddTransient<ISecurityService, SecurityService>();
services.AddTransient<IDbInitializerService, DbInitializerService>();
services.AddTransient<ITokenStoreService, TokenStoreService>();
services.AddTransient<ITokenValidatorService, TokenValidatorService>();
services.AddTransient<ICookieValidatorService, CookieValidatorService>();
services.AddTransient<IRequestRepository, RequestRepository>();
services.AddDbContextPool<ApplicationDbContext>(options =>
{
options.UseSqlServer(
Configuration["ConnectionStrings:ApplicationDbContextConnection"].ToString(),
serverDbContextOptionsBuilder =>
{
var minutes = (int)TimeSpan.FromMinutes(3).TotalSeconds;
serverDbContextOptionsBuilder.CommandTimeout(minutes);
serverDbContextOptionsBuilder.EnableRetryOnFailure();
});
});
....
这是我的DbContext:
namespace Eela.Data
{
public class
ApplicationDbContextFactory : IDesignTimeDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContext CreateDbContext(string[] args)
{
var services = new ServiceCollection();
services.AddOptions();
services.AddScoped<IHostingEnvironment, CustomHostingEnvironment>();
services.AddSingleton<ILoggerFactory, LoggerFactory>();
var serviceProvider = services.BuildServiceProvider();
var loggerFactory = serviceProvider.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger<ConfigProvider>();
var hostingEnvironment = serviceProvider.GetRequiredService<IHostingEnvironment>();
Console.WriteLine($"Using `{hostingEnvironment.ContentRootPath}` as the ContentRootPath");
var configuration = new ConfigurationBuilder()
.SetBasePath(basePath: hostingEnvironment.ContentRootPath)
.AddJsonFile(path: "appsettings.json", reloadOnChange: true, optional: false)
.AddEncryptedProvider(hostingEnvironment: hostingEnvironment, logger: logger)
.AddJsonFile(path: $"appsettings.{hostingEnvironment.EnvironmentName}.json", optional: true)
.Build();
var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
var connectionString = configuration["ConnectionStrings:ApplicationDbContextConnection"];
var useInMemoryDatabase = configuration[key: "UseInMemoryDatabase"].Equals(value: "true",
comparisonType: StringComparison.OrdinalIgnoreCase);
if (useInMemoryDatabase)
builder.UseInMemoryDatabase("MyDatabase");
else
builder.UseSqlServer(connectionString);
builder.ConfigureWarnings(warnings => warnings.Log(CoreEventId.IncludeIgnoredWarning));
return new ApplicationDbContext(builder.Options);
}
}
public class ApplicationDbContext : DbContext, IUnitOfWork
{
public ApplicationDbContext(DbContextOptions options) : base(options)
{ }
protected override void OnModelCreating(ModelBuilder model)
{
base.OnModelCreating(model);
model.Entity<Person>().Property(p => p.PersonId).ValueGeneratedOnAdd();
model.Entity<Person>()
.HasDiscriminator<int>(name: "Type")
.HasValue<WorkerTaxi>(value: Convert.ToInt32(value: AccountType.TaxiWorker))
.HasValue<User>(value: Convert.ToInt32(value: AccountType.User))
.HasValue<Reseller>(value: Convert.ToInt32(value: AccountType.Reseller));
model.Entity<Log>().Property(p => p.Id).ValueGeneratedOnAdd();
model.Entity<Log>()
.HasDiscriminator<int>(name: "Type")
.HasValue<LogRequest>(value: Convert.ToInt32(value: LogLevel.Information))
.HasValue<LogError>(value: Convert.ToInt32(value: LogLevel.Error));
model.Entity<Request>().Property(p => p.RequestId).ValueGeneratedOnAdd();
model.Entity<Request>()
.HasDiscriminator<int>(name: "Type")
.HasValue<RequestTaxi>(value: Convert.ToInt32(value: RequestType.TaxiRequester));
model.Entity<ApplicationUsers>().Property(p => p.Id).ValueGeneratedOnAdd();
model.Entity<Role>().Property(p => p.RoleId).ValueGeneratedOnAdd();
model.Entity<Car>().Property(p => p.CarId).ValueGeneratedOnAdd();
model.Entity<Address>().Property(p => p.AddressId).ValueGeneratedOnAdd();
model.Entity<Organization>().Property(p => p.OrganizationId).ValueGeneratedOnAdd();
model.Entity<Credit>().Property(p => p.CreditId).ValueGeneratedOnAdd();
model.Entity<StablePrice>().Property(p => p.StablePriceId).ValueGeneratedOnAdd();
model.Entity<Package>().Property(p => p.PackageId).ValueGeneratedOnAdd();
model.Entity<Rating>().Property(p => p.RatingId).ValueGeneratedOnAdd();
model.Entity<City>().Property(p => p.CityId).ValueGeneratedOnAdd();
model.Entity<SpecialAddress>().Property(p => p.SpecialAddressId).ValueGeneratedOnAdd();
model.Entity<UserToken>().Property(p => p.Id).ValueGeneratedOnAdd();
model.Entity<PersonRequest>(entity =>
{
entity.HasKey(e => new {e.RequestId, e.PersonId})
.HasName(name: "PK_dbo.PersonRequest");
entity.HasIndex(e => e.RequestId)
.HasName(name: "IX_RequestId");
entity.HasIndex(e => e.PersonId)
.HasName(name: "IX_PersonId");
});
model.Entity<PackageReseller>(entity =>
{
entity.HasKey(e => new { e.PackageId, e.ResellerId })
.HasName(name: "PK_dbo.PackageReseller");
entity.HasIndex(e => e.PackageId)
.HasName(name: "IX_PackageId");
entity.HasIndex(e => e.ResellerId)
.HasName(name: "IX_ResellerId");
});
model.Entity<UserRole>(entity =>
{
entity.HasKey(e => new { e.ApplicationUserId, e.RoleId })
.HasName(name: "PK_dbo.UserRole");
entity.HasIndex(e => e.ApplicationUserId)
.HasName(name: "IX_ApplicationUserId");
entity.HasIndex(e => e.RoleId)
.HasName(name: "IX_RoleId");
});
}
public virtual DbSet<ApplicationUsers> ApplicationUsers { get; set; }
public virtual DbSet<Role> Role { get; set; }
public virtual DbSet<UserRole> UserRole { get; set; }
public virtual DbSet<UserToken> UserToken { get; set; }
public virtual DbSet<Address> Address { get; set; }
public virtual DbSet<Credit> Credit { get; set; }
public virtual DbSet<Organization> Organization { get; set; }
public virtual DbSet<City> City { get; set; }
public virtual DbSet<StablePrice> StablePrice { get; set; }
public virtual DbSet<PersonRequest> PersonRequest { get; set; }
public virtual DbSet<Discount> Discount { get; set; }
public virtual DbSet<Rating> Rating { get; set; }
public virtual DbSet<SpecialAddress> SpecialAddress { get; set; }
public void AddRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class
{
Set<TEntity>().AddRange(entities: entities);
}
public void RemoveRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class
{
Set<TEntity>().RemoveRange(entities: entities);
}
public void MarkAsChanged<TEntity>(TEntity entity) where TEntity : class
{
Entry(entity: entity).State = EntityState.Modified; // Or use ---> this.Update(entity);
}
public void ExecuteSqlCommand(string query)
{
Database.ExecuteSqlCommand(sql: query);
}
public void ExecuteSqlCommand(string query, params object[] parameters)
{
Database.ExecuteSqlCommand(sql: query, parameters: parameters);
}
public int SaveAllChanges()
{
return SaveChanges();
}
public Task<int> SaveAllChangesAsync()
{
return SaveChangesAsync();
}
}
}
这是我的工作单元:
namespace Eela.Data
{
public interface IUnitOfWork : IDisposable
{
DbSet<TEntity> Set<TEntity>() where TEntity : class;
void AddRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
void RemoveRange<TEntity>(IEnumerable<TEntity> entities) where TEntity : class;
EntityEntry<TEntity> Entry<TEntity>(TEntity entity) where TEntity : class;
void MarkAsChanged<TEntity>(TEntity entity) where TEntity : class;
void ExecuteSqlCommand(string query);
void ExecuteSqlCommand(string query, params object[] parameters);
int SaveAllChanges();
Task<int> SaveAllChangesAsync();
int SaveChanges(bool acceptAllChangesOnSuccess);
int SaveChanges();
Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = new CancellationToken());
Task<int> SaveChangesAsync(CancellationToken cancellationToken = new CancellationToken());
}
}
这是我的一个存储库:
public class RequestRepository : IRequestRepository
{
private readonly IMapper _mapper;
private readonly IUnitOfWork _unitOfWork;
private readonly DbSet<Request> _request;
private readonly DbSet<Person> _person;
private readonly DbSet<PersonRequest> _personRequest;
public RequestRepository(IMapper mapper, IUnitOfWork unitOfWork)
{
_mapper = mapper;
_unitOfWork = unitOfWork;
_request = _unitOfWork.Set<Request>();
_person = _unitOfWork.Set<Person>();
_personRequest = _unitOfWork.Set<PersonRequest>();
}
public async Task<DetailPageViewModel> GetRequestAsync(string requestId)
{
var request = await (from x in _request
where x.RequestId == Guid.Parse(requestId)
from y in x.PersonsRequests
where y.Person is User
select new DetailPageViewModel
{
RequestId = x.RequestId.ToString(),
CustomerName = y.Person.LastName,
SourceAddress = ((RequestTaxi) x).SourceAddress,
DestinationAddress = ((RequestTaxi) x).DestinationAddress,
DestinationLat = x.DestinationLat,
DestinationLon = x.DestinationLon,
EstimateDistance = ((RequestTaxi) x).Distance.ToString(CultureInfo.InvariantCulture),
EstimateDriverPrice = x.Price.ToString(),
EstimatePassengerPrice = x.PaymentType == PaymentType.Cash ? x.Price.ToString() : "0",
SourceLat = ((RequestTaxi) x).SourceLat,
SourceLon = ((RequestTaxi) x).SourceLon
}).FirstOrDefaultAsync();
return
_mapper.Map<DetailPageViewModel>(
source: request);
}
.....
最后,这是我的控制器之一:
public class DetailPageController:Controller
{
private readonly IPersonRequestRepository _personRequest;
private readonly IRequestRepository _request;
private readonly IApplicationUsersRepository _appUser;
private readonly IStablePriceRepository _stablePrice;
private readonly ILogRepository _log;
private readonly ICreditRepository _credit;
private readonly INotificationService _notification;
private readonly IPasswordGenerator _charecterGenerator;
public DetailPageController(IPersonRequestRepository personRequest,ICreditRepository credit,
ILogRepository log,IStablePriceRepository stablePrice,IApplicationUsersRepository appUser,
IRequestRepository request,INotificationService notification,IPasswordGenerator charecterGenerator)
{
_personRequest = personRequest;
_credit = credit;
_log = log;
_stablePrice = stablePrice;
_appUser = appUser;
_request = request;
_notification = notification;
_charecterGenerator = charecterGenerator;
}
[HttpPost]
[ActionName("GetRequest")]
public async Task<ActionResult> GetRequest([FromBody]string model)
{
var requestId = model;
return Json(data: await _request.GetRequestAsync(requestId));
}
RequestLoggingMiddleware.cs:
public class RequestLoggingMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<RequestLoggingMiddleware> _logger;
private readonly ILogRepository _logRepository;
private readonly IConfigurationRoot _configuration;
public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger,
ILogRepository logRepository,IConfigurationRoot configuration)
{
_next = next;
_logger = logger;
_logRepository = logRepository;
_configuration = configuration;
}
public async Task<OperationResult> Invoke(HttpContext context)
{
using (MemoryStream requestBodyStream = new MemoryStream())
{
using (MemoryStream responseBodyStream = new MemoryStream())
{
Stream originalRequestBody = context.Request.Body;
context.Request.EnableRewind();
Stream originalResponseBody = context.Response.Body;
OperationResult op= new OperationResult();
try
{
await context.Request.Body.CopyToAsync(requestBodyStream);
requestBodyStream.Seek(0, SeekOrigin.Begin);
string requestBodyText = new StreamReader(requestBodyStream).ReadToEnd();
requestBodyStream.Seek(0, SeekOrigin.Begin);
context.Request.Body = requestBodyStream;
string responseBody = "";
context.Response.Body = responseBodyStream;
Stopwatch watch = Stopwatch.StartNew();
await _next(context);
watch.Stop();
responseBodyStream.Seek(0, SeekOrigin.Begin);
responseBody = new StreamReader(responseBodyStream).ReadToEnd();
var log = new LogRequestViewModel
{
Host= context.Request.Host.Host,
Path= context.Request.Path,
QueryString= context.Request.QueryString.ToString(),
ClientIp= context.Connection.RemoteIpAddress.MapToIPv4(),
Date= DateTime.Now.ToString(CultureInfo.InvariantCulture),
Duration= watch.ElapsedMilliseconds,
Method= context.Request.Method,
RequestContentLength= context.Request.ContentLength,
RequestContentType= context.Request.ContentType,
Application= GetType().Namespace,
User= context.User.Claims
.FirstOrDefault(x => x.Type == _configuration["UserIdType"])?.Value,
Headers= string.Join(",", context.Request.Headers.Select(he => he.Key + ":[" + he.Value + "]").ToList()),
RequestBodyText= requestBodyText,
ResponseBodyText = responseBody
};
var result = await _logRepository.SaveRequestLogAsync(log);
if (!result.Success)
{
op.Success = false;
op.AddMessage("Couldn't add request log to database");
_logger.LogError(message: result.MessageList.FirstOrDefault());
var ex = new Exception(message: result.MessageList.FirstOrDefault());
await _logRepository.SaveErrorLogAsync(exception: ex);
}
responseBodyStream.Seek(0, SeekOrigin.Begin);
await responseBodyStream.CopyToAsync(originalResponseBody);
}
catch (Exception ex)
{
_logger.LogError(message: ex.Message);
await _logRepository.SaveErrorLogAsync(exception: ex);
byte[] data = System.Text.Encoding.UTF8.GetBytes("Unhandled Error occured, the error has been logged and the persons concerned are notified!! Please, try again in a while.");
originalResponseBody.Write(data, 0, data.Length);
op.Success = false;
op.AddMessage(ex.Message);
}
finally
{
context.Request.Body = originalRequestBody;
context.Response.Body = originalResponseBody;
}
const string logTemplate = @"
Client IP: {clientIP}
Request path: {requestPath}
Request content type: {requestContentType}
Request content length: {requestContentLength}
Start time: {startTime}
Duration: {duration}";
_logger.LogInformation(logTemplate,
context.Connection.RemoteIpAddress.ToString(),
context.Request.Path,
context.Request.ContentType,
context.Request.ContentLength,
DateTime.UtcNow,
Stopwatch.StartNew());
return op;
}
}
}
}
这是我的堆栈跟踪:
在微软。微软的EntityFrameworkCore . internal . concurrencydetector . entercriticalsection()。EntityFrameworkCore . change tracking . internal . state manager . d _ _ 61。MoveNext() -从引发异常的上一个位置开始的堆栈跟踪的结尾-在系统中。系统上的runtime . exception services . exceptiondispatchinfo . throw()。系统上的runtime . compiler services . taskawaiter . handlenonsuccessanddebuggernotification(Task Task)。Microsoft的runtime . compiler services . taskawaiter 1 . get result()。EntityFrameworkCore . change tracking . internal . state manager . d _ _ 59。MoveNext() -从引发异常的上一个位置开始的堆栈跟踪的结尾-在系统中。系统上的runtime . exception services . exceptiondispatchinfo . throw()。系统上的runtime . compiler services . taskawaiter . handlenonsuccessanddebuggernotification(Task Task)。Microsoft的runtime . compiler services . taskawaiter 1 . get result()。EntityFrameworkCore . db context . d _ _ 48。MoveNext() -从引发异常的上一个位置开始的堆栈跟踪的结尾-在系统中。系统上的runtime . exception services . exceptiondispatchinfo . throw()。系统上的runtime . compiler services . taskawaiter . handlenonsuccessanddebuggernotification(Task Task)。Eela上的runtime . compiler services . taskawaiter 1 . get result()。Service.LogRepository.d__7。D:\Eela\Eela中的MoveNext()。Service\LogRepository.cs:第41行-从抛出异常的前一个位置开始的堆栈跟踪的结尾-在系统中。系统上的runtime . exception services . exceptiondispatchinfo . throw()。系统上的runtime . compiler services . taskawaiter . handlenonsuccessanddebuggernotification(Task Task)。Eela上的runtime . compiler services . taskawaiter 1 . get result()。web . models . requestloggingmmiddleware . d _ _ 5。D:\Eela\Eela中的MoveNext()。web \ Models \ requestloggingmmiddleware . cs:第82行
更新:
我的创业公司有一个中间件.cs:
app.UseMiddleware<RequestLoggingMiddleware>();
当我对它进行注释时,我的代码可以毫无问题地工作。我包括RequestLoggingMiddleware。我的问题中的cs来源。
主要问题在哪里?
我的猜测是,中间件只实例化一次。因此,这意味着使用上下文的单个实例来执行对数据库的并发访问。
有两种解决方案。第一个是让context fabric在每次调用< code>Invoke方法时创建一个context实例。第二个是将日志记录存储在中间件的一个集合中。并在某种情况下(记录计数达到某个特定数目或超时达到零)将它们保存到数据库。
根据日志记录的数量,您可能会遇到性能问题。第二种方法需要实现对集合的正确并发访问。在某些情况下,您可能会丢失一些日志记录。
问题内容: 我知道这不是线程安全的,但是我不确定其确切含义。 在和都使用的情况下,以下哪种情况会引起问题并需要同步? 两个线程同时读取相同的索引 假设您不在乎获取旧元素还是新元素,则替换尝试同时访问的元素。 问题答案: 两个线程同时读取相同的索引 如果 列表是由分支and 的线程构造的,并且列表在线程被分支之前已完全构建并加载,则可以从公共线程读取多个线程。 这样做的原因是,使用线程和派生该线程的
问题内容: 我试图弄清楚如何将对象从表单发布到Web api服务。在我的控制器中,我定义了一个想要向其添加输入值的模型。 在我的输入字段中,我将它们绑定起来,例如: 在提交表单时,将这两个字段传递给我的服务并提交给我的WebApi 我已经通过两种方式尝试了此提交: 并且也如下,不声明参数 在webAPI中,我为帖子设置了一个方法 ReportLabel(dto)的定义如下: 我遇到的问题是,当我从
背景: 我在同一个解决方案中有一个Web API项目和一个类库项目,它们共享相同的模型类。两个项目共享同一个数据库,并且都使用DbContext来读/写数据。 Web API项目以典型的UnitOfWork模式设置,工作正常。 这个班级项目有点不同。我在构造函数中指定连接字符串,而不是在Web中指定。配置文件: 我使用WebAPI调用类库中定义的函数。当我试图使用类库查询数据库时,我得到一个错误。
问题内容: 我知道许多操作系统都在文件系统上执行某种锁定,以防止视图不一致。Java和/或Android是否可以保证文件访问的线程安全性?在我自己编写并发代码之前,我想尽可能多地了解这一点。 如果我错过了回答的类似问题,请随时关闭此线程。谢谢。 问题答案: Android建立在Linux之上,因此继承了Linux的文件系统语义。除非您明确锁定文件,否则多个应用程序和线程可以打开该文件以进行读/写访
问题内容: 在具有并发访问的程序中使用映射时,是否需要在函数中使用互斥体来 读取 值? 问题答案: 读者众多,没有作家可以: https://groups.google.com/d/msg/golang- nuts/HpLWnGTp-n8/hyUYmnWJqiQJ 一个作家,没有读者是可以的。(否则,地图不会太好。) 否则,如果至少有一个作家,而作家或读者至少还有一个,那么 所有 读者 和 作家都
我正试图从web API项目中使用Microsoft.Identity.web库对Microsoft Graph API SDK进行简单调用。 用户已经登录,正在从SPA调用受保护的控制器,一切都正常工作--但是现在,这些控件应该调用图形API,而我没有启动并运行它... 而且 MicrosoftIdentityWebChallengeUserException:IDW10502:由于对用户的质询