Nano Hash - криптовалюты, майнинг, программирование

Ошибка при добавлении-миграции — ссылка на объект не указывает на экземпляр объекта

В этой статье мы попытались реализовать поставщика арендаторов на основе базы данных — https://www.codingame.com/playgrounds/5440/multi-tenant-asp-net-core-2---implementing-database-based-арендатор-поставщик ... и у него есть 2 контекста базы данных ApplicationDbContext и MultiTenantDbContext.

Нам удалось сделать add-migration init and update-database для ApplicationDbContext, НО мы могли НЕ сделать 2-й для MultiTenantDbContext ... и он продолжает говорить о проблеме со ссылкой на объект, не установленной на экземпляр объекта, который связан с `var host = accessor.HttpContext.Request.Host.Value; на /Models/Tenant.cs ниже.

Также мои 2-е вопросы, я не понимаю, почему этот класс DatabaseTenantProvider выполняется в инициализации добавления-миграции в MultiTenantDbContext?!?!

Любые идеи?

Вот код:

/Models/Tenant.cs:

using AthlosifyCore.Data;
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;

namespace AthlosifyCore.Models
{
    public class Tenant
    {
        [Key]
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string HostName { get; set; }
    }

    public interface ITenantProvider
    {
        Guid GetTenantId();
    }

    public class DatabaseTenantProvider : ITenantProvider
    {
        private Guid _tenantId;

        public DatabaseTenantProvider(ApplicationDbContext context, IHttpContextAccessor accessor) 
        {
            var host = accessor.HttpContext.Request.Host.Value;

            context.AddSampleData();

            // This is for real life cases
            //_tenantId = context.Tenants.First(t => t.HostName == host).Id;

            _tenantId = context.Tenants.First(t => t.HostName == "imaginary.example.com").Id;
        }

        public Guid GetTenantId()
        {
            return _tenantId;
        }
    }
}

/Data/ApplicationDbContext.cs:

using System;
using System.Collections.Generic;
using System.Text;
using AthlosifyCore.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

namespace AthlosifyCore.Data
{
    public class ApplicationDbContext : IdentityDbContext
    {
        private readonly IHttpContextAccessor _httpContextAccessor;

        public DbSet<Tenant> Tenants { get; set; }
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options,
                                    IHttpContextAccessor httpContextAccessor)
            : base(options)
        {
            _httpContextAccessor = httpContextAccessor;
        }
        public void AddSampleData()
        {
            Tenants.Add(new Tenant
            {
                Id = MultitenantDbContext.Tenant1Id,
                Name = "Imaginary corp.",
                HostName = "imaginary.example.com"
            });

            Tenants.Add(new Tenant
            {
                Id = MultitenantDbContext.Tenant2Id,
                Name = "The Very Big corp.",
                HostName = "big.example.com"
            });

            SaveChanges();
        }
    }
}

/Data/MultitenantDbContext.cs:

using AthlosifyCore.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace AthlosifyCore.Data
{
    public class MultitenantDbContext : DbContext
    {
        public static Guid Tenant1Id = Guid.Parse("51aab199-1482-4f0d-8ff1-5ca0e7bc525a");
        public static Guid Tenant2Id = Guid.Parse("ae4e21fa-57cb-4733-b971-fdd14c4c667e");

        public DbSet<Person> People { get; set; }

        private ITenantProvider _tenantProvider;

        public MultitenantDbContext(DbContextOptions<MultitenantDbContext> options,
                                ITenantProvider tenantProvider) : base(options)
        {
            _tenantProvider = tenantProvider;
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Entity<Person>().HasQueryFilter(p => p.TenantId == _tenantProvider.GetTenantId());
        }

        public void AddSampleData()
        {
            People.Add(new Person
            {
                Id = Guid.Parse("79865406-e01b-422f-bd09-92e116a0664a"),
                TenantId = Tenant1Id,
                FirstName = "Gunnar",
                LastName = "Peipman"
            });

            People.Add(new Person
            {
                Id = Guid.Parse("d5674750-7f6b-43b9-b91b-d27b7ac13572"),
                TenantId = Tenant2Id,
                FirstName = "John",
                LastName = "Doe"
            });

            People.Add(new Person
            {
                Id = Guid.Parse("e41446f9-c779-4ff6-b3e5-752a3dad97bb"),
                TenantId = Tenant1Id,
                FirstName = "Mary",
                LastName = "Jones"
            });

            SaveChanges();
        }
    }
}

Ответы:


1

мы НЕ могли сделать 2-й для MultiTenantDbContext ... и он продолжает говорить о проблеме со ссылкой на объект, не установленной на экземпляр объекта, который связан с `var host = accessor.HttpContext.Request.Host.Value; на /Models/Tenant.cs ниже.

Это потому, что когда вы запускаете dotnet-tool add-migration init, HttpContext вообще нет. Другими словами, accessor.HttpContext в это время имеет значение null, а затем происходит сбой, когда вы обращаетесь к свойству Request null.

Чтобы исправить эту ошибку, измените код, как показано ниже:

    public DatabaseTenantProvider(TenantsDbContext context, IHttpContextAccessor accessor)
    {
        var host = accessor.HttpContext?.Request.Host.Value;

        // ....
    }

Кроме того, чтобы избежать многократного добавления образцов и возникновения ошибки:

 Cannot insert duplicate key in object 'dbo.Tenants'. The duplicate key value is (51aab199-1482-4f0d-8ff1-5ca0e7bc525a).

Мы должны изменить метод AddSampleData() класса TenantsDbContext:

public class TenantsDbContext : DbContext
{
    // ....
    public void AddSampleData()
    {
        // add samples only if there's no record.
        if(Tenants.Count()==0){
            Tenants.Add(new Tenant
            {
                Id = MultitenantDbContext.Tenant1Id,
                Name = "Imaginary corp.",
                HostName = "imaginary.example.com"
            });
            Tenants.Add(new Tenant
            {
                Id = MultitenantDbContext.Tenant2Id,
                Name = "The Very Big corp.",
                HostName = "big.example.com"
            });
            SaveChanges();
        }
    }
}

Также мои 2-е вопросы, я не понимаю, почему этот класс DatabaseTenantProvider выполняется в инициализации добавления-миграции в MultiTenantDbContext?!?!

Это потому, что DatabaseTenantProvider зарегистрирован как реализация службы ITenantProvider,

services.AddTransient<ITenantProvider, DatabaseTenantProvider>()

который требуется классу MultitenantDbContext:

public class MultitenantDbContext : DbContext
{
    //...

    // note we inject the `ITenantProvider` service here!
    public MultitenantDbContext(DbContextOptions<MultitenantDbContext> options,
                                ITenantProvider tenantProvider) : base(options)
    {
        _tenantProvider = tenantProvider;
    }

}

Когда EF Core вызывает методы MultitenantDbContext.OnModelCreating(), он вызывает службу ITenantProvider (т. е. класс DatabaseTenantProvider) для получения идентификатора.

12.02.2019
Новые материалы

Кластеризация: более глубокий взгляд
Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

Как написать эффективное резюме
Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

Частный метод Python: улучшение инкапсуляции и безопасности
Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

Как я автоматизирую тестирование с помощью Jest
Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..