На этом этапе я с легкостью встраиваю элементы в свои контроллеры, в некоторых случаях создавая собственный класс ResolverServices. Жизнь хороша .
Что я не могу понять, так это заставить фреймворк автоматически внедряться в неконтроллерные классы. Что действительно работает, так это то, что фреймворк автоматически вводится в мой контроллер IOptions
, что фактически является конфигурацией для моего проекта:
public class MessageCenterController : Controller
{
private readonly MyOptions _options;
public MessageCenterController(IOptions<MyOptions> options)
{
_options = options.Value;
}
}
Я думаю, смогу ли я сделать то же самое для моих собственных классов. Я предполагаю, что я близок, когда имитирую контроллер, например:
public class MyHelper
{
private readonly ProfileOptions _options;
public MyHelper(IOptions<ProfileOptions> options)
{
_options = options.Value;
}
public bool CheckIt()
{
return _options.SomeBoolValue;
}
}
Я думаю, что ошибаюсь, когда называю это так:
public void DoSomething()
{
var helper = new MyHelper(??????);
if (helper.CheckIt())
{
// Do Something
}
}
Проблема, которую я отслеживаю, - это практически все, что говорит о D, я говорю об этом на уровне контроллера. Я пытался выследить, где это происходит в Controller
исходном коде объекта, но там это становится немного сумасшедшим.
Я знаю, что могу вручную создать экземпляр IOptions и передать его MyHelper
конструктору, но похоже, что я смогу заставить фреймворк сделать это, поскольку он работает для Controllers
.
источник
new
. Никогда для объектов, которые необходимо разрешитьIServiceProvider
в вашу фабрику и вызываяIMyHelper helper = services.RequestService<IMyHelper>()
Ответы:
Ниже приведен рабочий пример использования DI без чего-либо, что связано с контроллерами MVC. Это то, что мне нужно было сделать, чтобы понять процесс, так что, возможно, это поможет кому-то другому.
Объект ShoppingCart получает через DI экземпляр INotifier (который уведомляет покупателя об их заказе).
using Microsoft.Extensions.DependencyInjection; using System; namespace DiSample { // STEP 1: Define an interface. /// <summary> /// Defines how a user is notified. /// </summary> public interface INotifier { void Send(string from, string to, string subject, string body); } // STEP 2: Implement the interface /// <summary> /// Implementation of INotifier that notifies users by email. /// </summary> public class EmailNotifier : INotifier { public void Send(string from, string to, string subject, string body) { // TODO: Connect to something that will send an email. } } // STEP 3: Create a class that requires an implementation of the interface. public class ShoppingCart { INotifier _notifier; public ShoppingCart(INotifier notifier) { _notifier = notifier; } public void PlaceOrder(string customerEmail, string orderInfo) { _notifier.Send("admin@store.com", customerEmail, $"Order Placed", $"Thank you for your order of {orderInfo}"); } } public class Program { // STEP 4: Create console app to setup DI static void Main(string[] args) { // create service collection var serviceCollection = new ServiceCollection(); // ConfigureServices(serviceCollection) serviceCollection.AddTransient<INotifier, EmailNotifier>(); // create service provider var serviceProvider = serviceCollection.BuildServiceProvider(); // This is where DI magic happens: var myCart = ActivatorUtilities.CreateInstance<ShoppingCart>(serviceProvider); myCart.PlaceOrder("customer@home.com", "2 Widgets"); System.Console.Write("Press any key to end."); System.Console.ReadLine(); } } }
источник
ShoppingCart
в другом классе или методе, к которому у нас нет доступа кserviceProvider
объекту?Скажем,
MyHelper
используется,MyService
который, в свою очередь, используется вашим контроллером.Способ разрешения этой ситуации:
Зарегистрируйте оба
MyService
иMyHelper
вStartup.ConfigureServices
.Контроллер получает экземпляр
MyService
в своем конструкторе.public HomeController(MyService service) { ... }
MyService
конструктор, в свою очередь, получит экземплярMyHelper
.public MyService(MyHelper helper) { ... }
Фреймворк DI сможет без проблем разрешить весь граф объектов. Если вас беспокоит создание новых экземпляров каждый раз при разрешении объекта, вы можете прочитать о различных вариантах времени жизни и регистрации, таких как время жизни синглтона или запроса.
Вы должны быть действительно подозрительными, если думаете, что вам нужно вручную создать экземпляр какой-либо службы, поскольку вы можете оказаться в анти-шаблоне локатора служб . Лучше оставить создание объектов в контейнере DI. Если вы действительно оказались в этой ситуации (скажем, вы создаете абстрактную фабрику), вы можете использовать
IServiceProvider
напрямую (либо запроситеIServiceProvider
в своем конструкторе, либо используйте тот, который представлен в httpContext ).var foo = serviceProvider.GetRequiredService<MyHelper>();
Я бы порекомендовал прочитать конкретную документацию о платформе ASP.Net 5 DI и о внедрении зависимостей в целом.
источник
К сожалению, прямого пути нет. Единственный способ заставить его работать - это создать статический класс и использовать его везде, как показано ниже:
public static class SiteUtils { public static string AppName { get; set; } public static string strConnection { get; set; } }
Затем в своем классе запуска заполните его, как показано ниже:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //normal as detauls , removed for space // set my variables all over the site SiteUtils.strConnection = Configuration.GetConnectionString("DefaultConnection"); SiteUtils.AppName = Configuration.GetValue<string>("AppName"); }
Хотя это плохой шаблон, так как он будет оставаться на протяжении всего жизненного цикла приложения, и я не мог найти лучшего способа использовать его вне контроллера.
источник
Вот более полный пример прямого ответа на вопрос OP, основанный на текущей документации .NET Core 2.2 DI здесь . Добавляем этот ответ, поскольку он может помочь кому-то, кто плохо знаком с .NET Core DI, и потому, что этот вопрос является лучшим результатом поиска Google.
Сначала добавьте интерфейс для MyHelper:
public interface IMyHelper { bool CheckIt(); }
Во-вторых, обновите класс MyHelper, чтобы реализовать интерфейс (в Visual Studio нажмите ctrl-., Чтобы реализовать интерфейс):
public class MyHelper : IMyHelper { private readonly ProfileOptions _options; public MyHelper(IOptions<ProfileOptions> options) { _options = options.Value; { public bool CheckIt() { return _options.SomeBoolValue; } }
В-третьих, зарегистрируйте интерфейс как сервис, предоставляемый платформой, в сервисном контейнере DI. Сделайте это, зарегистрировав службу IMyHelper с конкретным типом MyHelper в методе ConfigureServices в Startup.cs.
public void ConfigureServices(IServiceCollection services) { ... services.AddScoped<IMyHelper, MyHelper>(); ... }
В-четвертых, создайте частную переменную для ссылки на экземпляр службы. Передайте службу в качестве аргумента в конструкторе (через внедрение конструктора), затем инициализируйте переменную экземпляром службы. Ссылка на любые свойства или методы вызова этого экземпляра настраиваемого класса через частную переменную.
public class MessageCenterController : Controller { private readonly MyOptions _options; private readonly IMyHelper _myHelper; public MessageCenterController( IOptions<MyOptions> options, IMyHelper myHelper ) { _options = options.value; _myHelper = myHelper; } public void DoSomething() { if (_myHelper.CheckIt()) { // Do Something } } }
источник
Вы можете использовать Activator.CreateInstance (). Вот функция-оболочка для него. Вы используете это следующим образом.
var determinedProgrammatically = "My.NameSpace.DemoClass1"; // implements IDemo interface var obj = CreateInstance<My.NameSpace.IDemo, string>(determinedProgrammatically, "This goes into the parameter of the constructor.", "Omit this parameter if your class lives in the current assembly");
Теперь у вас есть экземпляр obj, который создается программно определенного типа. Этот объект может быть введен в классы неконтроллера.
public TInterface CreateInstance<TInterface, TParameter>(string typeName, TParameter constructorParam, string dllName = null) { var type = dllName == null ? System.Type.GetType(typeName) : System.AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault(a => a.FullName.StartsWith(dllName, System.StringComparison.OrdinalIgnoreCase)).GetType(typeName); return (TInterface)System.Activator.CreateInstance(type, constructorParam); }
PS: Вы можете выполнить итерацию через System.AppDomain.CurrentDomain.GetAssemblies (), чтобы определить имя сборки, в которой находится ваш класс. Это имя используется в третьем параметре функции-оболочки.
источник