简体   繁体   中英

Dependency Injection to Unit of Work

I'm having an issue my unitofwork doesn't create instance of AppSettings whenever it is called. Unitofwork is for my repository data layer.

This error comes out:

An unhandled exception occurred while processing the request. NullReferenceException: Object reference not set to an instance of an object. Core.UnitOfWork..ctor() in UnitOfWork.cs, line 24

Stack Query Cookies Headers NullReferenceException: Object reference not set to an instance of an object. Core.UnitOfWork..ctor() in UnitOfWork.cs + _connection = new SqlConnection(App.GetConnectionString()); Core.Service.UserService.Login(User entity) in UserService.cs + using (var uow = new UnitOfWork(/ connStr /)) SRTManagement.Controllers.LoginController+d__6.MoveNext() in LoginController.cs + var _user = service.Login(user);

Startup.cs

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient<IAppSettings,AppSettings>();
        services.AddMvc();
    }

IAppSettings.cs

namespace Core.Etc
{
    public interface IAppSettings
    {
        string GetConnectionString();
    }
}

AppSettings.cs

namespace Core.Etc
{
    public class AppSettings : IAppSettings
    {
        public readonly string _connectionString;

        public AppSettings(IConfiguration configuration)
        {
            _connectionString = configuration.GetConnectionString("DefaultConnection");
        }

        public string GetConnectionString()
        {
            return _connectionString;
        }
    }
}

UnitOfWork.cs

namespace Core
{
    public class UnitOfWork : IUnitOfWork
    {
        private IDbConnection _connection;
        private IDbTransaction _transaction;
        private IUserRepository _user;
        private IRoleRepository _role;
        private IAppSettings App;
        private bool _disposed;
        private bool _token;

        public UnitOfWork()
        {
            _connection = new SqlConnection(App.GetConnectionString());
            _connection.Open();
            _transaction = _connection.BeginTransaction();
            _token = false;
        }

        public IUserRepository UserRepository
        {
            get { return _user ?? (_user = new UserRepository(_transaction)); }
        }

        public IRoleRepository RoleRepository
        {
            get { return _role ?? (_role = new RoleRepository(_transaction)); }
        }

        public bool Success()
        {
            return _token;
        }

        public void Commit()
        {
            try
            {
                _transaction.Commit();
                _token = true;
            }
            catch
            {
                _transaction.Rollback();
                _token = false;
                throw;
            }
            finally
            {
                _transaction.Dispose();
                _transaction = _connection.BeginTransaction();
                ResetRepositories();
            }
        }

        private void ResetRepositories()
        {
            _user = null;
            _role = null;
            App = null;
        }

        public void Dispose()
        {
            DisposeConn(true);
            GC.SuppressFinalize(this);
        }

        private void DisposeConn(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    if(_transaction != null)
                    {
                        _transaction.Dispose();
                        _transaction = null;
                    }
                    if(_connection != null)
                    {
                        _connection.Dispose();
                        _connection = null;
                    }
                }
                _disposed = true;
            }
        }

        ~UnitOfWork()
        {
            DisposeConn(false);
        }
    }
}

IAppSettings is not being injected into your UnitOfWork , so it will be null when call as you have it

public class UnitOfWork : IUnitOfWork {
    private IDbConnection _connection;
    private IDbTransaction _transaction;
    private IUserRepository _user;
    private IRoleRepository _role;
    private IAppSettings App;
    private bool _disposed;
    private bool _token;

    public UnitOfWork(IAppSettings App) {
        this.App = App;
        _connection = new SqlConnection(App.GetConnectionString());
        _connection.Open();
        _transaction = _connection.BeginTransaction();
        _token = false;
    }
    //Remove the rest of the code for brevity
}

Assuming UnitOfWork is also registered with the service collection.

public void ConfigureServices(IServiceCollection services) {
    services.AddTransient<IAppSettings, AppSettings>();
    services.AddTransient<IUnitOfWork, UnitOfWork>();
    services.AddMvc();
}

I would also suggest rethinking the current design and avoid tightly coupling the UoW to implementation concerns like SqlConnection .

If staying with ADO then consider using a IDbConnectionFactory abstraction.

public class MyDbConnectionFactory : IDbConnectionFactory {
    private readonly IAppSettings appSettings;

    public MyDbConnectionFactory(IAppSettings appSettings) {
        this.appSettings = appSettings;
    }

    public IDbConnection CreateConnection() {
        return new SqlConnection(appSettings.GetConnectionString());
    }
}

Which would let the UoW to be refactored to

public class UnitOfWork : IUnitOfWork {
    private IDbConnection _connection;
    private IDbTransaction _transaction;
    private IUserRepository _user;
    private IRoleRepository _role;
    private bool _disposed;
    private bool _token;

    public UnitOfWork(IDbConnectionFactory factory) {
        _connection = factory.CreateConnection();
        _connection.Open();
        _transaction = _connection.BeginTransaction();
        _token = false;
    }

    //Remove the rest of the code for brevity
}

With usual service registrations

public void ConfigureServices(IServiceCollection services) {
    services.AddTransient<IAppSettings, AppSettings>();
    services.AddTransient<IDbConnectionFactory, MyDbConnectionFactory>();
    services.AddTransient<IUnitOfWork, UnitOfWork>();
    services.AddMvc();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM