AMcoder - javascript, python, java, html, php, sql

Փոխեք կախվածության լուծաչափը միայն կոնկրետ շրջանակի համար

Ես ունեմ մեկ կախվածություն, որը գրանցված է հետևյալ կերպ.

interface IDependency { }

class DependencyImpl : IDependency { }

Գործարկում.

services.AddScoped<IDependency, DependencyImpl>();

Սա աշխատում է այնպես, ինչպես նախատեսված է, քանի որ ես ուզում եմ նորից օգտագործել նույն օրինակը իմ Web API հարցումների շրջանակում:

Այնուամենայնիվ, մեկ ֆոնային ծառայության մեջ ես կցանկանայի ասել, թե որ օրինակն այն կլուծի.

class MyBackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory; // set in ctor

    public void DoStuff()
    {
        var itens = GetItens();

        var dependencyInstance = new DependencyImpl();

        Parallel.ForEach(itens, (item) =>
        {
             using(var scope = _scopeFactory.CreateScope())
             {
                 scope.SwapDependencyForThisScopeOnly<IDependency>( () => dependencyInstance ); // something like this

                 var someOtherService = scope.ServiceProvider.GetRequiredService<ItemService(); // resolve subsequent services with provided dependencyInstance
                 someOtherService.Process(item);
             }
        });
    }

}

Ես չեմ կարող կրկին օգտագործել նույն Scope-ը, քանի որ ItemService-ը (և/կամ դա կախվածություն է) օգտագործում է շրջանակի այլ ծառայություններ, որոնք հնարավոր չէ համօգտագործել: Ես չեմ ուզում փոխարինել կախվածության լուծումը ամբողջ հավելվածի համար:

Հնարավո՞ր է այստեղ անել այն, ինչ ուզում եմ: Արդյո՞ք դա իմաստ ունի:

Ես օգտագործում եմ dotnet core 2.2 լռելյայն IoC կոնտեյներով այդ հարցերի համար:

Խմբագրել ի պատասխան @Steven. DependencyImpl-ը պարունակում է կոնֆիգուրացիաներ, թե ինչպես է մշակվելու տարրը: Դրանցից մեկը ներառում է համեմատաբար թանկ հարցում: DependencyImpl-ը նույնպես ներարկվում է գրաֆիկում մեկից ավելի անգամ: Այսպիսով, ներկայումս այն կարդում է կոնֆիգուրացիան մեկ անգամ, պահում է դրանք մասնավոր հատկություններում և օգտագործում է քեշավորված տարբերակը հետագա ընթերցումների ժամանակ: Քանի որ ես գիտեմ, որ վերօգտագործելու եմ նույն կոնֆիգուրացիան այստեղ բոլոր տարրերի համար, ես կցանկանայի խուսափել կազմաձևումը կրկին կարդալուց յուրաքանչյուր զուգահեռ կատարման համար:

Իմ իրական աշխարհի կախվածությունն ավելի նման է հետևյալին.

interface IDependency 
{ 
    Task<Configuration> GetConfigurationAsync();
}

class DependencyImpl : IDependency 
{ 
    private readonly Configuration _configuration;
    private readonly DbContext _dbContext;

    ctor(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public async  Task<Configuration> GetConfigurationAsync()
    {
         if(_configuration is null)
         {
              // read configurations
         }

         return _configuration;
    }
}

Ես հասկանում եմ, որ, ինչպես որ կա, իմ դասը թելերի համար անվտանգ չէ: Ես ստիպված կլինեի կարդալ սկզբում և/կամ ավելացնել թելի անվտանգությունը այստեղ:

Բացի այդ, այդ մշակումները նախկինում տեղի էին ունենում վեբ հարցման ողջ ընթացքում, և ֆոնային ծառայությունը նոր նյութ է: Ես կնախընտրեի հնարավորինս քիչ փոխել գոյություն ունեցող ծածկագիրը, քանի որ կան քիչ թեստեր և, իհարկե, ժամանակի սահմանափակումներ, որոնք կարող են լինել:


