Я пытаюсь использовать это DbContext в методе POST для добавления записи.
Конструктор контроллера с этим методом выглядит следующим образом:
public CookieController(ILogger<CookieController> logger, ICookieRepository cookieRepository)
{
_logger = logger;
_cookieRepository = cookieRepository;
}
Вот метод:
[HttpPost(Name = "")]
public IEnumerable<Cookie> PostCookie([FromBody] Cookie data)
{
DbContextOptions<ReactWithASPDbContext> options = new DbContextOptions<ReactWithASPDbContext>();
ReactWithASPDbContext dbContext = new ReactWithASPDbContext(options);
// ...
}
Класс DbContext выглядит так:
public class ReactWithASPDbContext : DbContext
{
public ReactWithASPDbContext(DbContextOptions<ReactWithASPDbContext> options):
base(options)
{
}
// ...
}
Это код Program.cs:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddDbContext<ReactWithASPDbContext>(options => {
options.UseSqlServer(
builder.Configuration["ConnectionStrings:ReactWithASPDbContextConnection"]); });
var app = builder.Build();
DbInitializer.Seed(app);
Это метод DbInitializer, и он работает:
public static void Seed(IApplicationBuilder applicationBuilder)
{
ReactWithASPDbContext context =
applicationBuilder.ApplicationServices
.CreateScope()
.ServiceProvider
.GetRequiredService<ReactWithASPDbContext>();
// ...
}
appsettings.json имеет следующее содержание:
"ConnectionStrings": {
"ReactWithASPDbContextConnection": "Server=
(localdb)\mssqllocaldb;Database=ReactWithASP;Trusted_Connection=True;MultipleActiveResultSets=True" }
Но конфигурация генерирует эту ошибку:
Для этого DbContext не настроен ни один поставщик базы данных. Поставщика можно настроить, переопределив метод DbContext.OnConfiguring или используя AddDbContext в поставщике службы приложения. Если используется «AddDbContext», также убедитесь, что ваш тип DbContext принимает объект DbContextOptions в своем конструкторе и передает его базовому конструктору для DbContext.
Я предполагаю, что мне не нужно воссоздавать материал инициализации в файле Program.cs, который создает IApplicationBuilder и т. д. Должен быть способ передать контекст после его создания, верно?
Почему ваш инициализатор БД «работает», если вы еще нигде не настроили, какую строку подключения должен использовать контекст? Вы хотите сказать, что Seed правильно заполняет нужную БД данными?
Да, метод семян работает.
Я вижу, вы только что опубликовали фрагмент кода, который раньше выглядел отсутствующим... Опубликуйте конструктор вашего контроллера (класс, содержащий метод PostCookie)
Просто добавил конструктор
Хорошо, есть ли у ICookieRepository конструктор, который имеет этот контекст в качестве параметра? Или, может быть, у контроллера есть свойство, которое представляет собой контекст БД, украшенный атрибутом внедрения? (Похоже, вы выполнили необходимые настройки для DI, чтобы создать для вас контекст, подключенный к БД, но я еще не видел, где вы вводите его в контроллер с помощью DI)
Класс CookieRepository имеет такой конструктор: public CookieRepository(ReactWithASPDbContext actWithASPDbContext) { _reactWithASPDbContext = actWithASPDbContext; }
Итак, в вашем методе PostCookie вы не будете создавать экземпляр контекста, вы будете вызывать методы в репозитории cookie, а репозиторий cookie будет использовать внедренный контекст для выполнения работы с БД. Не выполняйте работу с БД в контроллере, если у вас есть репозиторий, который выполняет работу с БД, к которой контроллер должен обращаться (и если у вас есть уровень обслуживания, не выполняйте работу с репозиторием в контроллере)





Это говорит вам, что вы не добавили что-то подобное
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
как в
public class SomeContext: DbContext
{
private readonly string _connectionString;
public SomeContext(string connString) : base()
{
_connectionString= connString;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer(_connectionString);
}
// Add DB sets here
}
И connString — это имя этой переменной в appsettings.json, верно? Разве это не должно быть инициализировано? И это вместо текущего конструктора? Или в дополнение к этому?
Извлеките эти данные из конфигурации при запуске, где вы настраиваете свой DI и остальные службы, и вызовите AddDbContext. Используйте DI, чтобы передать экземпляр контекста конструктору вашего контроллера или введенным реквизитам и использовать его. Не сохраняйте контекст в течение длительного времени (не делайте ничего, что приведет к тому, что он станет одноэлементным).
Извините, но не могли бы вы показать мне пример? Это единственный способ, которым я видел это в примере, который я использовал.
@John Джон Как хранить строку подключения, решать вам. Если хранить в appsettings - отлично. Сохраняем в секретном менеджере. И еще по поводу ДИ. Есть еще один ответ, показывающий, как это сделать с помощью DI. Это один из способов. Есть другой способ, где вы вместо .Services.AddDbContext используете обычный .AddTransient и можете добавить фабрику контекста БД. Затем в вашем контроллере вы можете вызвать контекст, например using (var ctx = CtxFactory.Create()) { // do something } . Я использую фабричный стиль, потому что он помогает поддерживать несколько механизмов БД с помощью одной базы кода.
вам нужно настроить DbContext в Program.cs
// You already have this
var builder = WebApplication.CreateBuilder(args);
// But you are missing this
builder.Services.AddDbContext<ReactWithASPDbContext>(
options => options.UseSqlServer("name=ConnectionStrings:ReactWithASPDbContextConnection"));
Как только это будет сделано, вам нужно будет ввести ReactWithASPDbContext в свой контроллер, а не создавать его вручную.
public CookieController(ILogger<CookieController> logger,
ICookieRepository cookieRepository, ReactWithASPDbContext context)
{
_logger = logger;
_cookieRepository = cookieRepository;
_context = context;
}
[HttpPost(Name = "")]
public IEnumerable<Cookie> PostCookie([FromBody] Cookie data)
{
_context.DoSomething()
...
}
Это здесь. Я добавил это в пример.
@Джон обновлен на основе ваших последних изменений.
Нет, это смешивание слоев. Если у OP есть уровень репо, а у репо есть контекст, вы также не будете использовать контексты из контроллера. Это создает беспорядок. Если кто-то писал методы расширения для контекстов и признавал, что контекст представляет собой реализацию шаблона репо (разумно), тогда (при отсутствии уровня обслуживания) обязательно иметь контекст в контроллере, но не иметь обоих репозиториев, которые имеют контексты и также тогда есть контексты в контроллерах
Я понимаю, что вы говорите, но описанный выше подход работает. Но не очень ремонтопригодно я так понимаю?
Я так понимаю, вы имеете в виду, что функция добавления должна быть в классе Repo?
Вопрос, который я пытаюсь решить, заключается в том, как заставить dbcontext работать. После этого обязательно посмотрите на различные шаблоны (например, репозиторий), которые помогут организовать код, но это выходит далеко за рамки первоначального запроса.
Хорошо, я реализовал это с помощью репо, и это работает. Спасибо!!
как заставить dbcontext работать - он уже работает ;) для работы просто нужно использовать то место, где он настроен, а не внедрять/создавать повсюду :D Но я так понимаю, это не очень удобно в обслуживании? - через пару лет вы оглянетесь назад и удивитесь тому, как изменился ваш инженерный подход. Это хорошая вещь
вы имеете в виду, что функция добавления должна быть в репо - да. Репозиторий отвечает за представление базового хранилища данных как единообразного интерфейса. Однажды вы можете решить перейти на хранение данных в текстовом файле или использовать интерфейс API, как если бы это была БД. Вместо этого вы переконфигурируете свое репо, чтобы сохранить его в текстовом файле. Add продолжал работать, но записывал в текстовый файл или сохранял в раскрывающемся списке и т. д., все продолжало его вызывать, несмотря на то, что данные передаются в другое место. Вы можете реализовать в своем репозитории интерфейс IBlahRepo, требующий добавления. Вы можете написать поддельный репо..
...для целей тестирования он просто хранит данные в памяти, красиво и быстро, их легко уничтожить. Он ведет себя так же, как ваш настоящий репо. Вы можете писать для него тесты, вызывать их и доказывать, что код, основанный на Add, будет работать, не разрушая при этом вашу БД. Вот почему мы создаем отдельные уровни с единообразными интерфейсами; чтобы мы могли заменить их на что-то другое, не нарушая остальную часть установки.
На самом деле, в этой заметке по тестированию я рекомендую вам использовать что-то близкое к репозиторию, который использует реальный контекст, но, возможно, выполняет откат в конце каждого теста. Это означает, что вы можете тестировать свои операции на реальной базе данных со всеми отклонениями, которые она вносит, но она надежно отменяет свою работу после того, как доказывает свою точку зрения, а это означает, что ваши идеально подобранные тестовые данные не пострадают и готовы к следующему тесту.
Эрк, большинство людей не так информируют свой контроллер о контексте базы данных, который будет использоваться в их методе PostXxx.