【问题标题】:Asp.net core rc1, dbcontext connection is closed in IStringLocalizer GetString methodAsp.net core rc1,dbcontext连接在IStringLocalizer GetString方法中关闭
【发布时间】:2016-07-17 05:47:27
【问题描述】:

Asp.net core rc1, dbcontext 连接在 IStringLocalizer GetString 方法中关闭。仅在 VS2015 处于调试模式时发生,并且仅在启动时发生一次。

我正在使用 Autofac DI,但同样的问题(没有 autofac)使用内置 DI。

当我在调试模式下运行应用程序并且仅在启动时,会产生以下错误。当我刷新浏览器时一切正常,没有错误。如果我在没有调试的情况下运行应用程序,没有错误,一切运行正常。

调试威胁和 DI 有什么问题吗?有什么想法吗?

浏览器出错:

处理请求时数据库操作失败。 InvalidOperationException:ExecuteReader 需要打开和 可用的连接。连接的当前状态为关闭。

输出窗口:

Microsoft.Data.Entity.Storage.Internal.RelationalCommandBuilderFactory: Information: Executed DbCommand (55ms) [Parameters=[@___cultureName_0='?', @__name_1='?'], CommandType='Text', CommandTimeout='30']
SELECT TOP(1) [l].[CultureId], [l].[Name], [l].[Value]
FROM [UIResources] AS [l]
WHERE ([l].[CultureId] = @___cultureName_0) AND ([l].[Name] = @__name_1)
Microsoft.Data.Entity.Query.Internal.QueryCompiler: Error: An exception occurred in the database while iterating the results of a query.
System.NullReferenceException: Not Specified object reference to an instance object.
   σε System.Data.SqlClient.SqlConnection.TryOpenInner(TaskCompletionSource`1 retry)
   σε System.Data.SqlClient.SqlConnection.TryOpen(TaskCompletionSource`1 retry)
   σε System.Data.SqlClient.SqlConnection.Open()
   σε Microsoft.Data.Entity.Storage.RelationalConnection.Open()
   σε Microsoft.Data.Entity.Query.Internal.QueryingEnumerable.Enumerator.MoveNext()
   σε System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   σε System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   σε lambda_method(Closure , QueryContext )
   σε Microsoft.Data.Entity.Query.Internal.QueryCompiler.<>c__DisplayClass18_1`1.<CompileQuery>b__1(QueryContext qc)
Microsoft.Data.Entity.Query.Internal.QueryCompiler: Error: An exception occurred in the database while iterating the results of a query.
System.InvalidOperationException: ExecuteReader requires an open and available Connection. The connection's current state is closed.
   at System.Data.SqlClient.SqlCommand.ValidateCommand(String method, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method)
   at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.<>c__DisplayClass17_0.<ExecuteReader>b__0(DbCommand cmd, IRelationalConnection con)
   at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.Execute[T](IRelationalConnection connection, Func`3 action, String executeMethod, Boolean openConnection, Boolean closeConnection)
   at Microsoft.Data.Entity.Storage.Internal.RelationalCommand.ExecuteReader(IRelationalConnection connection, Boolean manageConnection)
   at Microsoft.Data.Entity.Query.Internal.QueryingEnumerable.Enumerator.MoveNext()
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable`1 source)
   at lambda_method(Closure , QueryContext )
   at Microsoft.Data.Entity.Query.Internal.QueryCompiler.<>c__DisplayClass18_1`1.<CompileQuery>b__1(QueryContext qc)
Exception thrown: 'System.NullReferenceException' in EntityFramework.Core.dll
Exception thrown: 'System.InvalidOperationException' in EntityFramework.Core.dll

