部分服务无法构建 === 当我倾向于构建我的API

huangapple go评论57阅读模式
英文:

Some services are not able to be constructed === When I tend to build my API

问题

I have models:

public class Employees
{
    public int Id { get; set; }
    public string First_name { get; set; }
    public string Last_name { get; set; }
    public string User_name { get; set; }
    public string Password { get; set; }
    public string Email { get; set; }
    public string Phone_number { get; set; }
    public string Mobile_number { get; set; }
    public bool Active_is { get; set; }
}
public class HasRole
{
    public int Id { get; set; }
    public int Employees_id { get; set; }
    public int Role_id { get; set; }
    public TimeOnly Time_from { get; set; }
    public TimeOnly Time_to { get; set; }
    public bool Active_is { get; set; }
}
public class Role
{
    public int Id { get; set; }
    public string Role_name { get; set; }
}

I have IRepository:

public interface IRepository<TEntity>
{
    Task<IEnumerable<TEntity>> Get_all_Information();
    Task<TEntity> Get_by_Id(int id);
}

and Implementation:

public class RepositoryBase<TEntity> : IRepository<TEntity> where TEntity : class
{
    protected IDbConnection _connection;
    protected IDbTransaction _transaction;
    protected string title_table;

    public RepositoryBase(IDbConnection connection, IDbTransaction transaction, string titleTable)
    {
        _connection = connection;
        _transaction = transaction;
        title_table = titleTable;
    }

    public async Task<IEnumerable<TEntity>> Get_all_Information()
    {
        var query = $"Select * From {title_table}";
        return await _connection.QueryAsync<TEntity>(query, transaction: _transaction);
    }

    public async Task<TEntity> Get_by_Id(int id)
    {
        string query = $"Select * From {title_table} Where Id = @id";
        var result =
            await _connection.QueryFirstOrDefaultAsync<TEntity>(query, param: new { id }, transaction: _transaction);

        if (result == null)
        {
            throw new KeyNotFoundException($"{title_table} with id [{id}] could not be found.");
        }

        return result;
    }
}

Employee Repository:

public class EmployeesRepository : RepositoryBase<Employees>, IEmployeesRepository
{
    public EmployeesRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction, "Employees")
    {
    }

    public async Task<IEnumerable<Employees>> Get_all_activity_Employees()
    {
        string query = "Select * From [dbo].Employees Where Active_is = 1";
        IEnumerable<Employees> result = await _connection.QueryAsync<Employees>(query, transaction: _transaction);
        return result;
    }

    public async Task<IEnumerable<Employees>> Get_all_Employees_By_Specialization(string specialization)
    {
        string query = "Select a.First_name, a.Last_name, b.Role_name " +
                       "From Employees a, Role b, Has_Role c " +
                       $"Where c.Employees_id = a.Id and c.Role_id = b.Id and b.Role_name = {specialization}";

        IEnumerable<Employees> result = await _connection.QueryAsync<Employees>(query, transaction: _transaction);
        return result;
    }
}

I add Scoped to DI

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(s =>
{
    s.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "Swagger Example-Dapper-Migration API",
        Description = "Base Swagger Description"
    });

    var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    s.IncludeXmlComments(xmlPath);
});

builder.Services.AddScoped((s) => new SqlConnection(builder.Configuration.GetConnectionString("SqlConnection")));
builder.Services.AddScoped<IDbTransaction>(s =>
{
    SqlConnection connection = s.GetRequiredService<SqlConnection>();
    connection.Open();
    return connection.BeginTransaction();
});

// Dependency Injections 
builder.Services.AddSingleton<DapperContext>()
    .AddScoped<ICompanyRepository, CompanyRepository>()
    .AddScoped<IDepartmentRepository, DepartmentRepository>()
    .AddScoped<IEmployeesRepository, EmployeesRepository>();


var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseSwagger();

    app.UseSwaggerUI(s =>
    {
        s.SwaggerEndpoint("/swagger/v1/swagger.json", "Swagger API Version");
        s.RoutePrefix = string.Empty;
    });
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllers();

app.Run();

and I have the Problem:

System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Dapper_Data_Access_Layer.Repository.Contracts.Interfaces.IEmployeesRepository Lifetime: Scoped ImplementationType: Dapper_Data_Access_Layer.Repository.Contracts.EmployeesRepository': Unable to resolve service for type 'System.Data.IDbConnection' while attempting to activate 'Dapper_Data_Access_Layer.Repository.Contracts.EmployeesRepository'.)'

