Diskuze: Vrácení instance
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 11 zpráv z 11.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Test znalostí C# .NET online, jsme si ověřili nabyté zkušenosti z kurzu.
Ano, to lze. I když to není nejlepší praxe:
public class HomeController : Controller
{
public HomeController() { }
public IActionResult Index()
{
var services = HttpContext.RequestServices;
var log = (ILog)services.GetService(typeof(ILog));
log.info("Hello, World!");
return View();
}
}
A co je na tom prosím špatného? Mě se líbí, že né vždycky to například potřebuji v celé třídě, ale pouze v jedné metodě. Já našel tohle, je to ok?
private static ServiceProvider _serviceProvider;
public static void SetLocatorProvider(ServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public static TService GetInstance<TService>()
{
return _serviceProvider.GetService<TService>();
}
Ve startup
ServiceLocator.SetLocatorProvider(services.BuildServiceProvider());
A co je na tom prosím špatného?
Neřekl jsem, že je to špatné. Jen to není nejlepší praxe. Samotný framework tě přímo "nutí" používat IServiceCollection za účelem vnoření závislostí (princip dependency injection container).
Přeci jen na rozdíl od typického MVC, Core už neobsahuje Global ASAX, který sloužil pro účely globální konfigurace (filtry, routování, správa svazků apod.).
Výchozí IoC kontejner umožňuje tzv. "Service Lifetime", čili životnost služeb.
tohle mi vrátí instanci a nemusím si to přendavat přes konstruktor, což občas potřebuju.
Pokud máš jednoduchou službu, která dělá jednu jedinou věc. Lze ji zaregistrovat jako tzv. Transient (přechodnou).
services.AddTransient<ISlužba, Implementace>();
věnoval jsem tomu celé 2 články:
K tomu co jsi napsal. Pokud to funguje - super, ale framework to nedoporučuje.
Děkuju za odpověď. Já furt ale nechápu v čem je ten hlavní problém :/ Mohl by si mi to prosím tě ještě zkusit vysvětlil. Byl bych moc rád. Samozřejmě o Transient vím.Jde mi třeba o problém, kdy mám class a vní tři metody Metoda1(), Metoda2() a Metoda3() v každé mětodě potřebuji použí dvě jiné service. Když to dám do konstruktoru, tak se mi nainitializují vždy všechny ato nechci. přeem díky
Můžeš sdílet nějaký pseudo kód nebo alespoň jak si představuješ, aby tvoje implementace vypadala? Jinak nevím, jak mám odpovědět. Jednoduše bych vnořil do konstruktoru dvě Transient služby a následně v každé z metod využil.
Např. takhle:
public HomeController: Controller
{
private readonly ITransientService1 transientService1;
private readonly ITransientService2 transientService2;
public HomeController(ITransientService1 transientService1, ITransientService1 transientService2)
{
this.transientService1 = transientService1;
this.transientService2 = transientService2;
}
public IActionResult Metoda1()
{
transientService1.DoSomething();
transientService2.DoSomething();
}
}
Jde mi o to, že mi vadí pssát něco jako tohle
public HomeController: Controller
{
private readonly ITransientService1 transientService1;
private readonly ITransientService2 transientService2;
private readonly ITransientService3 transientService3;
private readonly ITransientService4 transientService4;
private readonly ITransientService5 transientService5;
private readonly ITransientService6 transientService6;
public HomeController(ITransientService1 transientService1, ITransientService2 transientService2,
ITransientService3 transientService3, ITransientService4 transientService4, ITransientService5 transientService5, ITransientService6 transientService6)
{
this.transientService1 = transientService1;
this.transientService2 = transientService2;
this.transientService3 = transientService3;
this.transientService4 = transientService4;
this.transientService5 = transientService5;
this.transientService6 = transientService6;
}
public IActionResult Metoda1()
{
transientService1.DoSomething();
transientService2.DoSomething();
}
public IActionResult Metoda2()
{
transientService3.DoSomething();
transientService4.DoSomething();
}
public IActionResult Metoda3()
{
transientService5.DoSomething();
}
public IActionResult Metoda4()
{
transientService6.DoSomething();
}
}
Prostě mi to přijde zvláštní A navíc ještě používám partial controllery, takže to musím
dělat na jendom místě... já nevím připadá mi to zvláštní
Nejakú dobu som sa k ASP.NET Core už nedostal, ale toto by snáď malo v Controlleri fungovať.
var service = HttpContext.RequestServices.GetService<T>();
K tvojmu poslednému príspevku - máš pravdu, je to zvláštne, ale
riešenie hľadáš na zlom mieste
Keď ti na hlavičku konštruktora nestačia ani dva monitory a polovicu obrazovky ti zaberajú deklarácie tvojich závislostí (private ITransientService1,2,3,…), tak riešenie v 99% prípadov nie je v skrývaní týchto závislostí (odstránim ich z konštruktora aj z triedy, aby ich nikto pri čítaní kódu jednoducho nenašiel, a radšej si ich sprisahaneckým šepotom vypýtam od dílera v tmavej uličke). Osobne mi takáto situácia smrdí porušením Single Responsibility Principle (SRP - https://www.itnetwork.cz/…lid-a-stupid).
Je možné, že väčší zmysel by dávalo niekoľko oddelených, menších controllerov, než jeden veľký, ktorý robí všetko (a potom takto "zvláštne" vyzerá). Možno potrebuješ niekoľko z tých "ITransientService1,2,3,…" s podobnou funkcionalitou združiť do jedného objektu, ktorý ti poskytne menšie a vhodnejšie rozhranie. Skús sa trochu zamyslieť nad kódom z trochu "vyššej" perspektívy, možno sa ti podarí to zjednodušiť.
Pokud třeba jen jedna akce využívá nějakou službu, tak v akcích controlleru můžeš použít atribut [FromServices].
public IActionResult SomeAction([FromServices] ISomeService someService)
{
someService.DoSomething();
}
Ale jak už bylo zmíněno, vypadá to, že problém bude nejspíš jinde.
Ok zapouzdřit to samozřejmě můžu. Ale jde mi třeba o to když chci použít servicu v statické třídě, jak to mám udělat?
Nie som si istý, či má ASP.NET Core na takéto situácie už niečo pripravené (snáď ma niekto opraví ak áno). Najpriamočiarejšie riešenie, ktoré mi z hlavy napadne, je spraviť v statickej triede verejnú property a nastaviť ju v Startup.cs v ConfigureServices:
public static class YourClass
{
public static IYourService Service { get; set; }
}
// Startup.cs > ConfigureServices
YourClass.Service = services.BuildServiceProvider().GetService<IYourService>();
Tento postup je možné použiť, ak potrebuješ s nejakou službou často pracovať a chceš si uchovať jej inštanciu.
Stále to ale píšem s veľkým sebazapretím a dal by som si pozor na to, aby fungovalo správne s tvojimi Transient alebo Scoped závislosťami.
Prikláňam sa k tomu, že statike by si sa vo väčšine prípadov mal vyhnúť (okrem extension metód), a keď už je raz niečo static, tak to nemá čo mať nejaký vnútorný stav (čiže držať nejaké dáta, premenné). Ak môžeš, pošli si potrebné veci v argumentoch svojich metód. Ak to bude stále vyzerať divne (napr. budeš mať často 3 a viac argumentov), pravdepodobne sa pozeráš na triedu, ktorá nechce byť static.
Zobrazeno 11 zpráv z 11.