  • Կարո՞ղ եք մանրամասնել, թե ինչու է անհրաժեշտ կախվածությունը ստեղծել օղակից դուրս և ներարկել այն մեկ այլ թեմայի գրաֆիկի մեջ: Ի՞նչ տվյալներ ունի DependencyImpl-ը, որոնք պետք է համօգտագործվեն շղթաներով: 16.10.2019
  • @Steven-ը խմբագրեց իմ հարցը 16.10.2019

Պատասխանները:


1

Ընդհանրապես, հավելվածի գործարկման ընթացքում գրանցված օբյեկտների գրաֆիկների կառուցվածքը փոխելը լավ գաղափար չէ: Սա ոչ միայն դժվար է հասնել բեռնարկղերի մեծ մասի հետ, այլև հակված է նուրբ խնդիրների, որոնք դժվար է հայտնաբերել: Հետևաբար, ես առաջարկում եմ ձեր դիզայնի մի փոքր փոփոխություն, որը շրջանցում է ձեր առջև ծառացած խնդիրը:

Կախվածությունն ամբողջությամբ փոխելու փորձի փոխարեն, փոխարենը նախապես համալրեք գոյություն ունեցող կախվածությունը այլ շղթայի վրա բեռնված տվյալների հետ:

Դա կարելի է անել՝ օգտագործելով հետևյալ վերացական/իրականացման զույգը.

public interface IConfigurationProvider
{
    Task<Configuration> GetConfigurationAsync();
}

public sealed class DatabaseConfigurationProvider : IConfigurationProvider
{
    private readonly DbContext _dbContext;

    public DatabaseConfigurationProvider(DbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public Configuration Configuration { get; set; }

    public async Task<Configuration> GetConfigurationAsync()
    {
         if (Configuration is null)
         {
             await // read configurations
         }

         return Configuration;
    }
}

Ուշադրություն դարձրեք DatabaseConfigurationProvider-ի կատարման հանրային Configurationին, որը ոչ IConfigurationProvider ինտերֆեյսի վրա:

Սա է իմ ներկայացրած լուծման առանցքը: Թույլատրել ձեր Կոմպոզիցիայի արմատը արժեքը սահմանելու համար՝ առանց ձեր հավելվածի աբստրակցիաները աղտոտելու, քանի որ հավելվածի կոդը կարիք չունի վերագրանցելու Configuration օբյեկտը. միայն Composition Root-ին է պետք:

Այս աբստրակցիա/իրականացում զույգով ֆոնային ծառայությունը կարող է այսպիսի տեսք ունենալ.

class MyBackgroundService
{
    private readonly IServiceScopeFactory _scopeFactory; // set in ctor

    public Task DoStuff()
    {
        var itens = GetItens();

        // Create a scope for the root operation.
        using (var scope = _scopeFactory.CreateScope())
        {
            // Resolve the IConfigurationProvider first to load
            // the configuration once eagerly.
            var provider = scope.ServiceProvider
                .GetRequiredService<IConfigurationProvider>();

            var configuration = await provider.GetConfigurationAsync();

            Parallel.ForEach(itens, (item) => Process(configuration, item));
        }
    }

