InvalidOperationException:尝试激活 'UnitOfWork' 时无法解析类型 'DataAccessContext' 的服务

InvalidOperationException: Unable to resolve service for type 'DataAccessContext' while attempting to activate 'UnitOfWork'

我收到以下错误。我正在使用 .Net Core 网络 API.

An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve service for type 'CustomerManager.Db.DataAccessContext' while attempting to activate 'CustomerManager.Repository.UnitOfWork'. Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteFactory.CreateArgumentCallSites(Type serviceType, Type implementationType, CallSiteChain callSiteChain, ParameterInfo[] parameters, bool throwIfCallSiteNotFound)

Api控制器

 [Route("api/[controller]")]
        [ApiController]
        public class CustomerController : ControllerBase
        {
            private ICustomersManager _customersManager = null;
            public CustomerController(ICustomersManager customersManager)
            {
                _customersManager = customersManager;
            }
            [HttpGet]
            public async Task<IActionResult> Get()
            {
                var customers = await _customersManager.GetAll();
                return Ok(customers);
            }
        }

客户模型

public class Customers
    {
        public Customers()
        {
            Customers customer = this;
            customer.CustomerBankDetails = new List<CustomerBankDetail>();
            customer.CustomerContactDetails = new List<CustomerContactDetail>();
            customer.CustomerFamilyDetails = new List<CustomerFamilyDetail>();
            customer.CustomerPhotos = new List<CustomerPhoto>();
        }

        public int Id { get; set; }
        public string CustomerNo { get; set; }
        public string CustomerName { get; set; }
        public string Gender { get; set; }
        public DateTime? CustomerEntryDate { get; set; }
        public DateTime? DateOfBirth { get; set; }
        public string Nationality { get; set; }
        public bool? IsApproved { get; set; }
        public bool IsActive { get; set; }
        public bool? IsDeleted { get; set; }
        public byte? SortedBy { get; set; }
        public string Remarks { get; set; }
        public virtual IEnumerable<CustomerBankDetail> CustomerBankDetails { get; set; }
        public virtual IEnumerable<CustomerContactDetail> CustomerContactDetails { get; set; }
        public virtual IEnumerable<CustomerFamilyDetail> CustomerFamilyDetails { get; set; }
        public virtual IEnumerable<CustomerPhoto> CustomerPhotos { get; set; }
    }

客户业务层代码

public interface ICustomersManager
    {
        Task<List<Customers>> GetAll();
    }

BLL 实现

public class CustomersManager : ICustomersManager
    {
        private IUnitOfWork _unitOfWork = null;
        public CustomersManager(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }
        public async Task<List<Customers>> GetAll()
        {
            return await _unitOfWork.CustomerRepository.GetAllAsync();
        }
    }

工作单元接口

public interface IUnitOfWork : IDisposable
    {
        ICustomerRepository CustomerRepository { get; }
    }

工作单元实现

public class UnitOfWork : IUnitOfWork
    {
        #region properties

        private readonly DataAccessContext _context;
        private ICustomerRepository _customerRepository;

        public UnitOfWork(DataAccessContext context)
        {
            _context = context;
        }

        #endregion
        public ICustomerRepository CustomerRepository =>
            _customerRepository ?? (_customerRepository = new CustomerRepository(_context));

        public void Dispose()
        {
            _customerRepository = null;
        }
    }

客户存储库界面

public interface ICustomerRepository : IRepository<Customers>
    {

    }

客户存储库实施

public class CustomerRepository : BaseRepository, ICustomerRepository
    {
        public CustomerRepository(DataAccessContext objDataAccessContext) : base(objDataAccessContext)
        {
        }
        
        public Task<List<Customers>> GetAllAsync()
        {
            return Task.Run(() =>
            {
                var objCustomerList = new List<Customers>();
                ObjDbCommand.Parameters.Clear();
                ObjDbCommand.AddInParameter("@Id", null);
                try
                {
                    ObjDbDataReader = ObjDataAccessContext.ExecuteReader(ObjDbCommand, "dbo.prGetAllCustomers", CommandType.StoredProcedure);
                    if (ObjDbDataReader.HasRows)
                        while (ObjDbDataReader.Read())
                        {
                            var objCustomer = new Customers();
                            BuildModel(ObjDbDataReader, objCustomer);
                            objCustomerList.Add(objCustomer);
                        }
                }
                catch (Exception ex)
                {
                    throw new Exception("Error : " + ex.Message);
                }
                finally
                {
                    if (ObjDbDataReader != null) ObjDbDataReader.Close();
                    ObjDataAccessContext.Dispose(ObjDbCommand);
                }

                return objCustomerList;
            });

        }
    }

