WPF .Net Core 3.1 依赖注入/服务参考问题

Posted

技术标签:

【中文标题】WPF .Net Core 3.1 依赖注入/服务参考问题【英文标题】:WPF .Net Core 3.1 Dependency Injection/Service Reference Question 【发布时间】:2021-09-11 06:44:29 【问题描述】:

我正在尝试从我的域类中引用 a_UserTenant 中的方法

这是顶部:

public IServiceProvider Services  get; set; 
private readonly A_UserTenant a_UserTenant;
private readonly A_User a_User;
private string Username = null;

public Domain(string Username)

    InitializeComponent();
    this.Username = Username;
    UsernameTextbox.Text = Username;
    loading = new Loading.Loading();
    this.a_UserTenant = this.Services.GetRequiredService<A_UserTenant>();
    this.a_User = this.Services.GetRequiredService<A_User>();

这是我的 App.Xaml

public IServiceProvider ServiceProvider  get; private set; 

public IConfiguration configuration  get; private set; 

protected override void OnStartup(StartupEventArgs e)

    var builder = new ConfigurationBuilder()
     .SetBasePath(Directory.GetCurrentDirectory())
     .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);

    configuration = builder.Build();

    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);

    ServiceProvider = serviceCollection.BuildServiceProvider();

    var login = ServiceProvider.GetService<Login>();
    login.Show();


private void ConfigureServices(IServiceCollection services)

    // ...
    services.AddSingleton(configuration);
    LoadSDR_ManageWSControllers loadSDR_ManageWSControllers = new LoadSDR_ManageWSControllers();
    loadSDR_ManageWSControllers.Services(services);

    //Views
    services.AddTransient(typeof(Login));
    services.AddTransient(typeof(Domain));


现在的问题是我得到一个异常说 -

$exception "值不能为空。(参数 'provider')" System.ArgumentNullException

这是 A_UserTenant 类的构造函数:

private readonly IConfiguration configuration;

public A_UserTenant(IConfiguration configuration)

    this.configuration = configuration;

我该如何解决这个问题?

编辑:

这是我想从我的 Domain 类调用的 A_UserTenant 中的方法之一

public UserTenant Get(string Id)

    RestClient client = new RestClient();
    var link = $"link]Directory/UserTenant/Get";
    var username = uname;
    var password = upw;
    client.BaseUrl = new Uri(link);
    client.Authenticator = new HttpBasicAuthenticator(username, password);
    RestRequest request = new RestRequest();
    request.AddParameter("Id", Id);
    request.Method = Method.GET;
    var res = client.Execute(request);
    if (res.StatusCode == System.Net.HttpStatusCode.OK)
    
        return JsonConvert.DeserializeObject<UserTenant>(res.Content);
    
    else
    
        return null;
    

这是我目前从另一个类导航到 Domain 类的方式:

Domain domain = new Domain(Username);
domain.Show();
this.Close();

【问题讨论】:

你想在 wpf 中使用 asp.net core DI 吗? 您没有将IOptions&lt;T&gt; 用于强配置类型是否有特殊原因? "Parameter 'provider'" 我没有看到提供者参数,完整的堆栈跟踪是什么? 从外观上看,您有一个实例成员IServiceProvider Services,并且您希望它在您的视图中自动分配给您,直言不讳地对您来说效果不佳,它将为空 @LeiYang 是的,我读到有可能? 【参考方案1】:

根据您的问题,您将Domain 注册为服务;

services.AddTransient(typeof(Domain));

但是你的构造函数暗示调用者是直接调用new,而不是从服务提供者那里获取实例;

public Domain(string Username) ...

// maybe the caller looks like this?
var domain = new Domain(username);

正确设计会有点棘手。

您希望每个服务构造函数都明确列出实际需要的服务,这样您就不会陷入“服务定位器”反模式。

但您不希望每个调用者都知道有关这些依赖项的任何信息。

您有多种选择来混合服务依赖项和参数。您可以将参数分配给实例方法。然后也许将所有内容封装在一个静态方法中;

public class Domain
    private Domain(A_UserTenant a_UserTenant, A_User a_user) ...
    private void SetUsername(string Username) ...

    public static Domain Factory(IServiceProvider provider, string Username) 
    
        var domain = services.GetRequiredServce<Domain>();
        domain.SetUsername(username);
        return domain;
    


var domain = Domain.Factory(services, username);

或者您可以将表单排除在服务集合之外,而只在新的服务类中注册依赖项;

public Domain(string Username, DomainDependencies dependencies) ...

var domain = new Domain(
    username,
    services.GetRequiredService<DomainDependencies>()
);

无论哪种方式,您至少需要传递IServiceProvider

【讨论】:

感谢您的回复。对于实例方法,我如何从另一个类导航到 Domain 类?你是对的,我直接从另一个班级打电话给 new 。但是有了那里的参数,这是否意味着我必须将所有预期的服务注入到第一个启动类中然后传递它? var domain = services.GetRequiredServce(); domain.SetUsername(用户名);我把这个放在哪里?我是否也将它放在 Domain 类中?【参考方案2】:

如果你想在 WPF 中使用 .Net Core Dependency Injection,你可以使用反射。例如通过其接口获取正在运行的服务类型:

var interfaceType = typeof(IServiceProvider );
var services = Assembly.GetExecutingAssembly().GetTypes().Where(w => interfaceType.IsAssignableFrom(w)).ToList();

然后你可以使用Activator.CreateInstance(&lt;your service&gt;) as &lt;Service class&gt;;创建实例

【讨论】:

答案与依赖注入无关。 它不是依赖注入,而是和它类似,在 WPF 中我这样调用我的服务,你还有什么推荐的? DI 在背面也使用反射 OP 询问在 wpf 中使用 asp.net core DI,而不是手动制作 DI 框架。【参考方案3】:

依赖注入系统需要所有在 ConfigureService 方法中提前定义构建服务所需的信息。在这种情况下这是不可能的,因为您的 Domain 类需要构造一个字符串。您可以创建某种具有 CreateDomain(string name) 方法的 IDomainService 并将其注入。

【讨论】:

以上是关于WPF .Net Core 3.1 依赖注入/服务参考问题的主要内容,如果未能解决你的问题,请参考以下文章

如何为 .NET Core 3.0 中 WPF 配置依赖注入 ?

.NET Core 3.1 中的依赖注入具有多种实现 [重复]

如何在 .net core 3.1 中的 Newtonsoft JsonConverter 中注入依赖项

.Net6 or .Net Core界面程序依赖注入实现Caliburn.Micro

无法使用 MassTransit 在 Windows 服务应用程序 (.Net Core 3.1) 中向消费者注入服务

ASP.NET Core 依赖注入(DI)