Sleva na školení Naučit se HTML & CSS, JS a Bootstrap
Získej 500 Kč na naše školení. Více zde
Probíhá výprodej HTML & CSS, JavaScript a Bootstrap

Diskuze: Vrácení instance

Aktivity (4)
Avatar
Luboš Hnědý:29. března 20:50

Zdravím, přecházím z .net frameworku MVC na .net Core MVC a mám jeden problém. V .net frameworku používám následující zápis: DependencyResol­ver.Current.Get­Service<TServi­ce>(); tohle mi vrátí instanci a nemusím si to přendavat přes konstruktor, což občas potřebuju. Je tohle možné v .net core? Vím, že v controlleru ano, ale já to potřebuji úplně mimo tzn. že nemám přístup k IServiceProvider. Předem díky za rady :)

Zkusil jsem: Hledat na googlu ale nic moc jsem nenašel

Chci docílit: Dobré funkčnosti

 
Odpovědět 29. března 20:50
Avatar
Ilja Židkov
Člen
Avatar
Odpovídá na Luboš Hnědý
Ilja Židkov:30. března 16:16

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();
    }
}
Editováno 30. března 16:17
 
Nahoru Odpovědět 30. března 16:16
Avatar
Odpovídá na Ilja Židkov
Luboš Hnědý:30. března 17:45

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());
 
Nahoru Odpovědět 30. března 17:45
Avatar
Ilja Židkov
Člen
Avatar
Ilja Židkov:30. března 19:16

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:

Služby a DI v ASP .NET Core

K tomu co jsi napsal. Pokud to funguje - super, ale framework to nedoporučuje.

 
Nahoru Odpovědět 30. března 19:16
Avatar
Odpovídá na Ilja Židkov
Luboš Hnědý:30. března 19:46

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

Editováno 30. března 19:46
 
Nahoru Odpovědět 30. března 19:46
Avatar
Ilja Židkov
Člen
Avatar
Odpovídá na Luboš Hnědý
Ilja Židkov:30. března 21:59

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();
    }
}
 
Nahoru Odpovědět 30. března 21:59
Avatar
Odpovídá na Ilja Židkov
Luboš Hnědý:31. března 0:50

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í

 
Nahoru Odpovědět 31. března 0:50
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na Luboš Hnědý
Martin Petrovaj:31. března 9:27

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 ITransientSer­vice1,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 "ITransientSer­vice1,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ť.

Nahoru Odpovědět 31. března 9:27
if (this.motto == "") { throw new NotImplementedException(); }
Avatar
vosa53
Člen
Avatar
vosa53:31. března 12:56

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.

 
Nahoru Odpovědět 31. března 12:56
Avatar
Odpovídá na Martin Petrovaj
Luboš Hnědý:1. dubna 9:12

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?

 
Nahoru Odpovědět 1. dubna 9:12
Avatar
Martin Petrovaj
Překladatel
Avatar
Odpovídá na Luboš Hnědý
Martin Petrovaj:1. dubna 9:33

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.

Akceptované řešení
+20 Zkušeností
+1 bodů
Řešení problému
Nahoru Odpovědět 1. dubna 9:33
if (this.motto == "") { throw new NotImplementedException(); }
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 11 zpráv z 11.