C# 如何处理ASP.NETCore中在相同上下文范围内运行的静态类?
在下面的示例中,我有一个控制器,该控制器生成一个文件并加密一些敏感信息,例如SSN。我在静态类中有我的函数,允许我从项目中的任何地方调用它们。这两个类都在同一个上下文中运行,并且运行SP。我认为问题就在这里 startup.csC# 如何处理ASP.NETCore中在相同上下文范围内运行的静态类?,c#,sql-server,entity-framework,stored-procedures,asp.net-core,C#,Sql Server,Entity Framework,Stored Procedures,Asp.net Core,在下面的示例中,我有一个控制器,该控制器生成一个文件并加密一些敏感信息,例如SSN。我在静态类中有我的函数,允许我从项目中的任何地方调用它们。这两个类都在同一个上下文中运行,并且运行SP。我认为问题就在这里 startup.cs public void ConfigureServices(IServiceCollection services) { services.Configure<MvcOptions>(optio
public void ConfigureServices(IServiceCollection services)
{
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new RequireHttpsAttribute());
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("ARTNetCore")));
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
services.Configure<SMSoptions>(Configuration);
services.AddMvc();
// Configure Identity
services.Configure<IdentityOptions>(options =>
{
// Password settings
options.Password.RequireDigit = true;
options.Password.RequiredLength = 8;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = true;
options.Password.RequireLowercase = false;
// Lockout settings
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
options.Lockout.MaxFailedAccessAttempts = 10;
options.Lockout.AllowedForNewUsers = true;
services.AddCookieAuthentication(o =>
{
o.LoginPath = "/Account/LogIn";
o.LogoutPath = "/Account/LogOut";
});
// User settings
options.User.RequireUniqueEmail = true;
});
services.Configure<AuthMessageSenderOptions>(Configuration);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var options = new RewriteOptions()
.AddRedirectToHttps();
app.UseRewriter(options);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
//Comment when migrating or demigrating
//SeedData.Initialize(app.ApplicationServices);
}
控制器是
private readonly ApplicationDbContext _context;
public PatRegController(ApplicationDbContext context)
{
_context = context;
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("FName,MName,LName,Dob,GenrId,StasId,NatyId,MarsId,CouyId,StaeId,CityId,OccnId,Email,SNN,PassNo,MobNo,LLine,MAdds,StrtNo,SDirn,AptNo,Locy,ALevl,PCode,Couy,ProeId")] PatReg patReg)
{
if (ModelState.IsValid)
{
patReg.FileId = DbSerializerHandler.SerializeFileId(_context);
patReg.SNN = DbEncryptionHandler.DynamicEncrypt(patReg.SNN, _context);
_context.Add(patReg);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(patReg);
}
加密静态类是
public static class DbEncryptionHandler
{
public static string DynamicEncrypt(string clearText, ApplicationDbContext _context)
{
try
{
if (!string.IsNullOrWhiteSpace(clearText))
{
List<EncKeys> Keys = new List<EncKeys>();
Keys = _context.EncKeys.FromSql("EncKeysSP").ToList();
string EncryptionKey = Keys[0].DynamicKey;
byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
using (Aes encryptor = Aes.Create())
{
Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
encryptor.Key = pdb.GetBytes(32);
encryptor.IV = pdb.GetBytes(16);
using (MemoryStream ms = new MemoryStream())
{
using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
{
cs.Write(clearBytes, 0, clearBytes.Length);
cs.Close();
}
clearText = Convert.ToBase64String(ms.ToArray());
}
}
}
else
{
clearText = null;
}
}
catch (Exception ex)
{
throw;
}
return clearText;
}
}
并且序列化器静态类是
public static class DbSerializerHandler
{
public static Int64 SerializeFileId(ApplicationDbContext _context)
{
List<FileIdSeq> NewFileSeq = new List<FileIdSeq>();
NewFileSeq = _context.FileIdSeq.FromSql("FileIdSeqSP").ToList();
var FileID = NewFileSeq[0].LastSequence;
return FileID;
}
}
当我试图保存我的数据时,我得到了这个错误
处理请求时发生未处理的异常
SqlException:不允许新建事务,因为存在其他事务
会话中运行的线程。
System.Data.SqlClient.SqlConnection.OnErrorSqlException异常,
bool断开连接,操作wrapCloseInAction
此控制器行上的错误返回wait_context.SaveChangesAsync
我做错了什么
更新
我选中了,一次只能运行其中一个函数,但不能同时运行这两个函数。DbEncryptionHandler和DbSerializerHandler类不需要依赖于ApplicationDbContext,只需要依赖于它们需要的数据
public static class DbEncryptionHandler
{
public static string DynamicEncrypt(string clearText, IEnumerable<EncKeys> keys)
{
...
}
}
public static class DbSerializerHandler
{
public static Int64 SerializeFileId(IEnumerable<FileIdSeq> seq)
{
...
}
}
在控制器中,您可以在使用静态类之前从上下文中获取数据
public async Task<IActionResult> Create(PatReg patReg)
{
if (ModelState.IsValid)
{
var seq = await _context.FileIdSeq.FromSql("FileIdSeqSP").ToListAsync();
var keys = await _context.EncKeys.FromSql("EncKeysSP").ToListAsync();
patReg.FileId = DbSerializerHandler.SerializeFileId(seq);
patReg.SNN = DbEncryptionHandler.DynamicEncrypt(patReg.SNN, keys);
_context.Add(patReg);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(patReg);
}
在代码的何处返回错误?@reds,wait_context.SaveChangesAsync@ScottChamberlain,它是一个私有只读,,,私有只读应用程序上下文;,我编辑了这个问题您的代码看起来是正确的,我没有主意也许您有一个中间件,它在一个单独的线程中使用上下文,而不是结束它的事务?。您可以删除针对我的旧注释,我删除了我的注释。您应该向DbEncryptionHandler类提供所需的密钥数据,而不是将DbContext传递给DbEncryptionHandler类。您的加密方法依赖于DbContext没有任何意义。就像charm一样工作,我是否使用return seq.Firstc=>c.SequenceDate正确选择了它=null.LastSequence;虽然这解决了问题,但我想知道是否有人能真正弄清楚为什么会发生这种情况。从理论上讲,代码应该有效。这里出了点问题,我担心这是EF Core的问题。在这种情况下,我们可能应该报告这个问题@Ahmad Abu Maizar,你使用的是什么版本的EFCARE?EF CORE2,VS 2017预览最新更新,你会考虑投票会得到更多的关注。我相信最初的问题是由在静态方法中对数据库进行非异步调用引起的,因为这些静态方法是不可等待的。我的回答迫使所有数据库调用返回控制器,在那里可以等待它们。我本可以建议让静态方法返回任务,这样它们就可以等待了,但我觉得对DbContext的依赖不是必需的,而且是一个糟糕的设计,这很明显,在调用SaveChangesAsync时会导致问题。@Brad.ToList调用是一个同步调用,不是吗?这意味着理论上你不需要等待任何事情,也不需要返回任务。这就是我认为问题所在的地方——calls.ToList应该是同步的,它会使线程旋转,并且不会正确终止线程,因此会出现异常。