I create the RoleRepository and HasRoleRepository, but I have the same problem. I only start learning it, and maybe my mistake is very simple, but I will be very grateful for the help.

英文:

I have models:

  public class Employees
    {
        public int Id { get; set; }
        public string First_name { get; set; }
        public string Last_name { get; set; }
        public string User_name { get; set; }
        public string Password { get; set; }
        public string Email { get; set; }
        public string Phone_number { get; set; }
        public string Mobile_number { get; set; }
        public bool Active_is { get; set; }
    }
 public class HasRole
    {
        public int Id { get; set; }
        public int Employees_id { get; set; }
        public int Role_id { get; set; }
        public TimeOnly Time_from { get; set; }
        public TimeOnly Time_to { get; set; }
        public bool Active_is { get; set; }
    }
public class Role
    {
        public int Id { get; set; }
        public string Role_name { get; set; }
    }

I have IRepository:

  public interface IRepository&lt;TEntity&gt;
    {
        public Task&lt;IEnumerable&lt;TEntity&gt;&gt; Get_all_Information();
        public Task&lt;TEntity&gt; Get_by_Id(int id);
    }

and Implementation:

 public class RepositoryBase&lt;TEntity&gt; : IRepository&lt;TEntity&gt; where TEntity : class
    {
        protected IDbConnection _connection;
        protected IDbTransaction _transaction;
        protected string title_table;

        public RepositoryBase(IDbConnection connection, IDbTransaction transaction, string titleTable)
        {
            _connection = connection;
            _transaction = transaction;
            title_table = titleTable;
        }

        public async Task&lt;IEnumerable&lt;TEntity&gt;&gt; Get_all_Information()
        {
            var query = $&quot;Select * From {title_table}&quot;;
            return await _connection.QueryAsync&lt;TEntity&gt;(query, transaction: _transaction);
        }

        public async Task&lt;TEntity&gt; Get_by_Id(int id)
        {
            string query = $&quot;Select * From {title_table} Where Id = @id&quot;;
            var result =
                await _connection.QueryFirstOrDefaultAsync&lt;TEntity&gt;(query, param: new { id }, transaction: _transaction);

            if (result == null)
            {
                throw new KeyNotFoundException($&quot;{title_table} with id [{id}] could not be found.&quot;);
            }

            return result;
        }
    }

Employee Repository:

  public class EmployeesRepository : RepositoryBase&lt;Employees&gt;, IEmployeesRepository
    {
        public EmployeesRepository(IDbConnection connection, IDbTransaction transaction) : base(connection, transaction, &quot;Employees&quot;)
        {
        }

        public async Task&lt;IEnumerable&lt;Employees&gt;&gt; Get_all_activity_Employees()
        {
            string query = &quot;Select * From [dbo].Employees Where Active_is = 1&quot;;
            IEnumerable&lt;Employees&gt; result = await _connection.QueryAsync&lt;Employees&gt;(query, transaction: _transaction);
            return result;
        }

        public async Task&lt;IEnumerable&lt;Employees&gt;&gt; Get_all_Employees_By_Specialization(string specialization)
        {
            string query = &quot;Select a.First_name, a.Last_name, b.Role_name &quot; +
                           &quot;From Employees a, Role b, Has_Role c &quot; +
                           $&quot;Where c.Employees_id = a.Id and c.Role_id = b.Id and b.Role_name = {specialization}&quot;;

            IEnumerable&lt;Employees&gt; result = await _connection.QueryAsync&lt;Employees&gt;(query, transaction: _transaction);
            return result;
        }
    }

I add Scoped to DI

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddSwaggerGen(s =&gt;
{
    s.SwaggerDoc(&quot;v1&quot;, new OpenApiInfo
    {
        Version = &quot;v1&quot;,
        Title = &quot;Swagger Example-Dapper-Migration API&quot;,
        Description = &quot;Base Swagger Description&quot;
    });

    var xmlFile = $&quot;{Assembly.GetExecutingAssembly().GetName().Name}.xml&quot;;
    var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
    s.IncludeXmlComments(xmlPath);
});

builder.Services.AddScoped((s) =&gt; new SqlConnection(builder.Configuration.GetConnectionString(&quot;SqlConnection&quot;)));
builder.Services.AddScoped&lt;IDbTransaction&gt;(s =&gt;
{
    SqlConnection connection = s.GetRequiredService&lt;SqlConnection&gt;();
    connection.Open();
    return connection.BeginTransaction();
});