这是我的创业公司:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

    services.AddIdentity<ApplicationUser, ApplicationRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc().AddViewLocalization();
    services.AddMvc().AddDataAnnotationsLocalization();
    services.AddLocalization();

    // Create the Autofac container builder.
    var builder = new ContainerBuilder();

    // Populate the services from the collection.
    // This have to come First.
    builder.Populate(services);

    // Register dependencies.
    builder.RegisterType<AuthMessageSender>().As<IEmailSender>().InstancePerLifetimeScope();
    builder.RegisterType<AuthMessageSender>().As<ISmsSender>().InstancePerLifetimeScope();
    builder.RegisterType<DataInitializer>().As<IDataInitializer>().InstancePerLifetimeScope();
    builder.RegisterType<CultureHelper>().As<ICultureHelper>().InstancePerLifetimeScope();
    builder.RegisterType<RouteRequestCultureProvider>().InstancePerLifetimeScope();
    builder.RegisterType<CultureActionFilter>().InstancePerLifetimeScope();
    builder.RegisterType<DbStringLocalizerFactory>().As<IStringLocalizerFactory>().InstancePerLifetimeScope();
    // DbStringLocalizer registers with InstancePerDependency, 
    // because localization requires a new instance of IStringLocalizer created in the IStringLocalizerFactory.
    builder.RegisterType<DbStringLocalizer>().As<IStringLocalizer>().InstancePerDependency();

    // Build the container.
    var container = builder.Build();

    // Return the IServiceProvider resolved from the container.
    return container.Resolve<IServiceProvider>();
}

这是本地化实现:

public class DbStringLocalizerFactory : IStringLocalizerFactory
{
    private IServiceProvider _serviceProvider;

    public DbStringLocalizerFactory(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IStringLocalizer Create(Type resourceSource)
    {
        return _serviceProvider.GetService<IStringLocalizer>();
    }

    public IStringLocalizer Create(string baseName, string location)
    {
        return _serviceProvider.GetService<IStringLocalizer>();
    }
}
public class DbStringLocalizer : IStringLocalizer
{
    private ApplicationDbContext _db;
    private string _cultureName;

    public DbStringLocalizer(ApplicationDbContext db)
        : this(db, CultureInfo.CurrentCulture)
    {
    }

    public DbStringLocalizer(ApplicationDbContext db, CultureInfo cultureInfo)
    {
        _db = db;
        _cultureName = cultureInfo.Name;
    }

    public LocalizedString this[string name]
    {
        get
        {
            var value = GetString(name);
            return new LocalizedString(name, value ?? name, resourceNotFound: value == null);
        }
    }

    public LocalizedString this[string name, params object[] arguments]
    {
        get
        {
            var format = GetString(name);
            var value = string.Format(format ?? name, arguments);
            return new LocalizedString(name, value, resourceNotFound: format == null);
        }
    }

    private string GetString(string name)
    {
        //try
        //{
        var query = _db.UIResources.Where(l => l.CultureId == _cultureName);
        var value = query.FirstOrDefault(l => l.Name == name);
        return value?.Value;
        //}
        //catch
        //{
        //    return null;
        //}
    }


    public IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures)
    {
        return _db.UIResources.Where(l => l.CultureId == _cultureName)
            .Select(l => new LocalizedString(l.Name, l.Value, true));
    }

    public IStringLocalizer WithCulture(CultureInfo culture)
    {
        return new DbStringLocalizer(_db, culture);
    }
}

【问题讨论】:

  • 为什么IDataInitializer 被实例化为作用域(我希望它是瞬态的,因为它只被调用一次)。您还可以发布您对IDataInitializer 的实现吗?我怀疑你在IDataInitializer 实现中注入了你的作用域上下文,然后释放它(即调用using(...)context.Dispose()),这样作用域实例在你的请求中被释放并且不可用(它使用与作用域相同的实例)
  • 那个或你的DbStringLocalizer 正在处理/关闭范围内的实例。但是因为它只发生在调试中
  • 你的第一个嫌疑人,解决了我的问题。我制作了“IDataInitializer”瞬态“InstancePerDependency”,一切都像魅力一样!非常感谢
  • 我已将评论发布为未来阅读的答案,因此您可以将其标记为已解决,因此问题不会再出现在 StackOverflow 的未回答部分中

标签: entity-framework localization asp.net-core asp.net-core-mvc


【解决方案1】:

IDataInitializer 注册为范围内的服务

builder.RegisterType<DataInitializer>().As<IDataInitializer>().InstancePerLifetimeScope();

看起来很奇怪,因为预计数据初始化程序只被调用一次,当应用程序启动以确保创建数据库并填充运行应用程序所需的数据或更新之后。

我怀疑您在 DataInitializer 类中的某个位置处理了作用域数据库上下文,因此它在您的请求期间变得不可用,因为您的 IoC 容器在请求期间将始终返回相同的实例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-03
    • 1970-01-01
    相关资源
    最近更新 更多