gpt4 book ai didi

c# - 在 DI 环境中使用时出现奇怪且难以调试的错误

转载 作者:太空宇宙 更新时间:2023-11-03 12:18:04 31 4
gpt4 key购买 nike

我目前在使用 Autofac 的 IOC 设置中使用 EF6。在我的服务中,我像这样注入(inject)我的 DbContext:

    private readonly CommerceContext _dbContext;

public UserTokenService(CommerceContext dbContext)
{
_dbContext = dbContext;
}

当我更新 token 时,随机出现几个不同的 SQL 错误。

我的 API Controller :

private readonly IUserTokenService _tokenService;

public UsersApiController(IUserTokenService tokenService)
{
this._tokenService = tokenService;
}

[RequireHttps]
[System.Web.Http.HttpGet]
[System.Web.Http.Route("api/users/validatetoken")]
public IHttpActionResult ValidateToken(Guid tokenId)
{
var falseObj = new
{
IsValid = false,
Email = string.Empty
};

var token = _tokenService.Get(tokenId);
if (token == null) return Ok(falseObj);
if (token.IsExpired) return Ok(falseObj);

var user = _userService.Find(token.UserId);
if (user == null) return Ok(falseObj);

_tokenService.Update(token);
}

我的 TokenService 获取方法:

    public UserToken Get(Guid token)
{
return _dbContext.UserTokens.FirstOrDefault(x => x.Token == token);
}

我的 TokenService 更新方法:

    public void Update(UserToken token)
{
token.ExpiresAt = DateTime.UtcNow.AddHours(1);
_dbContext.SaveChanges();
}

_dbContext 包含我所有不同的 DbSet,并且是这样注册的:

  var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterModule(new AutofacWebTypesModule());

builder.RegisterAssemblyTypes(typeof(CommerceContext).Assembly)
.Where(t => t.Name.EndsWith("Context"))
.InstancePerRequest();

builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(t => t.Name.EndsWith("Service"))
.AsImplementedInterfaces()
.InstancePerRequest();

var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);

对该方法的每次调用都是来自不同域的 Web API。我几乎被困住了。我自己没有遇到过这个错误,但我可以在我的服务器日志中看到它。我能想到的唯一可能性是一次打开的连接太多,这真的很糟糕,因为该站点目前没有很多用户。我是否应该以不同的方式注册我的 DbContext,拥有多个,或者完全不同的东西。

不同的错误:

System.Web.HttpUnhandledException (0x80004005): The underlying provider failed on Open. ---> System.Data.Entity.Core.EntityException: The underlying provider failed on Open. ---> System.InvalidOperationException: The connection was not closed. The connection's current state is connecting.
at System.Data.ProviderBase.DbConnectionClosedConnecting.TryOpenConnection(DbConnection outerConnection, DbConnectionFactory connectionFactory, TaskCompletionSource`1 retry, DbConnectionOptions userOptions)
at System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
at System.Data.SqlClient.SqlConnection.Open()
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext](TTarget target, Action`2 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.Open(DbConnection connection, DbInterceptionContext interceptionContext)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.<>c__DisplayClass1.<Execute>b__0()
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
--- End of inner exception stack trace ---
at System.Data.Entity.Core.EntityClient.EntityConnection.Open()
at System.Data.Entity.Core.Objects.ObjectContext.EnsureConnection(Boolean shouldMonitorTransactions)
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at #.UserTokenService.Update(UserToken token) in E:\TeamCity\buildAgent\work\38cf8b2b27f5e099\src\#\UserTokenService.cs:line 79

System.Web.HttpUnhandledException (0x80004005): An error occurred while starting a transaction on the provider connection. See the inner exception for details. ---> System.Data.Entity.Core.EntityException: An error occurred while starting a transaction on the provider connection. See the inner exception for details. ---> System.InvalidOperationException: SqlConnection does not support parallel transactions.
at System.Data.SqlClient.SqlInternalConnection.BeginSqlTransaction(IsolationLevel iso, String transactionName, Boolean shouldReconnect)
at System.Data.SqlClient.SqlConnection.BeginTransaction(IsolationLevel iso, String transactionName)
at System.Data.SqlClient.SqlConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Entity.Infrastructure.Interception.InternalDispatcher`1.Dispatch[TTarget,TInterceptionContext,TResult](TTarget target, Func`3 operation, TInterceptionContext interceptionContext, Action`3 executing, Action`3 executed)
at System.Data.Entity.Infrastructure.Interception.DbConnectionDispatcher.BeginTransaction(DbConnection connection, BeginTransactionInterceptionContext interceptionContext)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
--- End of inner exception stack trace ---
at System.Data.Entity.Core.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.Entity.Core.EntityClient.EntityConnection.BeginTransaction()
at System.Data.Entity.Core.Objects.ObjectContext.ExecuteInTransaction[T](Func`1 func, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction, Boolean releaseConnectionOnSuccess)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesToStore(SaveOptions options, IDbExecutionStrategy executionStrategy, Boolean startLocalTransaction)
at System.Data.Entity.SqlServer.DefaultSqlExecutionStrategy.Execute[TResult](Func`1 operation)
at System.Data.Entity.Core.Objects.ObjectContext.SaveChangesInternal(SaveOptions options, Boolean executeInExistingTransaction)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at #.UserTokenService.Update(UserToken token) in E:\TeamCity\buildAgent\work\38cf8b2b27f5e099\src\#\UserTokenService.cs:line 79

最佳答案

我发现我的问题是由我为验证身份验证 token 而创建的 WebApi ActionFilter 属性引起的。

在此属性 OnActionExecuting 中,我将我的 UserTokenService 存储在一个私有(private)变量中,从 DependencyResolver 获取服务。

事实证明这是一个非常糟糕的解决方案,因为正在缓存 WebApi ActionFilter 属性,所以基本上我的服务被使用该属性的每个 api 请求共享。

解决方案是像这样在 OnActionExecuting() 中使用 HttpRequestMessage 提供的范围:

    var scope = actionContext.Request.GetDependencyScope();
var tokenService = scope.GetService(typeof(IUserTokenService)) as IUserTokenService;

更好的解决方案是使用此处描述的 ActionFilterAttribute 的 AutoFacs 实现:

http://autofaccn.readthedocs.io/en/latest/integration/webapi.html#provide-filters-via-dependency-injection

这让 Controller 有机会注入(inject)您的 ActionFilter。但就我而言,从范围请求服务是更好的选择。

关于c# - 在 DI 环境中使用时出现奇怪且难以调试的错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48868081/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com