// Dependency Injections 
builder.Services.AddSingleton&lt;DapperContext&gt;()
    .AddScoped&lt;ICompanyRepository, CompanyRepository&gt;()
    .AddScoped&lt;IDepartmentRepository, DepartmentRepository&gt;()
    .AddScoped&lt;IEmployeesRepository, EmployeesRepository&gt;();


var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
    app.UseSwagger();

    app.UseSwaggerUI(s =&gt;
    {
        s.SwaggerEndpoint(&quot;/swagger/v1/swagger.json&quot;, &quot;Swagger API Version&quot;);
        s.RoutePrefix = string.Empty;
    });
}
else
{
    app.UseExceptionHandler(&quot;/Error&quot;);
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllers();

app.Run();

and I have the Problem:
> System.AggregateException: 'Some services are not able to be constructed (Error while validating the service descriptor 'ServiceType: Dapper_Data_Access_Layer.Repository.Contracts.Interfaces.IEmployeesRepository Lifetime: Scoped ImplementationType: Dapper_Data_Access_Layer.Repository.Contracts.EmployeesRepository': Unable to resolve service for type 'System.Data.IDbConnection' while attempting to activate 'Dapper_Data_Access_Layer.Repository.Contracts.EmployeesRepository'.)'

I create the RoleRepository and HasRoleRepositroy, but I have the same problem. I only start learning it and maybe my mistake is very simple, but I will be very grateful for the help

答案1

得分: 1

您的异常消息表示存储库找不到已注册的 IDbConnection 实现。可能的原因是内置的 IoC 没有将您的 SqlConnection 映射到 IDbConnection

builder.Services.AddScoped((s) => new SqlConnection(builder.Configuration.GetConnectionString("SqlConnection")));

因此,尝试显式注册它:

builder.Services.AddScoped<IDbConnection>(s => new SqlConnection(builder.Configuration.GetConnectionString("SqlConnection")));

请确保通过检查 IServicesCollection 进行注册。

更新:

我已下载您的项目并重新检查了代码。答案似乎是正确的 - 我尝试显式注册 IDbConnection,并且它已为 EmployeesRepository 构建,然而在 DepartmentRepository 中出现了类似的问题,因为您在那里等待 SqlConnection

解决方案有两个:

1 - 在所有地方使用相同的参数(SqlConnectionIDbConnection)进行注入

或者

2 - 注册 both SqlConnectionIDbConnection(这不是一个好的方法)

另外,请记住,如果选择仅使用 IDbConnection,它可能在运行时失败,因为在这里使用 IDbConnection 会导致以下行失败,因为在集合中没有 SqlConnection 服务:

builder.Services.AddScoped<IDbTransaction>(s =>
{
    // 下面的行将失败,因为集合中没有 SqlConnection 服务
    // 也在这里使用 IDbConnection
    SqlConnection connection = s.GetRequiredService<SqlConnection>();
    connection.Open();
    return connection.BeginTransaction();
});
英文:

Your exception message says that Repository cannot find the registered IDbConnection implementation. The possible reason is that built-in IoC didn't map your SqlConnection to the IDbConnection.

> builder.Services.AddScoped((s) => new SqlConnection(builder.Configuration.GetConnectionString("SqlConnection")));

Therefore, try to register it explicitly:

builder.Services.AddScoped&lt;IDbConnection&gt;(s =&gt; new SqlConnection(builder.Configuration.GetConnectionString(&quot;SqlConnection&quot;)));

Make sure it is registered by checking IServicesCollection.

UPD:

I downloaded your project and rechecked the code. The answer seems to be right - I tried to register IDbConnection explicitly and it has been built for EmployeesRepository, however the similar issue appeared for DepartmentRepository as you wait for SqlConnection there.

The solutions are:

1 - Use the same parameter everywhere (SqlConnection or IDbConnection) for injections

OR

2 - Register both SqlConnection and IDbConnection (which is not good approach)

Also keep in mind, that if you choose to use IDbConnection only, it might fail in runtime over here:

builder.Services.AddScoped&lt;IDbTransaction&gt;(s =&gt;
{
    // line below will fail as there is no SqlConnection service in the Collection
    // Use IDbConnection here as well
    SqlConnection connection = s.GetRequiredService&lt;SqlConnection&gt;();
    connection.Open();
    return connection.BeginTransaction();
});

huangapple
  • 本文由 发表于 2023年2月27日 01:15:34
  • 转载请务必保留本文链接:https://go.coder-hub.com/75573707.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定