簡體   English   中英

ASP.NET 核心 (3.1) 與 EF 核心遷移和 IHttpContextAccessor

[英]ASP.NET Core (3.1) with EF Core Migrations and IHttpContextAccessor

我正在嘗試為我的 asp.net 核心 api 項目添加 ef 核心遷移。 不幸的是,遷移必須處理添加遷移的一些麻煩,因為我將 IHttpContextAccessor 注入到我的一個提供者中:/

我正在調用services.AddHttpContextAccessor(); services.AddDbContext<SCContext>(builder => builder.UseSqlServer(connectionstring)); 在我的startup.cs中。

如果我正在運行 > dotnet run並執行一些請求,一切正常。 但是,如果我嘗試運行>dotnet ef migrations add InitialCreate ,則會顯示以下日志(兩個命令都在 api 項目目錄路徑中執行):

Build started...
Build succeeded.
System.NullReferenceException: Object reference not set to an instance of an object.
   at SocietyCloud.Services.Provider.CredentialsProvider..ctor(IHttpContextAccessor httpContextAccessor) in E:\Bibliotheken\Projects\societycloud\Application\SocietyCloud.Services\Provider\CredentialsProvider.cs:line 15
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite singletonCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.DynamicServiceProviderEngine.<>c__DisplayClass1_0.<RealizeService>b__0(ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngine.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetServiceOrCreateInstance(IServiceProvider provider, Type type)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.<>c__DisplayClass13_2.<FindContextTypes>b__11()
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(Func`1 factory)
   at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.CreateContext(String contextType)
   at Microsoft.EntityFrameworkCore.Design.Internal.MigrationsOperations.AddMigration(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigrationImpl(String name, String outputDir, String contextType)
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.AddMigration.<>c__DisplayClass0_0.<.ctor>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
Object reference not set to an instance of an object.

有沒有人遇到同樣的問題?

啟動.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options =>
    {
        options.AddDefaultPolicy(builder =>
            builder.SetIsOriginAllowed(_ => true)
            .AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader());
    });
    services.AddControllers();
    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("v1", new OpenApiInfo { Title = "TEST", Version = "v1" });
    });
    AutoMapperConfig.Configure(services);
    OptionsConfig.Configure(services, Configuration);
    AuthenticationConfig.Configure(services, Configuration);
    DependencyConfig.Configure(services, Configuration);
}

依賴配置.cs

public static void Configure(IServiceCollection services, IConfiguration configuration)
{
    // Register provider
    services.AddHttpContextAccessor();
    var openibanurl = configuration[$"{nameof(ExternalApisOptions)}:{nameof(ExternalApisOptions.OpenIbanUrl)}"];
    services.AddHttpClient<IOpenIbanProvider, OpenIbanProvider>(configure => configure.BaseAddress = new Uri(openibanurl));

    // Register DBContext
    var connectionstring = configuration[$"{nameof(AzureOptions)}:{nameof(AzureOptions.SqlConnectionstring)}"];
    services.AddDbContext<SCContext>(builder => builder.UseSqlServer(connectionstring));

    // Register services
    foreach (var (Contract, Implementation) in typeof(MembershipsService).Assembly.GetTypesWithImplementations<IService>())
        services.AddScoped(Contract, Implementation);

    // Register validator
    services.AddScoped<IViewModelValidator<VMAddMembership>, VMAddMembershipValidator>();
}

CredentialsProvider.cs

public class CredentialsProvider : ICredentialsProvider
{
    public Guid? AccountId { get; private set; }
    public Guid? SocietyId { get; private set; }

    public CredentialsProvider(IHttpContextAccessor httpContextAccessor)
    {
        if (httpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
        {
            AccountId = GetGuid(httpContextAccessor.HttpContext, SCClaims.AccountId);
            SocietyId = GetGuid(httpContextAccessor.HttpContext, SCClaims.SocietyId);
        }
    }

    private Guid? GetGuid(HttpContext context, SCClaims claim)
    {
        if (Guid.TryParse(context.User.Claims?.FirstOrDefault(x => x.Type == Enum.GetName(typeof(SCClaims), claim))?.Value, out var societyid))
            return societyid;
        return null;
    }
}

CredentialsProvider的構造函數中訪問HttpContext將失敗,因為在可以填充上下文及其成員之前,您將在生命周期中過早訪問它

public class CredentialsProvider : ICredentialsProvider {
    private readonly IHttpContextAccessor httpContextAccessor;

    public CredentialsProvider(IHttpContextAccessor httpContextAccessor) {
        this.httpContextAccessor = httpContextAccessor;
    }

    public Guid? AccountId =>  GetGuid(SCClaims.AccountId);
    public Guid? SocietyId =>  GetGuid(SCClaims.SocietyId);

    private Guid? GetGuid(SCClaims claim) {
        if (Guid.TryParse(httpContextAccessor.HttpContext.User?.Claims?
                .FirstOrDefault(x => x.Type == Enum.GetName(typeof(SCClaims), claim))?.Value,
             out var societyid)
        )
            return societyid;
        return null;
    }
}

盡量避免在構造函數中做太多的邏輯。 它們主要用於分配初始值。

確保以正確的順序注冊它。 就像是:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    services.AddHttpContextAccessor();
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM