我使用的是ASP.NET Core MVC Web应用程序.我有一个名为District的模型:

public class DistrictModel
{
    public int district_id { get; set; }
    public string district_name { get; set; }
}

我有两个用于地区的数据源,一个是JSON文件中的测试数据,另一个是SQL Server数据库中的生产数据.

为了便于在数据源之间切换(我认为这称为依赖关系反转?),我创建了一个接口来定义获取数据的函数:

public interface IDistrictServices
{
    List<DistrictModel> GetAllDistricts();
    DistrictModel GetDistrictByID(int district_id);
    List<DistrictModel> SearchDistricts(string search_term);
}

我使用了用于检索JSON和SQL的两个类的接口.

JSON类:

public class DistrictJSON : IDistrictServices
{
    public List<DistrictModel> GetAllDistricts()
    {
        string district_file_location = @"wwwroot/data/districts.json"; //move this to config
        string jsonString = File.ReadAllText(district_file_location);
        List<DistrictModel> found_districts = JsonSerializer.Deserialize<List<DistrictModel>>(jsonString);
        return found_districts;
    }
}

SQL Server类:

public class DistrictSQL : IDistrictServices
{
    //move connection string to config
    string connection_string = @"Data Source=SWSQLDEV001;User ID=thannah;Password=*****;Connect Timeout=30;Encrypt=False;Database=CapV3;"; 

    public List<DistrictModel> GetAllDistricts()
    {
        List<DistrictModel> found_districts = new List<DistrictModel>();

        string sql_statement = @"
            SELECT dd.id, dd.fullname
            FROM districtdim dd
            INNER JOIN versions v ON v.districtid = dd.id
            WHERE v.version = 'Current Forecast' ";

        using (SqlConnection connection = new SqlConnection(connection_string))
        {
            SqlCommand command = new SqlCommand (sql_statement, connection);

            try
            {
                connection.Open ();

                SqlDataReader reader = command.ExecuteReader();

                while (reader.Read())
                {
                    found_districts.Add(new DistrictModel { district_id = (int)reader[0], district_name = (string)reader[1] });
                }
            } 
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        return found_districts;
    }
}

我的控制器获取所有地区,并将它们发送到一个视图进行显示:

public class DistrictController : Controller
{
    public IDistrictServices districtlist { get; set; }

    public DistrictController(IDistrictServices dataservice) 
    {
        districtlist = dataservice;
    }

    public IActionResult Index()
    {
        return View(districtlist.GetAllDistricts()) ;
    }
}

Program.cs定义使用的服务是JSON还是SQL Server:

using OperationalForecast.Services;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddTransient<IDistrictServices, DistrictSQL>();
//builder.Services.AddTransient<IDistrictServices, DistrictJSON>();
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

以下是我添加的两行代码:

builder.Services.AddTransient<IDistrictServices, DistrictSQL>();
//builder.Services.AddTransient<IDistrictServices, DistrictJSON>();

无论我留下哪一行没有注释,都是使用的类.如果我没有注释这两行,那么第二行就会被使用.

我的问题是:这到底是怎么回事?在某个时刻,DistrictController构造函数被调用(我假设每次使用/Districturl?还是每节课只有一次?).这段代码如何知道我打算将指定的类用于District控制器,而不是其他控制器?如果我有多个接口,并且需要将多个接口传递给控制器,该怎么办?

这部分看起来像是PFM,我担心如果我不真正了解它的工作原理,我将无法完成我的申请.

推荐答案

这段代码如何知道我打算将指定的类用于区域控制器,而不是其他控制器?

这是不可能的.

每次服务Provider 需要实例化您的区域控制器(或任何其他需要IDistrictServices的类型)时,它都会注入一个新的DistrictSQL实例,因为这就是您在这里告诉它要做的:

builder.Services.AddTransient<IDistrictServices, DistrictSQL>();

如果不同的控制器需要不同的实现,则需要使用不同的服务类型(或使用某个工厂在运行时解析实现类型).


在某个时刻,会调用SecreictControl构造函数(我假设每次使用/Region url时?还是每个会话只有一次?)

控制器构造函数在每个HTTP请求中调用一次.

它们注册为scoped,通过此扩展方法提供服务:

builder.Services.AddControllersWithViews();

服务提供者 for each HTTP请求创建一个新的作用域,因此将解析单个控制器实例来处理该请求.


如果我有多个接口,并且需要将多个接口传递给控制器,该怎么办?

然后,您也可以向服务Provider 注册这些类型,就像您为IDistrictServices注册类型一样.

请注意,您可以控制服务的生命周期:

  • 暂态=每次需要依赖项时都有新实例.
  • Scope=在服务作用域的持续时间内重用单个实例(相当于ASP.NET中的HTTP请求).
  • Singleton=在应用程序的整个生命周期内重复使用单个实例.

Csharp相关问答推荐

Blazor:类型或命名空间名称Components在命名空间中不存在''

哪个nuget包含SecurityStampValidatorOptions

ASP.NET核心结果.文件vs结果.流

REST API端点中异步后台代码执行的类型

为什么SignalR在每个Blazor服务器应用程序启动时最多启动8个服务器?

需要在重新启动ApplicartionPool或IIS后启动/唤醒API的帮助

从ASP.NET Core中的枚举字段填充 Select 选项时,将默认的第一个选项添加为 Select 元素

如何在没有前缀和可选后缀的情况下获取Razor Page Handler方法名称?

异步实体框架核心查询引发InvalidOperation异常

C# CompareTo()和Compare()可以返回除-1和1以外的整数吗?

如何在用户在线时限制令牌生成?

VS 2022 for ASP.NET Core中缺少自定义项模板

委托RequestDelegate不带2个参数-ASP.NET Core 8最小API

为值对象编写自定义JsonConverter

泛型参数在.NET 8 AOT中没有匹配的批注

在PostgreSQL上使用ExecuteSqlRawAsync的C#11原始字符串文字有区分大小写的问题

VS 2022与VS 2019:如何/为什么创建额外的任务?

.Net MAUI,在将FlyoutPage添加到容器之前,必须设置添加构造函数导致Flyout和Detail"

在';、';附近有错误的语法.必须声明标量变量";@Checkin";.';

在Unity C#中按键点击错误的参数