通用存储库界面

public interface IRepository<TEntity> where TEntity : class
    {
        Task<List<TEntity>> GetAllAsync();
    }

通用存储库实现

public class BaseRepository
    {
        protected readonly DataAccessContext ObjDataAccessContext;

        protected readonly DbCommand ObjDbCommand;

        protected DbDataReader ObjDbDataReader;

        protected BaseRepository(DataAccessContext objDataAccessContext)
        {
            ObjDataAccessContext = objDataAccessContext;
            ObjDbCommand = ObjDataAccessContext.GetCommand(true, IsolationLevel.ReadCommitted);
        }

        protected void BuildModel<T>(DbDataReader objDataReader, T item) where T : class
        {
            for (var inc = 0; inc < objDataReader.FieldCount; inc++)
            {
                var type = item.GetType();
                var prop = type.GetProperty(objDataReader.GetName(inc));
                var val = objDataReader.GetValue(inc) is DBNull || objDataReader.GetValue(inc).Equals(null) ||
                          string.IsNullOrEmpty(Convert.ToString(objDataReader.GetValue(inc)))
                    ? null
                    : objDataReader.GetValue(inc);
                prop?.SetValue(item, val, null);
            }
        }
    }

数据库访问上下文使用 ADO.NET

public abstract class DataAccessContext
    {
        public DbCommand GetCommand(bool isTransaction, IsolationLevel isolationLevel)
        {
            var connectionString = DbConfiguration.ConnectionString;
            return GetDbCommand(isTransaction, isolationLevel, connectionString);
        }

        public int ExecuteNonQuery(DbCommand objDbCommand, string textOrSpName, CommandType commandType)
        {
            try
            {
                objDbCommand.CommandType = commandType;
                objDbCommand.CommandText = textOrSpName;
                return objDbCommand.ExecuteNonQuery();
            }
            catch (DbException sqlEx)
            {
                throw new Exception("ExecuteNonQuery " + textOrSpName, sqlEx);
            }
        }
        public int ExecuteNonQuery(DbCommand objDbCommand)
        {
            try
            {
                return objDbCommand.ExecuteNonQuery();
            }
            catch (DbException sqlEx)
            {
                throw new Exception("ExecuteNonQuery " + objDbCommand.CommandText, sqlEx);
            }
        }
        public DbDataReader ExecuteReader(DbCommand objDbCommand, string textOrSpName, CommandType commandType)
        {
            try
            {
                objDbCommand.CommandType = commandType;
                objDbCommand.CommandText = textOrSpName;
                return objDbCommand.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (DbException sqlEx)
            {
                throw new Exception("ExecuteReader " + textOrSpName, sqlEx);
            }
        }

        public DbDataReader ExecuteReader(DbCommand objDbCommand)
        {
            try
            {
                return objDbCommand.ExecuteReader(CommandBehavior.CloseConnection);
            }
            catch (DbException sqlEx)
            {
                throw new Exception("ExecuteReader " + objDbCommand.CommandText, sqlEx);
            }
        }

        public void Dispose(DbCommand objDbCommand)
        {
            if (objDbCommand.Connection != null)
            {
                objDbCommand.Connection.Dispose();
                objDbCommand.Connection = null;
            }

            if (objDbCommand.Transaction != null)
            {
                objDbCommand.Transaction.Dispose();
                objDbCommand.Transaction = null;
            }

            objDbCommand.Dispose();
            objDbCommand = null;
        }

        private DbCommand GetDbCommand(bool bIsTransaction, IsolationLevel isolationLevel, string connectionString)
        {
            // retrieve provider invariant name from web.config
            var providerInvariantName = string.Empty;
            if (string.IsNullOrEmpty(providerInvariantName))
                providerInvariantName = "System.Data.SqlClient";
            // create the specific invariant provider
            //DbProviderFactories.RegisterFactory("System.Data.SqlClient", SqlClientFactory.Instance);
            var objDbProviderFactory = DbProviderFactories.GetFactory(providerInvariantName);
            var objDbConnection = objDbProviderFactory.CreateConnection();
            if (objDbConnection == null) return null;
            objDbConnection.ConnectionString = connectionString;
            var objDbCommand = objDbProviderFactory.CreateCommand();
            if (objDbCommand == null) return null;
            objDbCommand.Connection = objDbConnection;
            objDbConnection.Open();
            if (bIsTransaction)
            {
                var objDbTransaction = objDbConnection.BeginTransaction(isolationLevel);
                objDbCommand.Transaction = objDbTransaction;
                return objDbCommand;
            }

            return objDbCommand;
        }
    }

这是Startup.cs文件

public void ConfigureServices(IServiceCollection services)
        {
            DbConfiguration.ServerName = Configuration["DbConnection:ServerName"];
            DbConfiguration.DatabaseName = Configuration["DbConnection:DatabaseName"];
            DbConfiguration.UserId = Configuration["DbConnection:UserId"];
            DbConfiguration.Password = Configuration["DbConnection:Password"];
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

            //services.AddSingleton(typeof(DataAccessContext));

            // In production, the React files will be served from this directory
            services.AddSpaStaticFiles(configuration =>
            {
                configuration.RootPath = "ClientApp/build";
            });
            //Dependency Injection
            //services.AddScoped(sp => sp.GetService(typeof(DataAccessContext)));
            services.AddScoped<ICustomerRepository, CustomerRepository>();
            services.AddScoped<IUnitOfWork, UnitOfWork>();
            services.AddScoped<ICustomersManager, CustomersManager>();
        }

如何解决这个问题?

显示的代码片段中没有任何内容可以说明为什么 DataAccessContext 应该是 abstract class。

具体化class

public class DataAccessContext {
    //...code omitted for brevity
}

其次,classes 应该依赖于服务的抽象而不是具体化。 DataAccessContext 应该有一个支持抽象。

public interface IDataAccessContext {
    DbCommand GetCommand(bool isTransaction, IsolationLevel isolationLevel);
    int ExecuteNonQuery(DbCommand objDbCommand, string textOrSpName, CommandType commandType);
    int ExecuteNonQuery(DbCommand objDbCommand);
    DbDataReader ExecuteReader(DbCommand objDbCommand, string textOrSpName, CommandType commandType);
    DbDataReader ExecuteReader(DbCommand objDbCommand);
    Dispose(DbCommand objDbCommand);
    //...
}

public class DataAccessContext: IDataAccessContext {
    //...code omitted for brevity
}

Dependent classes 应该显式依赖于那个抽象

例如

public class UnitOfWork : IUnitOfWork {
    private readonly IDataAccessContext _context;
    private ICustomerRepository _customerRepository;

    public UnitOfWork(IDataAccessContext context) {
        _context = context;
    }

    //...omitted for brevity

以及向DI容器注册的抽象和实现

services.AddSingleton<IDataAccessContext, DataAccessContext>();

以便它知道如何在激活其依赖项时解析服务

An unhandled exception occurred while processing the request. InvalidOperationException: Unable to resolve service for type 'CustomerManager.Db.DataAccessContext' while attempting to activate 'CustomerManager.Repository.UnitOfWork'.

那是因为你没有在Startup.cs中注册DataAccessContext

因为你的DataAccessContextabstract,注意你一般不能注册抽象类,因为它们不能被实例化。

更改如下:

public class DataAccessContext {}

按如下方式注册:

services.AddScoped(typeof(DataAccessContext));

services.AddScoped 在这个问题上比 AddSingleton 更好