错误:“在 SetAuthenticationState 之前调用 GetAuthenticationStateAsync。”

问题描述 投票:0回答:1

我有一个 blazor 项目,其中我使用依赖注入来使用 AuthenticationStateProvider。

我收到错误:
'GetAuthenticationStateAsync 在 SetAuthenticationState 之前被调用。

我有两项服务:

  1. 返回用户身份的ServiceClass。
  2. IReportServiceConfiguration 使用另一个服务从数据库(xml 字符串)返回报告。

报告解析器间接依赖于ServiceClass,这是在startup.cs中的注册:

  services.AddScoped<IServiceClass, ServiceClass>();
        services.AddScoped<IReportServiceConfiguration>(sp =>
            new ReportServiceConfiguration
            {

                ReportingEngineConfiguration = sp.GetService<IConfiguration>(),


                HostAppId = "Html5DemoAppCore",
                Storage = new FileStorage(),
                ReportSourceResolver = sp.GetService<CustomReportSourceResolver>(),
            }
            ); ;

服务类别代码:

 public class ServiceClass : IServiceClass
{
    public ServiceClass(AuthenticationStateProvider authenticationStateProvider)
    {

        _authenticationStateProvider = authenticationStateProvider;

    }
    private readonly AuthenticationStateProvider _authenticationStateProvider;
    private string authuser = "";
    public async Task<string> GetIdentity()
    {
        var result = "";
        try
        {
            var authState = await _authenticationStateProvider.GetAuthenticationStateAsync();
            var user = authState.User;
            IEnumerable<Claim> claims = user.Claims;

            if (authState != null)
            {
                result = claims.FirstOrDefault(c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress").Value;
                authuser = result;
            }
            else
                result = authuser;

        }
        catch (Exception ex)
        { System.Diagnostics.Debug.WriteLine(ex.ToSafeString()); }
        return result;
    } 
}

全周期

服务类的 getIdentity() 自应用程序启动以来被调用多次,并且运行良好。 但是当这个剃刀组件运行时

<ReportViewer ViewerId="rv1"
      
          ServiceUrl="/api/reports"
          
        ReportSource="@(new ReportSourceOptions()
                          {
                              Report = "reportAccountingGeneralLedger",
                              Parameters= new Dictionary <string,object>
                              {}
                          })"
          Parameters="@(new ParametersOptions { Editors = new EditorsOptions { MultiSelect = EditorType.ComboBox, SingleSelect = EditorType.ComboBox } })"
          ScaleMode="@(ScaleMode.Specific)"
          Scale="1.0" />

Report = "reportAccountingGeneralLedger" 部分是通过我们在startup.cs中注册的ReportServiceConfiguration服务来解析的。 (它使用 CustomReportSourceResolver 类从数据库获取报告 xml 定义并使用它返回报告源,代码如下)

class CustomReportSourceResolver : IReportSourceResolver
{

    public CustomReportSourceResolver(IServiceClass sc, IReportConnectionStringManager csm)
    {
        userClass = sc;
        conStrMan = csm;
        //_scopeFactory = sc;
    }
    private readonly IServiceClass userClass;
    private readonly IReportConnectionStringManager conStrMan;
    public Telerik.Reporting.ReportSource Resolve(string reportName, OperationOrigin operationOrigin, IDictionary<string, object> currentParameterValues)
    {
        var report = string.Empty;
        if (!string.IsNullOrEmpty(reportName))
        {

            using (var context = new DataContext(userClass))
            {
                report = (from table in context.Reports where table.Name == reportName select table.Definition).First();
            }
        }
        ReportSource updatedReport;
        if (string.IsNullOrEmpty(report))
        {
            throw new System.Exception("Unable to load a report with the specified ID: " + reportName);

        }
        else
        {
            XmlReportSource retreivedReport = new Telerik.Reporting.XmlReportSource { Xml = report };
            updatedReport = conStrMan.UpdateReportSource(retreivedReport);
        }
        return updatedReport;
    }
}

datacontext的代码:

 public class DataContext : DbContext
{

    public DataContext(IServiceClass sc)
    {

        serviceClass = sc;
    }
    private readonly IServiceClass serviceClass;
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(serviceClass.getUserConnectionString().Result);
    }
object1..object2.. object3....
}

从上面的代码可以看出,为了通过数据库获取报告,它使用了 datacontext。 Datacontext 具有动态连接字符串,这就是为什么执行会转到服务类中的 getIdentity() 方法,然后我们在主题中获取消息。

asp.net-core dependency-injection asp.net-identity blazor telerik-reporting
1个回答
0
投票

您不应该直接在 ServiceClass 服务中注入

AuthenticationStateProvider
。相反,将其注入组件中并将其作为方法参数传递给 GetIdentity。

这就是 Microsoft

ASP.Net Core
文档所说的:

不要尝试在自定义中解决

AuthenticationStateProvider
范围,因为它会导致创建一个新的实例
AuthenticationStateProvider
未正确初始化。

要访问服务范围内的

AuthenticationStateProvider
组件,将
AuthenticationStateProvider
@inject
一起注入 指令或
[Inject]
属性并将其作为 范围。这种方法确保了正确的、初始化的
AuthenticationStateProvider
的实例用于每个用户应用程序 实例。

为组件范围内的服务注入 AuthenticationStateProvider

© www.soinside.com 2019 - 2024. All rights reserved.