Generi c DBContext Injection с помощью Autofac - PullRequest
1 голос
/ 17 марта 2020

Я пытаюсь зарегистрировать и внедрить экземпляры DbContext в мои компоненты через Autofa c. Я знаю, что подход, который я использую в настоящее время, может быть улучшен, и я ищу идеи о том, как этого добиться. В данный момент я просто играю с идеей обобщенного c и пытаюсь заставить его работать, но это исключение. Возможно ли, что Autofa c создает несколько потоков для внедрения компонента?

System.Threading.Tasks.TaskCanceledException: A task was canceled.
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsync(Boolean errorsExpected, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, Boolean errorsExpected)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
   at UserService.Repositories.UserRepository.FindByIdAsync(String id) in /Users/ryanr/Documents/invoicer-backend-microservices/src/UserService/Repositories/UserRepository.cs:line 31
   at UserService.Queries.Handlers.GetUserByIDQueryHandler.Handle(GetUserByIDQuery query) in /Users/ryanr/Documents/invoicer-backend-microservices/src/UserService/Queries/Handlers/GetUserByIDQueryHandler.cs:line 19
   at UserService.Controllers.UsersController.GetUserById(GetUserByIDQuery query) in /Users/ryanr/Documents/invoicer-backend-microservices/src/UserService/Controllers/UsersController.cs:line 43
   at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
   at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

У меня есть библиотека классов, которая регистрирует типы Autofa c и определяет интерфейс DBContext:

    public interface IDbContext<T> where T: class
    {
        DbSet<T> DataSet { get; set; }
    }

Модуль Autofa c для регистрации репозиториев и внедрения DbContext

    public class RepositoryModule : Autofac.Module
    {
        public Assembly ExecutingAssembly { get; set; }
        public string ConnectionString { get; set; }

        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterAssemblyTypes(ExecutingAssembly)
            .Where(t => t.Name.EndsWith("Repository"))
            .AsImplementedInterfaces();

            builder.RegisterAssemblyTypes(ExecutingAssembly)
                .Where(t => t.IsClosedTypeOf(typeof(IDbContext<>)))
                .AsSelf()
                .InstancePerLifetimeScope();

        }
    }

Затем он разрешается и внедряется в мой UserService (ASP. Net):

public class UserRepository : IUserRepository
    {
        private readonly UserDBContext _dbContext;
        public UserRepository(UserDBContext dbContext)
        {
            _dbContext = dbContext;
        }


        public async Task<User> FindByIdAsync(string id)
        {
            return await _dbContext.DataSet.FirstOrDefaultAsync(user => user.Id == id);

        }
}

Класс DbContext

public class UserDBContext : DbContext, IDbContext<User>
    {
        public DbSet<User> DataSet { get; set; }

        public UserDBContext()
        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer("server=localhost,1434;user id=sa;password=password;database=UserManagement;");
        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            builder.Entity<User>().HasKey(m => m.Id);
            builder.Entity<User>().ToTable("User");
            base.OnModelCreating(builder);
        }
   }

Затем хранилище внедряется в my в мой QueryHandler, и именно здесь используется DBContext:

public class GetUserByIDQueryHandler : IQueryHandler<GetUserByIDQuery, User>
    {
        private IUserRepository _repository;
        public GetUserByIDQueryHandler(IUserRepository repository)
        {
            _repository = repository;
        }

        public async Task<User> Handle(GetUserByIDQuery query)
        {
            return await _repository.FindByIdAsync(query.Id);
        }
    }

Где QueryHandlers разрешаются следующим образом:

var handlers = scope.Resolve<IEnumerable<IQueryHandler<TRequest, TResponse>>>().ToList();

РЕДАКТИРОВАТЬ: У меня есть основания полагать, что это проблема внедрения зависимостей / Autofa c, потому что этот тривиальный тест закончил работать:

// GET api/users/5
        [HttpGet("{Id}", Name = "GetUserById")]
        public async Task<IActionResult> GetUserById([FromBody]GetUserByIDQuery query)
        {
            //var users = await _queryBus.Query<GetUserByIDQuery, User>(query);
            //string id = new Guid().ToString();
            //var users = await _dbContext.DataSet.FirstOrDefaultAsync(x => x.Id == id);
            using(var dbContext = new UserDBContext())
            {
                return Ok(await dbContext.DataSet.ToListAsync());
            }
        }

Любая помощь будет оценена! Спасибо:)

Ответы [ 2 ]

2 голосов
/ 17 марта 2020

Я не думаю, что это имеет какое-либо отношение к внедрению зависимости или автофоре c. Посмотрите на трассировку стека - в верхней части трассы написано:

в Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenDbConnectionAsyn c (логические ошибки ожидаются, CancellationToken cancellationToken)

Это похоже на проблему с подключением к базе данных. Проверьте строку подключения и проведите быстрый тест, чтобы убедиться, что вы можете подключиться к базе данных без лишних сложностей, связанных с autofa c или обработчиками запросов.

0 голосов
/ 18 марта 2020

Я решил это.

QueryHandler пытался разрешить асинхронную c функцию синхронно, и это вызывало проблемы.

Например:

var handlers = scope.Resolve<IEnumerable<IQueryHandler<TRequest, TResponse>>>().ToList();
return await handlers[0].Handle(query);
...