You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET6 MAUI中IPublicClientApplication依赖注入错误解决咨询

.NET 6 MAUI 登录服务依赖注入配置方案

先解决初始错误

你遇到的Cannot instantiate implementation type 'Interface' for service type 'Interface'错误,是因为注册服务时把接口当成了实现类。比如错误写法:

// 错误:第二个参数不能是接口
services.AddScoped<ILoginService, ILoginService>();

正确写法应该是把实际实现类(LoginService)作为第二个参数:

// 正确:服务类型是接口,实现类型是具体类
services.AddScoped<ILoginService, LoginService>();

处理两个IPublicClientApplication实例的注入问题

因为LoginService需要两个不同的IPublicClientApplication实例,直接重复注册同类型服务会导致DI只会注入最后一个实例,下面提供三种可行方案:

方案1:使用Keyed Services(推荐,.NET 6+支持)

通过给两个实例添加唯一标识(Key),在创建LoginService时指定获取对应Key的实例:

  1. 注册带Key的IPublicClientApplication实例:
// 注册第一个实例,Key为"AuthApp1"
services.AddKeyedScoped<IPublicClientApplication>("AuthApp1", (sp, key) =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    return PublicClientApplicationBuilder
        .Create(config["AzureAd:AppId1"])
        .WithRedirectUri($"msal{config["AzureAd:AppId1"]}://auth")
        .Build();
});

// 注册第二个实例,Key为"AuthApp2"
services.AddKeyedScoped<IPublicClientApplication>("AuthApp2", (sp, key) =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    return PublicClientApplicationBuilder
        .Create(config["AzureAd:AppId2"])
        .WithRedirectUri($"msal{config["AzureAd:AppId2"]}://auth")
        .Build();
});
  1. 注册ILoginService时,通过工厂方法获取两个带Key的实例:
services.AddScoped<ILoginService>(sp =>
{
    var app1 = sp.GetRequiredKeyedService<IPublicClientApplication>("AuthApp1");
    var app2 = sp.GetRequiredKeyedService<IPublicClientApplication>("AuthApp2");
    return new LoginService(app1, app2);
});

方案2:直接在工厂方法中创建实例

如果这两个实例只给LoginService使用,不需要复用,可以直接在创建LoginService时生成两个实例:

services.AddScoped<ILoginService>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();

    // 创建第一个认证应用实例
    var app1 = PublicClientApplicationBuilder
        .Create(config["AzureAd:AppId1"])
        .WithRedirectUri($"msal{config["AzureAd:AppId1"]}://auth")
        .Build();

    // 创建第二个认证应用实例
    var app2 = PublicClientApplicationBuilder
        .Create(config["AzureAd:AppId2"])
        .WithRedirectUri($"msal{config["AzureAd:AppId2"]}://auth")
        .Build();

    return new LoginService(app1, app2);
});

方案3:用自定义接口区分实例

创建两个空接口继承自IPublicClientApplication,通过不同接口来区分实例:

  1. 定义自定义接口:
public interface IAuthApp1 : IPublicClientApplication { }
public interface IAuthApp2 : IPublicClientApplication { }
  1. 注册这两个接口的实现:
services.AddScoped<IAuthApp1>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    // 强制转换为自定义接口(PublicClientApplication实现了IPublicClientApplication,所以可以转换)
    return (IAuthApp1)PublicClientApplicationBuilder
        .Create(config["AzureAd:AppId1"])
        .WithRedirectUri($"msal{config["AzureAd:AppId1"]}://auth")
        .Build();
});

services.AddScoped<IAuthApp2>(sp =>
{
    var config = sp.GetRequiredService<IConfiguration>();
    return (IAuthApp2)PublicClientApplicationBuilder
        .Create(config["AzureAd:AppId2"])
        .WithRedirectUri($"msal{config["AzureAd:AppId2"]}://auth")
        .Build();
});
  1. 修改LoginService的构造函数,接收自定义接口:
public class LoginService : ILoginService
{
    private readonly IAuthApp1 _authApp1;
    private readonly IAuthApp2 _authApp2;

    public LoginService(IAuthApp1 authApp1, IAuthApp2 authApp2)
    {
        _authApp1 = authApp1;
        _authApp2 = authApp2;
    }

    // 登录相关业务方法
}
  1. 正常注册ILoginService:
services.AddScoped<ILoginService, LoginService>();

内容的提问来源于stack exchange,提问作者eengstroem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 15:57:54