Я использую проект ASP.NET Core 2.1 Web API, разработанный с архитектурой доменного управления.
У меня есть два контекста БД, AppDbContext
используется Asp.net Identity (для пользователя и ролиуправление, как используется UserManager), и Sprint1DbContext
используется для транзакций других таблиц.
В файле startup.cs я использовал:
string constring = Configuration.GetValue<string>("DBConnectionString");
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(constring));
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddDbContext<Sprint1DbContext>
(options => options
.UseLazyLoadingProxies()
.UseSqlServer(constring
// , sqlServerOptions => sqlServerOptions.CommandTimeout(120) this is not worked
)
//_dbContext is Sprint1DbContext
// _appDbContext is AppDbContext
Я использовал следующие строки в своем классе CustomActionFilterAttribute
:
public override void OnActionExecuting(ActionExecutingContext context)
{
_dbContext.Database.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception == null)
{
_dbContext.Database.CommitTransaction();
}
else
{
_dbContext.Database.RollbackTransaction();
}
}
В классе обслуживания я использую следующий бизнес-код:
// Some code
// creating Bill of the customer
await billToDataRepository.Add(billTo);
// some code
// creating new customer’s data AspNetUser, Role, and it Account record
ApplicationUser user = new ApplicationUser
{
Name = model.FName + " " + model.LName,
UserName = model.Email,
Email = model.Email,
PhoneNumber=model.PrimaryPhone,
};
// creating AspNetuser
IdentityResult result = await userManager.CreateAsync(user, Constants.PasswordDefault);
// some code for assigning the role to a user
var account = new Account
{
Id = Guid.NewGuid(),
FName = model.FName,
LName = model.LName,
AccountType = EnumAccountType.Customer,
AspNetUserId = user.Id,
};
await accountDataRepository.Add(account);
// other application business logic
Вышеуказанный метод Add определен в DataRepository
классе:
public class DataRepository<TEntity> : IDataRepository<TEntity>
where TEntity : DomainEntity
{
public async Task<TEntity> Add(TEntity entity)
{
if (entity == null)
throw new ArgumentException("entity is null");
return await Task.Run(() =>
{
try
{
Context.Set<TEntity>().Add(entity);
Context.SaveChanges();
}
catch (Exception e)
{
throw;
}
return entity;
});
}
}
Если в бизнес-логике другого приложения возникнет какое-либо исключение, мне придется все откатить.Поскольку я использовал только _dbContext.Database.RollbackTransaction()
, он откатывает только те записи, которые созданы _dbContext
.Это не возвращает ApplicationUser
и Role
вещи, созданные _appDbContext
(userManager
и RoleManager
).Итак, снова я обновил свой CustomActionFilterAttribute
класс.
public override void OnActionExecuting(ActionExecutingContext context)
{
_dbContext.Database.BeginTransaction();
_appdbContext.Database.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception == null)
{
_dbContext.Database.CommitTransaction();
_appdbContext.Database.CommitTransaction();
}
else
{
_dbContext.Database.RollbackTransaction();
_appdbContext.Database.RollbackTransaction();
}
}
После записи BeginTransaction
для _appdbContext
, когда я выполняю тот же код класса обслуживания, я получаю ошибку тайм-аута наследующий код:
await accountDataRepository.Add(account);
Этот метод Add
вызывает метод Add
класса DataRepository
означает, что исключение происходит в следующей строке, вызываемой методом accountDataRepository.Add
:
Context.Set<TEntity>().Add(entity);
Context.SaveChanges();
"errorDetail":"Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.\r\nThe statement has been terminated. ---> System.ComponentModel.Win32Exception: The wait operation timed out\r\n
Хотя функция RollbackTransaction
в обоих контекстах (_dbContext
& _appdbContext
) работает нормально и данные возвращаются, но я недалее.
Итак, подведем итог:
Задача 1
Если я использую
_dbContext.Database.BeginTransaction();
_dbContext.Database.CommitTransaction();
_dbContext.Database.RollbackTransaction();
await billToDataRepository.Add(billTo); //record created and rollback
// unable to rollback
IdentityResult result = await userManager.CreateAsync(user, Constants.PasswordDefault); //record created and but not rollback
await accountDataRepository.Add(account); //record created and rollback
Задача 2
В порядкеЧтобы решить проблему 1, я использовал:
_dbContext.Database.BeginTransaction();
_appdbContext.Database.BeginTransaction();
_dbContext.Database.CommitTransaction();
_appdbContext.Database.CommitTransaction();
_dbContext.Database.RollbackTransaction();
_appdbContext.Database.RollbackTransaction();
await billToDataRepository.Add(billTo);//record created and rollback
IdentityResult result = await userManager.CreateAsync(user, Constants.PasswordDefault); //record created and rollback
await accountDataRepository.Add(account);
//Which calling
Context.Set<TEntity>().Add(entity);
Context.SaveChanges();
//Unable to create record, Time out exception occur.
Как я могу это исправить?