    private void Process(Configuration configuration, Item item)
    {
        // Create a new scope per thread
        using (var scope = _scopeFactory.CreateScope())
        {
            // Request the configuration implementation that allows
            // setting the configuration.
            var provider = scope.ServiceProvider
                .GetRequiredService<DatabaseConfigurationProvider>();

            // Set the configuration object for the duration of the scope
            provider.Configuration = configuration;

            // Resolve an object graph that depends on IConfigurationProvider.
            var service = scope.ServiceProvider.GetRequiredService<ItemService>();

            service.Process(item);
        }    
    }
}

Դա անելու համար ձեզ հարկավոր է հետևյալ DI կոնֆիգուրացիան.

services.AddScoped<DatabaseConfigurationProvider>();
services.AddScoped<IConfigurationProvider>(
    p => p.GetRequiredService<DatabaseConfigurationProvider>());

Այս նախորդ կոնֆիգուրացիան գրանցում է DatabaseConfigurationProvider երկու անգամ՝ մեկ անգամ իր կոնկրետ տեսակի համար, մեկ անգամ՝ իր ինտերֆեյսի համար: Ինտերֆեյսի գրանցումը փոխանցում է զանգը և ուղղակիորեն լուծում կոնկրետ տեսակը: Սա հատուկ «հնարք» է, որը դուք պետք է կիրառեք MS.DI կոնտեյների հետ աշխատելիս՝ կանխելու երկու առանձին DatabaseConfigurationProvider օրինակներ մեկ շրջանակի ներսում: Դա լիովին կտապալի այս իրականացման ճիշտությունը:

16.10.2019
  • Հիանալի լուծում, շնորհակալություն: Կարծում եմ, որ ժամանակն է թարմացնել իմ DI գիրքը, իմ տարբերակում կա միայն Մարկ Սեմաննը :( 16.10.2019

  • 2

    Ստեղծեք ինտերֆեյս, որը ընդլայնում է IDependency-ը և կկիրառվի միայն ավելի արագ իրականացման համար, որը դուք պետք է պահանջեք, օրինակ՝ IFasterDependency: Այնուհետև գրանցվեք IFasterDependency-ի համար: Այսպիսով, ձեր ավելի արագ դասը դեռևս IDependency օբյեկտ է, և դուք չեք խաթարի գոյություն ունեցող ծածկագիրը, բայց այժմ կարող եք ազատորեն պահանջել այն:

    public interface IDependency
    {
        // Actual, useful interface definition
    }
    
    public interface IFasterDependency : IDependency
    {
        // You don't actually have to define anything here
    }
    
    public class SlowClass : IDependency
    {
    
    }
    
    // FasterClass is now a IDependencyObject, but has its own interface 
    // so you can register it in your dependency injection
    public class FasterClass : IFasterDependency
    {
    
    }
    
    16.10.2019
  • Իմ դասերը կախվածություն ունեն ID-ի կախվածությունից: Դա չի կարող փոխվել, քանի որ երբեմն (վեբ api հարցման համատեքստում կատարելիս) այն պետք է ստանա ID-ի կախվածություն: Միայն ֆոնային ծառայության միջոցով գործարկելու դեպքում այն ​​այլ կախվածության կարիք ունի: Ինչպե՞ս կասեմ ներարկել IDependency / IFasterDependency՝ կախված կատարման համատեքստից: 16.10.2019
  • Նոր նյութեր

    Օգտագործելով Fetch Vs Axios.Js-ը՝ HTTP հարցումներ կատարելու համար
    JavaScript-ը կարող է ցանցային հարցումներ ուղարկել սերվեր և բեռնել նոր տեղեկատվություն, երբ դա անհրաժեշտ լինի: Օրինակ, մենք կարող ենք օգտագործել ցանցային հարցումը պատվեր ներկայացնելու,..

    Տիրապետել հանգստության արվեստին. մշակողի ուղեցույց՝ ճնշման տակ ծաղկելու համար
    Տիրապետել հանգստության արվեստին. մշակողի ուղեցույց՝ ճնշման տակ ծաղկելու համար Ինչպե՞ս հանգստացնել ձեր միտքը և աշխատեցնել ձեր պրոցեսորը: Ինչպես մնալ հանգիստ և զարգանալ ճնշման տակ...

    Մեքենայի ուսուցում բանկային և ֆինանսների ոլորտում
    Բարդ, խելացի անվտանգության համակարգերը և հաճախորդների սպասարկման պարզեցված ծառայությունները բիզնեսի հաջողության բանալին են: Ֆինանսական հաստատությունները, մասնավորապես, պետք է առաջ մնան կորի..

    Ես AI-ին հարցրի կյանքի իմաստը, այն ինչ ասում էր, ցնցող էր:
    Այն պահից ի վեր, երբ ես իմացա Արհեստական ​​ինտելեկտի մասին, ես հիացած էի այն բանով, թե ինչպես է այն կարողանում հասկանալ մարդկային նորմալ տեքստը, և այն կարող է առաջացնել իր սեփական արձագանքը դրա..

    Ինչպես սովորել կոդավորումը Python-ում վագրի պես:
    Սովորելու համար ծրագրավորման նոր լեզու ընտրելը բարդ է: Անկախ նրանից, թե դուք սկսնակ եք, թե առաջադեմ, դա օգնում է իմանալ, թե ինչ թեմաներ պետք է սովորել: Ծրագրավորման լեզվի հիմունքները, դրա..

    C++-ի օրական բիթ(ե) | Ամենաերկար պալինդրոմային ենթաշարը
    C++ #198-ի ամենօրյա բիթ(ե), Ընդհանուր հարցազրույցի խնդիր. Ամենաերկար պալինդրոմային ենթատող: Այսօր մենք կանդրադառնանք հարցազրույցի ընդհանուր խնդրին. Ամենաերկար palindromic substring...

    Kydavra ICAReducer՝ ձեր տվյալների ծավալայինությունը նվազեցնելու համար
    Ի՞նչ է ICAReducer-ը: ICAReducer-ն աշխատում է հետևյալ կերպ. այն նվազեցնում է նրանց միջև բարձր փոխկապակցված հատկանիշները մինչև մեկ սյունակ: Բավականին նման է PCAreducer-ին, չնայած այն..