#c# #autofac #dbcontext #topshelf
#c# #autofac #dbcontext #верхняя полка
Вопрос:
Я создаю службу, которая, к сожалению, должна ссылаться на устаревшие библиотеки DLL для нашей ERP-системы.NET framework — это то, как мне нужно это сделать. Я пытался использовать службу Core Worker, но мои вызовы библиотек DLL не будут работать.
Мне нравится использовать TopShelf, и я искал DI для использования с этим, и Autofac, похоже, подходит, и у него есть поддержка TopShelf. Мне не нравится сохранять какие-либо настройки в наших файлах конфигурации, чтобы упростить развертывание в других средах. У нас есть целая система, которая сохраняет настройки, привязанные к среде, в которой вы находитесь (dev, test, prod и т. Д.). В основных приложениях я просто вводлю строку подключения при запуске, и все хорошо. В этом приложении я хочу вводить строку подключения при запуске службы и иметь возможность в любое время запускать класс DbContect и использовать эту строку подключения.
Поскольку я создаю свой слой данных и не хочу изменять сгенерированный DbContext, поэтому я создал другой частичный класс (MyContext.Custom.cs) с конструктором, который позволяет мне передавать строку подключения
public MyContext(string name) : base(name)
{ }
В моем Program.cs я добавляю в контейнер Autofac на верхнюю полку
HostFactory.Run(serviceConfig =>
{
serviceConfig.UseAutofacContainer(container);
// etc...
}
Контейнер создается в функции, я пытался следовать многим примерам, но, похоже, я не могу заставить свой конструктор с параметром быть тем, который используется. Вот несколько способов, которые я пробовал. Каждый метод не выдает ошибок, но он запускает мой конструктор по умолчанию, где он ищет именованную строку подключения в файле конфигурации.
static IContainer BuildContainer()
{
string myConnectionString = AppConfig.Instance.Settings["MyConnectionString"];
var builder = new ContainerBuilder();
//builder.RegisterType<MyContext>()
// .UsingConstructor(typeof(string))
// .WithParameter("name", myConnectionString)
// .InstancePerLifetimeScope();
//builder.Register(c => new MyContext(myConnectionString)).As<MyContext>();
//.WithParameter("name", myConnectionString);
//builder.RegisterType<MyContext>()
// .WithParameter("name", myConnectionString)
// .AsSelf();
//.InstancePerLifetimeScope();
builder.Register(c => new MyContext(myConnectionString)).AsSelf();
builder.RegisterType<MainService>();
return builder.Build();
}
Я пробовал каждый вариант с.Как и .AsSelf(). Я вставил .InstancePerLifetimeScope() и также пропустил его. Я не совсем уверен, на что устанавливать область видимости в этом случае, но решил, что это должно работать со временем жизни. Что бы я ни пробовал, я, похоже, не могу заставить его использовать мой конструктор.
Если я пропустил какую-либо информацию, не стесняйтесь спрашивать, и я могу ее заполнить. Надеюсь, кто-то это сделал. Я думаю, я мог бы передавать строку подключения каждый раз, когда я создаю экземпляр DbContext, но я надеялся заставить его работать как основное приложение, которое намного приятнее.
Спасибо
РЕДАКТИРОВАТЬ: добавление кода, чтобы показать, как я использую свой DbContext
public bool Start()
{
using(var db = new MyContext())
{
var warehouse = (from w in db.Warehouses
where w.WarehouseCode == "ABCD"
select w).FirstOrDefault();
}
// other code...
}
Комментарии:
1. Не могли бы вы показать нам пример класса (например
MainService
), который зависит от DbContext? Тогда, возможно, мы сможем помочь определить проблему..2. Я добавил этот код выше в функцию запуска моего MainService, поскольку обычное место, в которое я попадаю, моя база данных находится в другом проекте и имеет много уровней, чтобы добраться до нее. Я получаю ту же ошибку, что и при невозможности найти имя строки подключения в конфигурации. Также используется конструктор по умолчанию, а не мой пользовательский конструктор. Надеюсь, это поможет.
3. тьфу, думаю, я передаю свою строку подключения по цепочке, чувствую себя таким грязным.