Asp.Net Core এ একই ইন্টারফেসের একাধিক বাস্তবায়ন কীভাবে নিবন্ধিত করবেন?


239

আমার কাছে পরিষেবা রয়েছে যা একই ইন্টারফেস থেকে প্রাপ্ত।

public interface IService { }
public class ServiceA : IService { }
public class ServiceB : IService { } 
public class ServiceC : IService { }

সাধারণত, অন্যান্য আইওসি পাত্রে যেমন Unityআপনাকে কিছু Keyআলাদা করে তাদের দ্বারা কংক্রিট বাস্তবায়নগুলি নিবন্ধন করতে দেয় ।

এএসপি.নেট কোরে, আমি কীভাবে কীগুলির উপর ভিত্তি করে এই পরিষেবাগুলি নিবন্ধভুক্ত করব এবং রানটাইমগুলিতে সেগুলি সমাধান করব?

আমি কোনও Addপরিষেবা পদ্ধতি দেখতে পাচ্ছি না যা একটি keyবা nameপরামিতি গ্রহণ করে, যা সাধারণত কংক্রিট বাস্তবায়নের পার্থক্য করতে ব্যবহৃত হত।

    public void ConfigureServices(IServiceCollection services)
    {            
         // How do I register services of the same interface?            
    }


    public MyController:Controller
    {
       public void DoSomething(string key)
       { 
          // How do I resolve the service by key?
       }
    }

কারখানার প্যাটার্নটি কি এখানে একমাত্র বিকল্প?

Update1
আমি যদিও নিবন্ধ চলে গেছে এখানে যে দেখায় কিভাবে কারখানা প্যাটার্ন ব্যবহার করতে Service দৃষ্টান্ত পেতে আমরা একাধিক কংক্রিট বাস্তবায়নের আছে। তবে এটি এখনও সম্পূর্ণ সমাধান নয়। আমি যখন _serviceProvider.GetService()পদ্ধতিটি কল করি তখন আমি কনস্ট্রাক্টরের মধ্যে ডেটা ইনজেক্ট করতে পারি না।

উদাহরণস্বরূপ এটি বিবেচনা করুন:

public class ServiceA : IService
{
     private string _efConnectionString;
     ServiceA(string efconnectionString)
     {
       _efConnecttionString = efConnectionString;
     } 
}

public class ServiceB : IService
{    
   private string _mongoConnectionString;
   public ServiceB(string mongoConnectionString)
   {
      _mongoConnectionString = mongoConnectionString;
   }
}

public class ServiceC : IService
{    
    private string _someOtherConnectionString
    public ServiceC(string someOtherConnectionString)
    {
      _someOtherConnectionString = someOtherConnectionString;
    }
}

কিভাবে _serviceProvider.GetService()উপযুক্ত সংযোগ স্ট্রিং ইনজেক্ট করতে পারেন ? ইউনিটিতে, বা অন্য কোনও আইওসি লাইব্রেরিতে, আমরা এটি টাইপ রেজিস্ট্রেশনে করতে পারি। আমি আইওপশনটি ব্যবহার করতে পারি , তবে এর জন্য আমাকে সমস্ত সেটিংস ইনজেক্ট করতে হবে। আমি পরিষেবাটিতে কোনও নির্দিষ্ট সংযোগ স্ট্রিং ইনজেক্ট করতে পারি না।

এছাড়াও নোট করুন যে আমি অন্যান্য পাত্রে (ityক্য সহ) ব্যবহার এড়াতে চাইছি কারণ তখন নতুন কন্টেইনারে আমাকে অন্য সমস্ত কিছু (যেমন কন্ট্রোলার )ও নিবন্ধ করতে হবে।

এছাড়াও, পরিষেবা দৃষ্টান্ত তৈরি করতে কারখানার প্যাটার্নটি ব্যবহার করা ডিআইপি-র বিপক্ষে, কারণ এখানে কোনও ক্লায়েন্টের বিশদ থাকা নির্ভরতার সংখ্যা বৃদ্ধি করে ।

সুতরাং, আমি মনে করি এএসপি.নেট কোরের ডিফল্ট ডিআই দুটি জিনিস হারিয়েছে:

  1. একটি কী ব্যবহার করে দৃষ্টান্ত নিবন্ধ করার ক্ষমতা
  2. নিবন্ধের সময় কনস্টাক্টরে স্থির ডেটা ইনজেক্ট করার ক্ষমতা


2
নাম ভিত্তিক নিবন্ধগুলির জন্য শেষ পর্যন্ত নুগেটের একটি এক্সটেনশান রয়েছে , আশা করি এটি সহায়তা করতে পারে
নিউলিয়াস

হাই, আমার বোকা প্রশ্নের জন্য দুঃখিত, তবে আমি মাইক্রোসফ্ট. এক্সটেনশনস.ডেপেন্ডেন্সি ইন্জেকশন সম্পর্কে নতুন সম্পর্কে ... আপনি কি মনে করেন যে 3 টি খালি ইন্টারফেস তৈরি করা হয়েছে যা "পাবলিক ইন্টারফেস আইএসসারএ: আইসোয়ারেসি" এবং "পাবলিক ক্লাস সার্ভিসএ: আইসোর্সিয়া" এর চেয়ে আইভরিসকে প্রসারিত করে "... একটি ভাল অনুশীলন বিকল্প হতে পারে?
এমিলিয়ানো ম্যাগলিয়োকা

এই নিবন্ধটি কোন ব্যবহার? stevejgordon.co.uk/…
মাইক বি

Update1কনস্ট্রাক্টরগুলিতে ইনজেকশনের জিনিসগুলি যা তৈরি করতে হবে তা নির্ধারণের চেয়ে খুব আলাদা
নীল

উত্তর:


245

আমি Funcযখন নিজেকে এই পরিস্থিতিতে পেয়েছি তখন আমি ব্যবহার করে একটি সাধারণ কাজ করেছি।

প্রথমে ভাগ করে নেওয়া প্রতিনিধি ঘোষণা করুন:

public delegate IService ServiceResolver(string key);

তারপরে আপনার Startup.csএকাধিক কংক্রিট নিবন্ধকরণ এবং সেই ধরণের ম্যানুয়াল ম্যাপিং সেটআপ করুন:

services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();

services.AddTransient<ServiceResolver>(serviceProvider => key =>
{
    switch (key)
    {
        case "A":
            return serviceProvider.GetService<ServiceA>();
        case "B":
            return serviceProvider.GetService<ServiceB>();
        case "C":
            return serviceProvider.GetService<ServiceC>();
        default:
            throw new KeyNotFoundException(); // or maybe return null, up to you
    }
});

এবং ডিআই-তে নিবন্ধিত যে কোনও শ্রেণি থেকে এটি ব্যবহার করুন:

public class Consumer
{
    private readonly IService _aService;

    public Consumer(ServiceResolver serviceAccessor)
    {
        _aService = serviceAccessor("A");
    }

    public void UseServiceA()
    {
        _aService.DoTheThing();
    }
}

মনে রাখবেন যে এই উদাহরণে সমাধানের মূলটি একটি স্ট্রিং, সরলতার জন্য এবং কারণ ওপি বিশেষত এই ক্ষেত্রে জিজ্ঞাসা করেছিল।

তবে আপনি যে কোনও কাস্টম রেজোলিউশন প্রকারটি কী হিসাবে ব্যবহার করতে পারেন, কারণ আপনি সাধারণত আপনার কোডটি ঘোরানোর জন্য একটি বিশাল এন-কেস সুইচ চান না। আপনার অ্যাপ্লিকেশন কীভাবে স্কেল করে তা নির্ভর করে।



2
এর মতো কারখানার প্যাটার্ন ব্যবহার করা সবচেয়ে ভাল উপায়। ভাগ করে নেওয়ার জন্য ধন্যবাদ!
সের্গেই আকোপভ

2
+1 খুব ঝরঝরে এবং পরিষ্কার, কারণ যখন আমরা অন্যান্য ডি-কন্টেইনার ব্যবহার করি তখনই যখনই আমাদের নির্ভরতাগুলি সমাধান করার দরকার হয় তখন তাদের প্যাকেজটি অন্তর্ভুক্ত করতে হয়। অটোফ্যাকে আইলাইফটাইমস্কোপ।
অনুপম সিং

1
@ অনুপমসিংহ আমার মতে .NET কোর-এ চলমান বেশিরভাগ ধরণের ছোট থেকে মাঝারি অ্যাপ্লিকেশনগুলির প্রয়োজন নেই, কেবল জটিলতা এবং অযাচিত নির্ভরতা যুক্ত করে, বিল্ট-ইন ডিআই-র সৌন্দর্য এবং সরলতা যথেষ্ট পরিমাণে বেশি, এবং এটি করতে পারে এছাড়াও স্বাচ্ছন্দ্য সঙ্গে প্রসারিত করা।
মিগুয়েল এ। আরিলা

7
ভোট ভোটের ব্যাখ্যা - এটি খুব আকর্ষণীয় তবে আমি বর্তমানে কয়েক বছর আগে এই সমস্ত ফানক যাদুটি অপসারণের জন্য একটি বিশাল কোড বেসকে পুনঃসংশ্লিষ্ট করছি (এমএস ডিআই বিপ্লবের আগে) এর সাথে সমস্যাটি হ'ল এটি নাটকীয়ভাবে বৈশিষ্ট্যগুলিতে সংযোগ জটিলতা বৃদ্ধি করে যা আরও জটিলভাবে ডিআই রেজুলেশনের কারণ হতে পারে। উদাহরণস্বরূপ আমি ফান্ডের সাথে কাজ করার জন্য একটি উইন্ডোজ পরিষেবা হ্যান্ডলারের 1.6k এর বেশি কোড লাইন নিয়ে কাজ করেছি এবং এটি ডিআই-এর প্রস্তাবিত পদ্ধতিটি করার পরে আমি এটিকে 0.2k লাইনে কমিয়ে দিয়েছি। কোডের ঠিক আছে রেখার অর্থ কিছুই নেই .. এটি পড়া এবং পুনরায় পুনঃব্যবহার করা সহজ ছাড়া ...
কুলা

79

অন্য বিকল্পটি GetServicesথেকে এক্সটেনশন পদ্ধতিটি ব্যবহার করা Microsoft.Extensions.DependencyInjection

আপনার পরিষেবাগুলি নিবন্ধিত করুন:

services.AddSingleton<IService, ServiceA>();
services.AddSingleton<IService, ServiceB>();
services.AddSingleton<IService, ServiceC>();

তারপরে সামান্য লিনক দিয়ে সমাধান করুন:

var services = serviceProvider.GetServices<IService>();
var serviceB = services.First(o => o.GetType() == typeof(ServiceB));

অথবা

var serviceZ = services.First(o => o.Name.Equals("Z"));

(ধরে নিলাম যে IService"নাম" নামে একটি স্ট্রিং সম্পত্তি রয়েছে)

আছে তা নিশ্চিত করুন using Microsoft.Extensions.DependencyInjection;

হালনাগাদ

অ্যাস্পনেট ২.১ উত্স: GetServices


6
নিশ্চিত নয়, তবে আমি মনে করি এটি নির্বিচারক নয়। আজ আপনি যে ফলাফল পাবেন তা আগামীকাল বদলে যেতে পারে, এটি একটি ভাল অনুশীলন বলে মনে হয় না।
rnrneverdies

4
গেট সার্ভিসেসের লিঙ্কটি উত্সাহিত করুন, যা আমাকে দেখিয়েছে যে আপনি একটি নির্ভরশীল পরিষেবাগুলির অনুরোধের মাধ্যমে পরিষেবার একটি তালিকার জন্য আবেদন করতে পারেনIEnumerable<IService>
জননি 5

20
সার্ভিসপ্রাইভাইডার.গেট সার্ভিসেস <IS Services> () প্রতিটি সার্ভিসএ, সার্ভিসবি এবং সার্ভিসসি ইনস্ট্যান্ট করবে। আপনি কেবলমাত্র একটি পরিষেবার কনস্ট্রাক্টরকে কল করতে চান - এটি যা আপনার আসলে প্রয়োজন। যদি বাস্তবায়নগুলি হালকা ওজন না হয় বা আপনার আইএসসিভারের অনেকগুলি বাস্তবায়ন থাকে তবে এটি একটি বড় সমস্যা (উদাহরণস্বরূপ, প্রতিটি মডেলের জন্য আপনার আইআরপিওসিটরির স্বয়ংক্রিয়ভাবে উত্পাদিত প্রয়োগ রয়েছে)।
উরোস

6
আমি @ ইউরোসের সাথে একমত এটি একটি ভাল সমাধান নয়। আপনি যদি 10 টি আইসওয়ারি-বাস্তবায়নগুলি নিবন্ধভুক্ত করেন এবং আপনার প্রকৃত প্রয়োজনটি শেষটি হয় তবে কী হবে তা কল্পনা করুন। এই ক্ষেত্রে, 9 টি দৃষ্টান্ত আসলে ডিআই দ্বারা তৈরি করা হয়, যা কখনই ব্যবহার হয় না।
থোমাই

4
খারাপ ধারণা: একাধিক অব্যবহৃত উদাহরণ, পরিষেবা লোকেটার অ্যান্টি প্যাটার্ন এবং আসল বাস্তবায়নের সরাসরি সংযোগ (টাইপ <সার্ভিস>>)।
রিকো সুটার 21

20

এটি দ্বারা সমর্থিত নয় Microsoft.Extensions.DependencyInjection

তবে আপনি অন্য নির্ভরতা ইনজেকশন প্রক্রিয়াটি প্লাগ-ইন করতে পারেন, যেমন StructureMap এটির হোম পৃষ্ঠা এবং এটি গিটহাব প্রকল্প like

এটি মোটেই কঠিন নয়:

  1. আপনার স্ট্রাকচারম্যাপে নির্ভরতা যুক্ত করুন project.json:

    "Structuremap.Microsoft.DependencyInjection" : "1.0.1",
  2. এএসপি.নেট পাইপলাইনের ভিতরে এটি প্রবেশ করুন ConfigureServicesএবং আপনার ক্লাসগুলি নিবন্ধ করুন (দস্তাবেজগুলি দেখুন)

    public IServiceProvider ConfigureServices(IServiceCollection services) // returns IServiceProvider !
    {
        // Add framework services.
        services.AddMvc();
        services.AddWhatever();
    
        //using StructureMap;
        var container = new Container();
        container.Configure(config =>
        {
            // Register stuff in container, using the StructureMap APIs...
            config.For<IPet>().Add(new Cat("CatA")).Named("A");
            config.For<IPet>().Add(new Cat("CatB")).Named("B");
            config.For<IPet>().Use("A"); // Optionally set a default
            config.Populate(services);
        });
    
        return container.GetInstance<IServiceProvider>();
    }
  3. তারপরে, একটি নামকরণ উদাহরণ পেতে, আপনাকে অনুরোধ করতে হবে IContainer

    public class HomeController : Controller
    {
        public HomeController(IContainer injectedContainer)
        {
            var myPet = injectedContainer.GetInstance<IPet>("B");
            string name = myPet.Name; // Returns "CatB"

এটাই.

উদাহরণস্বরূপ নির্মাণের জন্য, আপনার প্রয়োজন

    public interface IPet
    {
        string Name { get; set; }
    }

    public class Cat : IPet
    {
        public Cat(string name)
        {
            Name = name;
        }

        public string Name {get; set; }
    }

আমি এই পদ্ধতির চেষ্টা করেছি, তবে আমি আমার নিয়ামকটিতে রানটাইম ত্রুটিগুলি পেয়েছি কারণ আইকনটাইনার বিল্ড প্ল্যানগুলিতে পাওয়া যায় নি। আইকন্টেইনারের স্বয়ংক্রিয় ইনজেকশন লাগানোর জন্য আমার প্রয়োজনীয় কিছু কি আছে?
মোহর্তান

বিটিডাব্লু, আমি স্ট্রাকচারম্যাপ.মিকারোসফট্ট। ডিপেন্ডেনসিআইজেকশন ১.৩.০ ব্যবহার করছি।
মোহর্তান

আপনি কি কনফিগার সার্ভিসগুলিতে নতুন ধারকটি ফিরিয়ে দিচ্ছেন?
জেরার্ডো গ্রিগনিলি

উপরের # 2 ধাপে উল্লিখিত হিসাবে আমি নতুন ধারকের আইএসভারসপ্রোভাইডারআইনস্ট্যান্স ফিরিয়ে দিচ্ছি। আমি অনুলিপি করেছি কেবল এটি আমার ধরণের জন্য পরিবর্তন করা। এটি একটি ভাল সমাধান এবং নিখুঁতভাবে কাজ করছে। একমাত্র ত্রুটিটি হ'ল আমি কোনও ইনজেকশনের ধারকটি ব্যবহার করতে অক্ষম এবং একটি স্ট্যাটিক পাত্রে অবলম্বন করছি, যা আমি করতে চাই না।
মোহর্তান

1
এটি আমার জন্য ধন্যবাদ জেরার্ডো গ্রিগনোলিকে ধন্যবাদ জানায়। আপনি যদি এখনও এটি সন্ধান করছেন তবে @ মোহর্টান নমুনা কোডটি এখানে রয়েছে। github.com/Yawarmurtaza/AspNetCoreStructureMap
ইয়াওয়ার মুর্তজা

13

আপনি ঠিক বলেছেন, এএসপি.নেট কোর কনটেইনারটিতে একাধিক পরিষেবা নিবন্ধকরণ এবং তারপরে একটি নির্দিষ্টটিকে পুনরুদ্ধারের ধারণা নেই, যেমন আপনি পরামর্শ দিয়েছেন যে কারখানায় একমাত্র আসল সমাধান।

বিকল্পভাবে, আপনি thirdক্য বা স্ট্রাকচারম্যাপের মতো কোনও তৃতীয় পক্ষের পাত্রে যেতে পারেন যা আপনার প্রয়োজনীয় সমাধানটি সরবরাহ করে (এখানে নথিভুক্ত: https://docs.asp.net/en/latest/fundamentals/d dependency-inication.html?#replacing- ডিফল্ট-পরিষেবাগুলির ধারক )।


13

আমি একই সমস্যার মুখোমুখি হয়েছি এবং কীভাবে এটি সমাধান করেছি এবং কেন তা ভাগ করে নিতে চাই।

যেমনটি আপনি উল্লেখ করেছেন দুটি সমস্যা আছে। প্রথম:

Asp.Net Core এ কীভাবে আমি এই পরিষেবাদিগুলি নিবন্ধভুক্ত করব এবং কোনও কী এর উপর ভিত্তি করে রানটাইম এ এটি সমাধান করব?

সুতরাং আমরা কি বিকল্প আছে? ভাবেন দুটি পরামর্শ দেয়:

  • একটি কাস্টম কারখানা ব্যবহার করুন (যেমন _myFactory.GetServiceByKey(key))

  • অন্য ডিআই ইঞ্জিন ব্যবহার করুন (যেমন _unityContainer.Resolve<IService>(key))

কারখানার প্যাটার্নটি কি এখানে একমাত্র বিকল্প?

বাস্তবে উভয় বিকল্পই কারখানা কারণ প্রতিটি আইওসি কনটেইনারও একটি কারখানা (যদিও অত্যন্ত কনফিগারযোগ্য এবং জটিল)। এবং এটি আমার কাছে মনে হয় যে অন্যান্য বিকল্পগুলিও কারখানার প্যাটার্নের বিভিন্নতা।

তাহলে কোন বিকল্পটি ভাল? এখানে আমি @ সোকের সাথে একমত যারা যিনি কাস্টম কারখানাটি ব্যবহার করার পরামর্শ দিয়েছেন এবং সে কারণেই।

প্রথমত, যখন সত্যই প্রয়োজন হয় না তখন আমি সর্বদা নতুন নির্ভরতা যুক্ত এড়াতে চেষ্টা করি। সুতরাং আমি এই বিষয়টিতে আপনার সাথে একমত। তদতিরিক্ত, দুটি ডিআই ফ্রেমওয়ার্ক ব্যবহার করা কাস্টম ফ্যাক্টরি অ্যাবস্ট্রাকশন তৈরির চেয়ে খারাপ। দ্বিতীয় ক্ষেত্রে আপনাকে নতুন প্যাকেজ নির্ভরতা যুক্ত করতে হবে (ইউনিটির মতো) তবে একটি নতুন কারখানার ইন্টারফেসের উপর নির্ভর করে এখানে কম খারাপ evil আমার বিশ্বাস, এএসপি.নেট কোর ডিআইএর মূল ধারণাটি সরলতা। এটি কেআইএসএস নীতি অনুসরণ করে ন্যূনতম সংখ্যক বৈশিষ্ট্য বজায় রাখে । আপনার যদি কিছু অতিরিক্ত বৈশিষ্ট্য প্রয়োজন তবে ডিআইওয়াই বা সংশ্লিষ্ট প্লাগিন ব্যবহার করুন যা পছন্দসই বৈশিষ্ট্যটি প্রয়োগ করে (ক্লোজড প্রিন্সিপলটি খুলুন)।

দ্বিতীয়ত, প্রায়শই আমাদের একক পরিষেবার জন্য অনেক নামযুক্ত নির্ভরতা ইনজেকশনের প্রয়োজন। ইউনিটির ক্ষেত্রে আপনাকে কনস্ট্রাক্টর প্যারামিটারের (নাম ব্যবহারের InjectionConstructor) জন্য নাম নির্দিষ্ট করতে হতে পারে । এই রেজিস্ট্রেশনটি নির্মাণকারীর পক্ষে যুক্তি অনুমান করতে প্রতিবিম্ব এবং কিছু স্মার্ট যুক্তি ব্যবহার করে। এটি যদি রানটাইম ত্রুটির দিকেও নিয়ে যেতে পারে তবে নিবন্ধকারীর সাথে যুক্তিগুলির সাথে মেলে না। অন্যদিকে, আপনার নিজস্ব কারখানাটি ব্যবহার করার সময় আপনি কীভাবে কনস্ট্রাক্টর প্যারামিটারগুলি সরবরাহ করবেন তার পুরো নিয়ন্ত্রণ। এটি আরও পঠনযোগ্য এবং সংকলন-সময়ে সমাধান করা হয়েছে। কেআইএসএস নীতি আবার।

দ্বিতীয় সমস্যা:

_ServicePovider.GetS सर्विस () কীভাবে উপযুক্ত সংযোগের স্ট্রিং ইনজেক্ট করতে পারে?

প্রথমত, আমি আপনার সাথে একমত যে নতুন জিনিসগুলির IOptions( যেমন এবং প্যাকেজের উপর Microsoft.Extensions.Options.ConfigurationExtensions) নির্ভর করে কোনও ভাল ধারণা নয়। আমি IOptionsএর বেনিফিট সম্পর্কে যেখানে বিভিন্ন মতামত ছিল সে সম্পর্কে কিছু আলোচনা করতে দেখেছি । আবার, যখন সত্যিকারের প্রয়োজন হয় না তখন আমি নতুন নির্ভরতা যুক্ত এড়াতে চেষ্টা করি। আসলেই কি দরকার? আমার মনে হয় না। অন্যথায় প্রতিটি বাস্তবায়নই সেই বাস্তবায়ন থেকে কোন স্পষ্ট প্রয়োজন ছাড়াই তার উপর নির্ভর করতে হবে (আমার কাছে এটি আইএসপি লঙ্ঘনের মতো বলে মনে হচ্ছে, যেখানে আমিও আপনার সাথে একমত আছি)। কারখানার উপর নির্ভর করে এটিও সত্য তবে এই ক্ষেত্রে এটি সম্ভব এড়ানো যায়।

ASP.NET কোর ডিআই সেই উদ্দেশ্যে একটি খুব সুন্দর ওভারলোড সরবরাহ করে:

var mongoConnection = //...
var efConnection = //...
var otherConnection = //...
services.AddTransient<IMyFactory>(
             s => new MyFactoryImpl(
                 mongoConnection, efConnection, otherConnection, 
                 s.GetService<ISomeDependency1>(), s.GetService<ISomeDependency2>())));

হাই, আমার বোকা প্রশ্নের জন্য দুঃখিত, তবে আমি মাইক্রোসফ্ট. এক্সটেনশানস.ডেপেন্ডেন্সি ইন্জেকশন সম্পর্কে নতুন সম্পর্কে ... আপনি কি মনে করেন যে "পাবলিক ইন্টারফেস আইএসসারিয়া: আইসওয়ারি" এবং "পাবলিক ক্লাস সার্ভিসএ: আইসোর্সিয়া" এর চেয়ে আইভরিসকে প্রসারিত 3 টি ইন্টারফেস তৈরি করুন? ... একটি ভাল অনুশীলন বিকল্প হতে পারে?
এমিলিয়ানো ম্যাগলিয়োকা

1
@ এমিলিয়ানো-ম্যাগলিয়োকা সাধারণভাবে, IServiceAআপনার ক্ষেত্রে আপনার ইন্টারফেসের উপর নির্ভর করা উচিত নয় যা আপনি ব্যবহার করেন না (আইএসপি) । আপনি যেহেতু IServiceকেবলমাত্র পদ্ধতি ব্যবহার করছেন তাই আপনার কেবলমাত্র নির্ভরতা থাকা উচিত IService
নিলিয়াস

1
@ ক্যাগাতে-কালান ওপির প্রশ্নের ক্ষেত্রে তিনি সহজেই এএসপি.নেট কোর ডিআই-এর সাথে তার লক্ষ্য অর্জন করতে পারেন। অন্যান্য ডিআই ফ্রেমওয়ার্কের প্রয়োজন নেই।
নিউলিয়াস

1
@ এমিলিয়ানো ম্যাগলিয়োকা সহজেই এইভাবে সমাধান করা যেতে পারে: services.AddTransient<MyFirstClass>( s => new MyFirstClass(s.GetService<Escpos>()));প্রথম শ্রেণির services.AddTransient<MySecondClass>( s => new MySecondClass(s.GetService<Usbpos>()));জন্য এবং দ্বিতীয় শ্রেণির জন্য।
নিউসিয়াস

1
এমিলিয়ানো ম্যাগলিয়োকা আমার উদাহরণে 'মাই ফার্স্টক্লাস' এবং 'মাইসেকন্ডক্লাস' উভয়েরই ইন্টারফেস টাইপের একই কোর প্যারামিটার রয়েছে যা এস্কপোস এবং ইউএসবিপোস উভয়ই প্রয়োগ করে। সুতরাং উপরের কোডটি কেবলমাত্র আইওসি পাত্রে নির্দেশ দেয় যে কীভাবে 'মাই ফার্স্টক্লাস' এবং 'মাইসেকেন্ডক্লাস' ইনস্ট্যান্সেট করতে হয়। বেশি না. সুতরাং এছাড়াও আপনাকে 'মাই ফার্স্টক্লাস' এবং 'মাইসেকেন্ডক্লাস' থেকে অন্য কিছু ইন্টারফেস মানচিত্রের প্রয়োজন হতে পারে। এটি আপনার প্রয়োজনের উপর নির্ভর করে এবং আমি আমার উদাহরণে এটি আবৃত করি নি।
নিলিয়াস

13

আমি কেবল একটি আইনিউমেবল ইনজেকশন করি

স্টার্টআপ। সি-তে কনফিগার সার্ভিসেস

Assembly.GetEntryAssembly().GetTypesAssignableFrom<IService>().ForEach((t)=>
                {
                    services.AddScoped(typeof(IService), t);
                });

পরিষেবাদি ফোল্ডার

public interface IService
{
    string Name { get; set; }
}

public class ServiceA : IService
{
    public string Name { get { return "A"; } }
}

public class ServiceB : IService
{    
    public string Name { get { return "B"; } }
}

public class ServiceC : IService
{    
    public string Name { get { return "C"; } }
}

MyController.cs

public class MyController
{
    private readonly IEnumerable<IService> _services;
    public MyController(IEnumerable<IService> services)
    {
        _services = services;
    }
    public void DoSomething()
    {
        var service = _services.Where(s => s.Name == "A").Single();
    }
...
}

Extensions.cs

    public static List<Type> GetTypesAssignableFrom<T>(this Assembly assembly)
    {
        return assembly.GetTypesAssignableFrom(typeof(T));
    }
    public static List<Type> GetTypesAssignableFrom(this Assembly assembly, Type compareType)
    {
        List<Type> ret = new List<Type>();
        foreach (var type in assembly.DefinedTypes)
        {
            if (compareType.IsAssignableFrom(type) && compareType != type)
            {
                ret.Add(type);
            }
        }
        return ret;
    }

কন্ট্রোলারের ডসোমিংথিং () পদ্ধতিতে আপনি যে সার্ভিসটি চান তা সমাধান করতে আপনি টাইপফ ব্যবহার করতে পারেন: var পরিষেবা = _services.FirstOrDefault (t => t.GetType () == টাইপফ (সার্ভিসএ));
Ciaran Bruen

আমি আক্ষরিকভাবে সবকিছু চেষ্টা করেছিলাম, এবং এটিই আমার জন্য কাজ করা একমাত্র সমাধান। ধন্যবাদ!
Skatz1990

@ Skatz1990 নীচে অন্য পোস্টে তৈরি সমাধানটি চেষ্টা করুন Try আমি মনে করি এটি পরিষ্কার এবং সহজ ব্যবহারযোগ্য।
টি ব্রাউন

12

এখানে বেশিরভাগ উত্তর একক দায়িত্বের নীতি লঙ্ঘন করে (কোনও পরিষেবা শ্রেণি নির্ভরতা নিজেই সমাধান করতে পারে না) এবং / অথবা পরিষেবা লোকেটারকে অ্যান্টি-প্যাটার্ন ব্যবহার করে।

এই সমস্যাগুলি এড়ানোর জন্য আরেকটি বিকল্প হ'ল:

  • ইন্টারফেসে বা অতিরিক্ত জেনেরিক ইন্টারফেস প্রয়োগকারী একটি নতুন ইন্টারফেসে অতিরিক্ত জেনেরিক ধরণের পরামিতি ব্যবহার করুন,
  • চিহ্নিতকারী টাইপ এবং তারপরে অ্যাডাপ্টার / ইন্টারসেপ্টর শ্রেণি প্রয়োগ করুন
  • জেনেরিক প্রকারটি "নাম" হিসাবে ব্যবহার করুন

আমি আরও বিশদ সহ একটি নিবন্ধ লিখেছি:। নেট মধ্যে নির্ভরতা ইনজেকশন: নাম নিবন্ধভুক্ত নিখোঁজ প্রায় কাজ করার একটি উপায়


গৃহীত উত্তর কীভাবে একক দায়িত্বের নীতি লঙ্ঘন করে?
এলপি 13

মন্তব্য দেখুন stackoverflow.com/a/52066039/876814 এবং গৃহীত উত্তরে সেবা lazyily সমাধান করা, অর্থাত্ আপনি শুধু জানি যদি এটা রানটাইম এ ব্যর্থ সেখানে স্ট্যাটিক্যালি ধারক বিল্ড পর সূচনার সময় এই পরীক্ষা করার কোনো উপায় (অনুরূপ মন্তব্যে উত্তর)। এসআরপি কারণ পরিষেবাটি কেবল তার ব্যবসায়িক যুক্তির জন্যই নয়, নির্ভরতা সমাধানের জন্যও দায়ী
রিকো সুটার

@ রিকোসুটার আমি আপনার ব্লগের সমাধানটি সত্যিই পছন্দ করি তবে স্টার্টআপ ক্লাসের মধ্যে আপনার ডিআই দ্বারা বিভ্রান্ত হয়ে পড়েছি। সুনির্দিষ্ট, আমি সেই স্বাক্ষর সহ কোনও নির্মাণকারীর দেখতে পাচ্ছি না বলে আমি মেসেজপুব্লিশার ("মাইআর্ডারক্রিটেড কিউইউ" )টি বুঝতে পারি না। Services.AddSingleton <IMessagePublisher <OrderCreatedMessage>> (নতুন মেসেজপুব্লিশার <অর্ডারক্রিয়েটেড মেসেজ> (নতুন মেসেজপুব্লিশার ("মাইআর্ডারক্রিটেড কিউইউ"))));
লি জেড

ধন্যবাদ, নিবন্ধটি আপডেট করেছেন এবং IMessagePublisher এর নমুনা বাস্তবায়ন হিসাবে MyMessagePublisher ব্যবহার করুন
রিকো সুটার

7

এই পার্টিতে দেরি হয়ে গেলেও এখানে আমার সমাধান:

জেনেরিক হ্যান্ডলার যদি স্টার্টআপ.সি বা প্রোগ্রাম.সি ...

services.AddTransient<IMyInterface<CustomerSavedConsumer>, CustomerSavedConsumer>();
services.AddTransient<IMyInterface<ManagerSavedConsumer>, ManagerSavedConsumer>();

টি ইন্টারফেস সেটআপের আইএমআইআইন্টারফেস

public interface IMyInterface<T> where T : class, IMyInterface<T>
{
    Task Consume();
}

টি এর আইএমআইআইন্টারফেসের কংক্রিট বাস্তবায়ন

public class CustomerSavedConsumer: IMyInterface<CustomerSavedConsumer>
{
    public async Task Consume();
}

public class ManagerSavedConsumer: IMyInterface<ManagerSavedConsumer>
{
    public async Task Consume();
}

আশা করি এটি এইভাবে করার সাথে যদি কোনও সমস্যা হয় তবে কেউ দয়া করে নির্দেশ করবে যে এটি কেন এই ভুল উপায়।


2
IMyInterface<CustomerSavedConsumer>এবং IMyInterface<ManagerSavedConsumer>হয় বিভিন্ন সেবা ধরনের - এই সব সময়ে Ops প্রশ্নের উত্তর নেই।
রিচার্ড হাউয়ার

2
ওপি Asp.net কোর একই ইন্টারফেসের একাধিক বাস্তবায়ন নিবন্ধনের একটি উপায় চেয়েছিল। যদি আমি এটি না করে থাকি তবে দয়া করে কীভাবে (ঠিক) ব্যাখ্যা করুন।
ধূসর

1
আপনি যখন সঠিক হন, এই প্যাটার্নটি অপ্টটি যে প্রভাবটি চেয়েছিল তা করতে দেয়। কমপক্ষে যখন আমি নিজেই এটি করার চেষ্টা করছিলাম তখন আমি এই পোস্টটি জুড়ে হোঁচট খেয়েছি এবং আমার সমাধানটি আমার পরিস্থিতির জন্য সবচেয়ে ভাল কাজ করেছে।
ধূসর

1
আমি আশা করি বিষয়টি আরও ছিল যে একক ইন্টারফেসের জন্য একাধিক বাস্তবায়ন (এমএস ডিআই ব্যবহার করে) নিবন্ধন করা ধারকটিকে অন্যের থেকে একটি বাস্তবায়ন আলাদা করার অনুমতি দেয় না। অন্যান্য ডিআই-তে আপনি এগুলি কী করতে পারেন যাতে ধারক জানে যে কোনটি বেছে নিতে পারে। মাইক্রোসফট আপনি আছে একটি প্রতিনিধি ব্যবহার করি এবং নিজে পছন্দ করে নিন। আপনার ইন্টারফেসগুলি পৃথক হওয়ায় আপনার সমাধান এই দৃশ্যের সমাধান করে না, সুতরাং ধারকটির সঠিক প্রয়োগটি চয়ন করার কোনও সমস্যা নেই। আপনার নমুনা স্পষ্টতই কাজ করার সময়, এটি উল্লিখিত হিসাবে সমস্যার সমাধান নয়।
রিচার্ড হাউয়ার

3
@ গ্রে যদিও আপনার পোস্টটি কিছু খারাপ চাপ পেয়েছে, এই সমাধানটি এগিয়ে দেওয়ার জন্য আমি আপনাকে ধন্যবাদ। এটি নেট কোর ডিআই-এর সীমাবদ্ধতাগুলি অতিক্রম করার জন্য পাঠকদেরকে অন্য বিকল্প দেয়। যদিও এটি সরাসরি ওপিএসের প্রশ্নের উত্তর নাও দিতে পারে, এটি একটি নিখুঁত বিকল্প সমাধান সরবরাহ করে, যা এসও সম্পর্কে ঠিক আছে, তাই না?
নীল ওয়াটসন

5

স্পষ্টতই, আপনি কেবল আপনার পরিষেবা ইন্টারফেসের আইনিউমেবল ইনজেকশন করতে পারেন! এবং তারপরে আপনি যে লাইনকিউ ব্যবহার করতে চান তা সন্ধান করুন।

আমার উদাহরণ এডাব্লুএস এসএনএস পরিষেবার জন্য তবে আপনি কোনও ইনজেকশনের পরিষেবার জন্য সত্যই এটি করতে পারেন।

প্রারম্ভ

foreach (string snsRegion in Configuration["SNSRegions"].Split(',', StringSplitOptions.RemoveEmptyEntries))
{
    services.AddAWSService<IAmazonSimpleNotificationService>(
        string.IsNullOrEmpty(snsRegion) ? null :
        new AWSOptions()
        {
            Region = RegionEndpoint.GetBySystemName(snsRegion)
        }
    );
}

services.AddSingleton<ISNSFactory, SNSFactory>();

services.Configure<SNSConfig>(Configuration);

SNSConfig

public class SNSConfig
{
    public string SNSDefaultRegion { get; set; }
    public string SNSSMSRegion { get; set; }
}

appsettings.json

  "SNSRegions": "ap-south-1,us-west-2",
  "SNSDefaultRegion": "ap-south-1",
  "SNSSMSRegion": "us-west-2",

এসএনএস কারখানা

public class SNSFactory : ISNSFactory
{
    private readonly SNSConfig _snsConfig;
    private readonly IEnumerable<IAmazonSimpleNotificationService> _snsServices;

    public SNSFactory(
        IOptions<SNSConfig> snsConfig,
        IEnumerable<IAmazonSimpleNotificationService> snsServices
        )
    {
        _snsConfig = snsConfig.Value;
        _snsServices = snsServices;
    }

    public IAmazonSimpleNotificationService ForDefault()
    {
        return GetSNS(_snsConfig.SNSDefaultRegion);
    }

    public IAmazonSimpleNotificationService ForSMS()
    {
        return GetSNS(_snsConfig.SNSSMSRegion);
    }

    private IAmazonSimpleNotificationService GetSNS(string region)
    {
        return GetSNS(RegionEndpoint.GetBySystemName(region));
    }

    private IAmazonSimpleNotificationService GetSNS(RegionEndpoint region)
    {
        IAmazonSimpleNotificationService service = _snsServices.FirstOrDefault(sns => sns.Config.RegionEndpoint == region);

        if (service == null)
        {
            throw new Exception($"No SNS service registered for region: {region}");
        }

        return service;
    }
}

public interface ISNSFactory
{
    IAmazonSimpleNotificationService ForDefault();

    IAmazonSimpleNotificationService ForSMS();
}

আপনি এখন আপনার কাস্টম পরিষেবা বা নিয়ামক হিসাবে যে অঞ্চলটি চান তার জন্য আপনি এসএনএস পরিষেবা পেতে পারেন

public class SmsSender : ISmsSender
{
    private readonly IAmazonSimpleNotificationService _sns;

    public SmsSender(ISNSFactory snsFactory)
    {
        _sns = snsFactory.ForSMS();
    }

    .......
 }

public class DeviceController : Controller
{
    private readonly IAmazonSimpleNotificationService _sns;

    public DeviceController(ISNSFactory snsFactory)
    {
        _sns = snsFactory.ForDefault();
    }

     .........
}

5

একটি কারখানার পদ্ধতির অবশ্যই কার্যকর। আর একটি পদ্ধতি হ'ল আইসোভার্স থেকে উত্তরাধিকারসূত্রে স্বতন্ত্র ইন্টারফেস তৈরি করতে উত্তরাধিকার ব্যবহার করা, আপনার আইএসভিয়ার প্রয়োগের ক্ষেত্রে উত্তরাধিকারসূত্রে প্রাপ্ত ইন্টারফেসগুলি প্রয়োগ করা, এবং বেসের পরিবর্তে উত্তরাধিকারসূত্রে প্রাপ্ত ইন্টারফেসগুলি নিবন্ধভুক্ত করা। উত্তরাধিকারের শ্রেণিবদ্ধতা বা কারখানাগুলি যুক্ত করা কিনা "ডান" প্যাটার্ন হ'ল সবই আপনি কার সাথে কথা বলছেন তার উপর নির্ভর করে। IRepository<T>ডেটা অ্যাক্সেসের ভিত্তি হিসাবে যেমন জেনেরিক ব্যবহার করে একই অ্যাপ্লিকেশনটিতে একাধিক ডাটাবেস সরবরাহকারীদের সাথে ডিল করার সময় আমাকে প্রায়শই এই প্যাটার্নটি ব্যবহার করতে হয়।

ইন্টারফেস এবং বাস্তবায়ন উদাহরণ:

public interface IService 
{
}

public interface IServiceA: IService
{}

public interface IServiceB: IService
{}

public IServiceC: IService
{}

public class ServiceA: IServiceA 
{}

public class ServiceB: IServiceB
{}

public class ServiceC: IServiceC
{}

ধারক:

container.Register<IServiceA, ServiceA>();
container.Register<IServiceB, ServiceB>();
container.Register<IServiceC, ServiceC>();

5

Necromancing।
আমি মনে করি এখানকার লোকেরা চাকাটি পুনর্নবীকরণ করছে - এবং খারাপভাবে যদি আমি এটি বলতে পারি ...
আপনি কী দ্বারা কোনও উপাদান নিবন্ধিত করতে চান, কেবল একটি অভিধান ব্যবহার করুন:

System.Collections.Generic.Dictionary<string, IConnectionFactory> dict = 
    new System.Collections.Generic.Dictionary<string, IConnectionFactory>(
        System.StringComparer.OrdinalIgnoreCase);

dict.Add("ReadDB", new ConnectionFactory("connectionString1"));
dict.Add("WriteDB", new ConnectionFactory("connectionString2"));
dict.Add("TestDB", new ConnectionFactory("connectionString3"));
dict.Add("Analytics", new ConnectionFactory("connectionString4"));
dict.Add("LogDB", new ConnectionFactory("connectionString5"));

এবং তারপরে পরিষেবা-সংগ্রহের সাথে অভিধানটি নিবন্ধ করুন:

services.AddSingleton<System.Collections.Generic.Dictionary<string, IConnectionFactory>>(dict);

এরপরে আপনি যদি অভিধানটি পেতে এবং কী দ্বারা এটি অ্যাক্সেস করতে ইচ্ছুক নন, আপনি পরিষেবা-সংগ্রহের জন্য একটি অতিরিক্ত কী-লক-পদ্ধতি-পদ্ধতি যুক্ত করে অভিধানটি আড়াল করতে পারেন:
(ডেলিগেট / ক্লোজারের ব্যবহারটি কোনও সম্ভাব্য রক্ষণাবেক্ষণকারীকে একটি সুযোগ দেওয়া উচিত) কী চলছে তা বোঝা - তীরচিহ্নটি কিছুটা রহস্যজনক)

services.AddTransient<Func<string, IConnectionFactory>>(
    delegate (IServiceProvider sp)
    {
        return
            delegate (string key)
            {
                System.Collections.Generic.Dictionary<string, IConnectionFactory> dbs = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService
 <System.Collections.Generic.Dictionary<string, IConnectionFactory>>(sp);

                if (dbs.ContainsKey(key))
                    return dbs[key];

                throw new System.Collections.Generic.KeyNotFoundException(key); // or maybe return null, up to you
            };
    });

এখন আপনি নিজের প্রকারের মাধ্যমে অ্যাক্সেস করতে পারেন

IConnectionFactory logDB = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<Func<string, IConnectionFactory>>(serviceProvider)("LogDB");
logDB.Connection

অথবা

System.Collections.Generic.Dictionary<string, IConnectionFactory> dbs = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<System.Collections.Generic.Dictionary<string, IConnectionFactory>>(serviceProvider);
dbs["logDB"].Connection

যেমনটি আমরা দেখতে পাচ্ছি, প্রথমটি সম্পূর্ণরূপে অতিরিক্তভাবে প্রয়োজন, কারণ আপনি ক্লোজার এবং অ্যাডট্রান্সিয়েন্টের প্রয়োজন ছাড়াই একটি অভিধান দিয়ে ঠিক এটি করতে পারেন (এবং আপনি যদি ভিবি ব্যবহার করেন, এমনকি বন্ধনীগুলিও আলাদা হবে না):

IConnectionFactory logDB = Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService<System.Collections.Generic.Dictionary<string, IConnectionFactory>>(serviceProvider)["logDB"];
logDB.Connection

(আরও সহজ ভাল - আপনি এটি এক্সটেনশন পদ্ধতি হিসাবে ব্যবহার করতে পারেন যদিও)

অবশ্যই, আপনি যদি অভিধানটি পছন্দ না করেন তবে আপনি কোনও ইন্টারফেসটি Name(বা যে কোনও কিছু) দিয়ে সাজিয়ে নিতে পারেন এবং কী দ্বারা এটি সন্ধান করতে পারেন:

services.AddSingleton<IConnectionFactory>(new ConnectionFactory("ReadDB"));
services.AddSingleton<IConnectionFactory>(new ConnectionFactory("WriteDB"));
services.AddSingleton<IConnectionFactory>(new ConnectionFactory("TestDB"));
services.AddSingleton<IConnectionFactory>(new ConnectionFactory("Analytics"));
services.AddSingleton<IConnectionFactory>(new ConnectionFactory("LogDB"));



// /programming/39174989/how-to-register-multiple-implementations-of-the-same-interface-in-asp-net-core
services.AddTransient<Func<string, IConnectionFactory>>(
    delegate(IServiceProvider sp)
    {
        return
            delegate(string key)
            {
                System.Collections.Generic.IEnumerable<IConnectionFactory> svs = 
                    sp.GetServices<IConnectionFactory>();

                foreach (IConnectionFactory thisService in svs)
                {
                    if (key.Equals(thisService.Name, StringComparison.OrdinalIgnoreCase))
                        return thisService;
                }

                return null;
            };
    });

তবে এর জন্য সম্পত্তিটি সংযুক্ত করার জন্য আপনার ইন্টারফেসটি পরিবর্তন করা দরকার, এবং অনেকগুলি উপাদানগুলির মধ্য দিয়ে লুপিংয়ের জন্য এসোসিয়েটিভ-অ্যারে লুচিং (অভিধান) এর চেয়ে অনেক ধীর হওয়া উচিত।
যদিও এটি জেনে রাখা যায় যে এটি ডিকশনারি ছাড়াই করা যায়।

এগুলি কেবল আমার 0.05 ডলার


পরিষেবা যদি IDisposeবাস্তবায়িত হয়ে থাকে তবে পরিষেবাটি নিষ্পত্তি করার দায় কে? আপনি Singleton
অভিধানটি

@ এলপি 13: আপনি কোনও ডেলিগেটের সাথে মান হিসাবে অভিধানও নিবন্ধভুক্ত করতে পারেন, তারপরে আপনি এটির জন্য এটি নিবন্ধভুক্ত করতে পারেন এবং একটি নতুন উদাহরণ তৈরি করতে পারেন, যেমন। গেটআরকিয়ারড সার্ভিস <টি> () ["লগডিবি"] ()
স্টিফান স্টিগার

5

উপরের আমার পোস্টটি থেকে, আমি জেনেরিক কারখানার ক্লাসে চলে এসেছি

ব্যবহার

 services.AddFactory<IProcessor, string>()
         .Add<ProcessorA>("A")
         .Add<ProcessorB>("B");

 public MyClass(IFactory<IProcessor, string> processorFactory)
 {
       var x = "A"; //some runtime variable to select which object to create
       var processor = processorFactory.Create(x);
 }

বাস্তবায়ন

public class FactoryBuilder<I, P> where I : class
{
    private readonly IServiceCollection _services;
    private readonly FactoryTypes<I, P> _factoryTypes;
    public FactoryBuilder(IServiceCollection services)
    {
        _services = services;
        _factoryTypes = new FactoryTypes<I, P>();
    }
    public FactoryBuilder<I, P> Add<T>(P p)
        where T : class, I
    {
        _factoryTypes.ServiceList.Add(p, typeof(T));

        _services.AddSingleton(_factoryTypes);
        _services.AddTransient<T>();
        return this;
    }
}
public class FactoryTypes<I, P> where I : class
{
    public Dictionary<P, Type> ServiceList { get; set; } = new Dictionary<P, Type>();
}

public interface IFactory<I, P>
{
    I Create(P p);
}

public class Factory<I, P> : IFactory<I, P> where I : class
{
    private readonly IServiceProvider _serviceProvider;
    private readonly FactoryTypes<I, P> _factoryTypes;
    public Factory(IServiceProvider serviceProvider, FactoryTypes<I, P> factoryTypes)
    {
        _serviceProvider = serviceProvider;
        _factoryTypes = factoryTypes;
    }

    public I Create(P p)
    {
        return (I)_serviceProvider.GetService(_factoryTypes.ServiceList[p]);
    }
}

প্রসার

namespace Microsoft.Extensions.DependencyInjection
{
    public static class DependencyExtensions
    {
        public static IServiceCollection AddFactory<I, P>(this IServiceCollection services, Action<FactoryBuilder<I, P>> builder)
            where I : class
        {
            services.AddTransient<IFactory<I, P>, Factory<I, P>>();
            var factoryBuilder = new FactoryBuilder<I, P>(services);
            builder(factoryBuilder);
            return services;
        }
    }
}

আপনি কি সরবরাহ করতে পারবেন? অ্যাডফ্যাক্টরি () পদ্ধতি এক্সটেনশন?
বিকাশকারী

দুঃখিত, এটি দেখেছি ... যুক্ত হয়েছে
টি ব্রাউন

3

যদিও এটি মনে হচ্ছে @ মিগুয়েল এ। অ্যারিলা এটি পরিষ্কারভাবে উল্লেখ করেছেন এবং আমি তার পক্ষে ভোট দিয়েছি, আমি তার দরকারী সমাধানের উপরে একটি আরও সমাধান তৈরি করেছি যা পরিষ্কার দেখায় তবে আরও অনেক কাজ প্রয়োজন।

এটি অবশ্যই উপরের সমাধানের উপর নির্ভর করে। সুতরাং মূলত আমি এর অনুরূপ কিছু তৈরি করেছি Func<string, IService>>এবং আমি এটিকে IServiceAccessorএকটি ইন্টারফেস হিসাবে ডেকেছিলাম এবং তারপরে আমাকে আরও কিছু এক্সটেনশন যুক্ত করতে হয়েছিল IServiceCollection:

public static IServiceCollection AddSingleton<TService, TImplementation, TServiceAccessor>(
            this IServiceCollection services,
            string instanceName
        )
            where TService : class
            where TImplementation : class, TService
            where TServiceAccessor : class, IServiceAccessor<TService>
        {
            services.AddSingleton<TService, TImplementation>();
            services.AddSingleton<TServiceAccessor>();
            var provider = services.BuildServiceProvider();
            var implementationInstance = provider.GetServices<TService>().Last();
            var accessor = provider.GetServices<TServiceAccessor>().First();

            var serviceDescriptors = services.Where(d => d.ServiceType == typeof(TServiceAccessor));
            while (serviceDescriptors.Any())
            {
                services.Remove(serviceDescriptors.First());
            }

            accessor.SetService(implementationInstance, instanceName);
            services.AddSingleton<TServiceAccessor>(prvd => accessor);
            return services;
        }

পরিষেবা অ্যাকসেসরের মত দেখাচ্ছে:

 public interface IServiceAccessor<TService>
    {
         void Register(TService service,string name);
         TService Resolve(string name);

    }

শেষ ফলাফল, আপনি নাম বা নামযুক্ত উদাহরণ সহ পরিষেবাগুলি নিবন্ধ করতে সক্ষম হবেন যেমন আমরা অন্যান্য ধারকগুলির সাথে করতাম.. যেমন:

    services.AddSingleton<IEncryptionService, SymmetricEncryptionService, EncyptionServiceAccessor>("Symmetric");
    services.AddSingleton<IEncryptionService, AsymmetricEncryptionService, EncyptionServiceAccessor>("Asymmetric");

এটি আপাতত যথেষ্ট, তবে আপনার কাজটি সম্পূর্ণ করার জন্য, একই পদ্ধতির অনুসরণ করে সমস্ত ধরণের নিবন্ধগুলি কভার করতে আপনি আরও এক্সটেনশন পদ্ধতি যুক্ত করা ভাল।

স্ট্যাকওভারফ্লোতে আরও একটি পোস্ট ছিল, তবে আমি এটি খুঁজে পাচ্ছি না, যেখানে পোস্টারটি ব্যাখ্যা করেছে যে কেন এই বৈশিষ্ট্যটি সমর্থন করা হচ্ছে না এবং কীভাবে এটি চারপাশে কাজ করা যায়, মূলত @ মিগুয়েলের বক্তব্য অনুসারে। যদিও আমি প্রতিটি পয়েন্টের সাথে একমত নই যদিও এটি দুর্দান্ত পোস্ট ছিল কারণ আমি মনে করি এমন পরিস্থিতি রয়েছে যেখানে আপনার সত্যিকারের নামকরণের উদাহরণ প্রয়োজন। আমি আবার সেই লিঙ্কটি খুঁজে পেয়ে এখানে পোস্ট করব।

প্রকৃতপক্ষে, আপনাকে সেই নির্বাচক বা অ্যাকসেসর পাস করার দরকার নেই:

আমি আমার প্রকল্পে নিম্নলিখিত কোড ব্যবহার করছি এবং এটি এখনও পর্যন্ত ভাল কাজ করেছে।

 /// <summary>
    /// Adds the singleton.
    /// </summary>
    /// <typeparam name="TService">The type of the t service.</typeparam>
    /// <typeparam name="TImplementation">The type of the t implementation.</typeparam>
    /// <param name="services">The services.</param>
    /// <param name="instanceName">Name of the instance.</param>
    /// <returns>IServiceCollection.</returns>
    public static IServiceCollection AddSingleton<TService, TImplementation>(
        this IServiceCollection services,
        string instanceName
    )
        where TService : class
        where TImplementation : class, TService
    {
        var provider = services.BuildServiceProvider();
        var implementationInstance = provider.GetServices<TService>().LastOrDefault();
        if (implementationInstance.IsNull())
        {
            services.AddSingleton<TService, TImplementation>();
            provider = services.BuildServiceProvider();
            implementationInstance = provider.GetServices<TService>().Single();
        }
        return services.RegisterInternal(instanceName, provider, implementationInstance);
    }

    private static IServiceCollection RegisterInternal<TService>(this IServiceCollection services,
        string instanceName, ServiceProvider provider, TService implementationInstance)
        where TService : class
    {
        var accessor = provider.GetServices<IServiceAccessor<TService>>().LastOrDefault();
        if (accessor.IsNull())
        {
            services.AddSingleton<ServiceAccessor<TService>>();
            provider = services.BuildServiceProvider();
            accessor = provider.GetServices<ServiceAccessor<TService>>().Single();
        }
        else
        {
            var serviceDescriptors = services.Where(d => d.ServiceType == typeof(IServiceAccessor<TService>));
            while (serviceDescriptors.Any())
            {
                services.Remove(serviceDescriptors.First());
            }
        }
        accessor.Register(implementationInstance, instanceName);
        services.AddSingleton<TService>(prvd => implementationInstance);
        services.AddSingleton<IServiceAccessor<TService>>(prvd => accessor);
        return services;
    }

    //
    // Summary:
    //     Adds a singleton service of the type specified in TService with an instance specified
    //     in implementationInstance to the specified Microsoft.Extensions.DependencyInjection.IServiceCollection.
    //
    // Parameters:
    //   services:
    //     The Microsoft.Extensions.DependencyInjection.IServiceCollection to add the service
    //     to.
    //   implementationInstance:
    //     The instance of the service.
    //   instanceName:
    //     The name of the instance.
    //
    // Returns:
    //     A reference to this instance after the operation has completed.
    public static IServiceCollection AddSingleton<TService>(
        this IServiceCollection services,
        TService implementationInstance,
        string instanceName) where TService : class
    {
        var provider = services.BuildServiceProvider();
        return RegisterInternal(services, instanceName, provider, implementationInstance);
    }

    /// <summary>
    /// Registers an interface for a class
    /// </summary>
    /// <typeparam name="TInterface">The type of the t interface.</typeparam>
    /// <param name="services">The services.</param>
    /// <returns>IServiceCollection.</returns>
    public static IServiceCollection As<TInterface>(this IServiceCollection services)
         where TInterface : class
    {
        var descriptor = services.Where(d => d.ServiceType.GetInterface(typeof(TInterface).Name) != null).FirstOrDefault();
        if (descriptor.IsNotNull())
        {
            var provider = services.BuildServiceProvider();
            var implementationInstance = (TInterface)provider?.GetServices(descriptor?.ServiceType)?.Last();
            services?.AddSingleton(implementationInstance);
        }
        return services;
    }

1
সার্ভিস অ্যাকসেসরের ক্ষেত্রে নিবন্ধগুলি হারাতে গিয়ে এটি আমার সমস্যার সমাধান করতে সহায়তা করেছে। কৌশলটি ছিল পরিষেবা অ্যাক্সেসরের জন্য সমস্ত বাইন্ডিংগুলি সরিয়ে ফেলা এবং তারপরে এটি আবার যুক্ত করা!
উমার ফারুক খাজা

3

আমি এর জন্য একটি লাইব্রেরি তৈরি করেছি যা কিছু সুন্দর বৈশিষ্ট্য প্রয়োগ করে। কোডটি গিটহাবটিতে পাওয়া যাবে: https://github.com/dazinator/Dazinator.Exferencess.D dependencyInication NuGet: https://www.nuget.org/packages/Dazinator.Extensions.D dependencyInication/

ব্যবহার সোজা:

  1. আপনার প্রকল্পে Dazinator.Extensions.D dependencyInication nuget প্যাকেজ যুক্ত করুন।
  2. আপনার নামযুক্ত পরিষেবা নিবন্ধগুলি যুক্ত করুন।
    var services = new ServiceCollection();
    services.AddNamed<AnimalService>(names =>
    {
        names.AddSingleton("A"); // will resolve to a singleton instance of AnimalService
        names.AddSingleton<BearService>("B"); // will resolve to a singleton instance of BearService (which derives from AnimalService)
        names.AddSingleton("C", new BearService()); will resolve to singleton instance provided yourself.
        names.AddSingleton("D", new DisposableTigerService(), registrationOwnsInstance = true); // will resolve to singleton instance provided yourself, but will be disposed for you (if it implements IDisposable) when this registry is disposed (also a singleton).

        names.AddTransient("E"); // new AnimalService() every time..
        names.AddTransient<LionService>("F"); // new LionService() every time..

        names.AddScoped("G");  // scoped AnimalService
        names.AddScoped<DisposableTigerService>("H");  scoped DisposableTigerService and as it implements IDisposable, will be disposed of when scope is disposed of.

    });

উপরের উদাহরণে লক্ষ করুন যে প্রতিটি নাম রেজিস্ট্রেশনের জন্য আপনি আজীবন বা সিঙ্গেলটন, স্কোপড বা ট্রান্সিয়েন্ট নির্দিষ্ট করে দিচ্ছেন।

আপনি এই পরিষেবাগুলির এই প্যাকেজের উপর নির্ভরতা না রাখার বিষয়ে যদি আপনার স্বাচ্ছন্দ্য বোধ করেন তবে তার উপর নির্ভর করে আপনি দুটি পদ্ধতির একটিতে পরিষেবাগুলি সমাধান করতে পারেন:

public MyController(Func<string, AnimalService> namedServices)
{
   AnimalService serviceA = namedServices("A");
   AnimalService serviceB = namedServices("B"); // BearService derives from AnimalService
}

অথবা

public MyController(NamedServiceResolver<AnimalService> namedServices)
{
   AnimalService serviceA = namedServices["A"];
   AnimalService serviceB = namedServices["B"]; // instance of BearService returned derives from AnimalService
}

মাইক্রোসফ্টের সাথে ভালভাবে কাজ করার জন্য আমি এই লাইব্রেরিটি বিশেষভাবে ডিজাইন করেছি x এক্সটেনশনগুলি epend নির্ভরতা ইনজেকশন - উদাহরণস্বরূপ:

  1. আপনি নামে সেবা রেজিস্টার করো, তখন কোনো ধরনের যে আপনি রেজিস্টার পরামিতি সঙ্গে কনস্ট্রাকটর থাকতে পারে - তারা, দ্বি মাধ্যমে সন্তুষ্ট হতে হবে একই ভাবে যে AddTransient<>, AddScoped<>এবং AddSingleton<>পদ্ধতি সচরাচর কাজ করি।

  2. ক্ষণস্থায়ী এবং স্কোপযুক্ত নামযুক্ত পরিষেবার জন্য, রেজিস্ট্রি ObjectFactoryএমন একটি তৈরি করে যাতে এটি যখন প্রয়োজন হয় তখন খুব দ্রুত নতুন ধরণের ঘটনা সক্রিয় করতে পারে। এটি অন্যান্য পদ্ধতির তুলনায় অনেক দ্রুত এবং মাইক্রোসফ্ট. এক্সটেনশনগুলি। নির্ভরতা ইনজেকশনগুলি কীভাবে কাজ করে তার সাথে সামঞ্জস্য।


2

এটির মূল্যবান জন্য আমার সমাধান ... ক্যাসেল উইন্ডসর এ স্যুইচ করা বিবেচনা করা যায় না কারণ এটি উপরের সমাধানগুলির মধ্যে আমার কোনও পছন্দ পছন্দ করে না। দুঃখিত !!

public interface IStage<out T> : IStage { }

public interface IStage {
      void DoSomething();
}

আপনার বিভিন্ন বাস্তবায়ন তৈরি করুন

public class YourClassA : IStage<YouClassA> { 
    public void DoSomething() 
    {
        ...TODO
    }
}

public class YourClassB : IStage<YourClassB> { .....etc. }

নিবন্ধন

services.AddTransient<IStage<YourClassA>, YourClassA>()
services.AddTransient<IStage<YourClassB>, YourClassB>()

নির্মাতা এবং উদাহরণ ব্যবহার ...

public class Whatever
{
   private IStage ClassA { get; }

   public Whatever(IStage<YourClassA> yourClassA)
   {
         ClassA = yourClassA;
   }

   public void SomeWhateverMethod()
   {
        ClassA.DoSomething();
        .....
   }

1

@Rnrneverdies এর সমাধান বাড়ানো হচ্ছে। টসস্ট্রিং () এর পরিবর্তে, নিম্নলিখিত বিকল্পগুলিও ব্যবহার করা যেতে পারে- 1) সাধারণ সম্পত্তি বাস্তবায়নের সাথে, ২) @ ক্রেইগ ব্রুনেটি প্রস্তাবিত একটি পরিষেবা।

public interface IService { }
public class ServiceA : IService
{
    public override string ToString()
    {
        return "A";
    }
}

public class ServiceB : IService
{
    public override string ToString()
    {
        return "B";
    }

}

/// <summary>
/// extension method that compares with ToString value of an object and returns an object if found
/// </summary>
public static class ServiceProviderServiceExtensions
{
    public static T GetService<T>(this IServiceProvider provider, string identifier)
    {
        var services = provider.GetServices<T>();
        var service = services.FirstOrDefault(o => o.ToString() == identifier);
        return service;
    }
}

public void ConfigureServices(IServiceCollection services)
{
    //Initials configurations....

    services.AddSingleton<IService, ServiceA>();
    services.AddSingleton<IService, ServiceB>();
    services.AddSingleton<IService, ServiceC>();

    var sp = services.BuildServiceProvider();
    var a = sp.GetService<IService>("A"); //returns instance of ServiceA
    var b = sp.GetService<IService>("B"); //returns instance of ServiceB

    //Remaining configurations....
}

1

উত্তর এবং অন্যত্র নিবন্ধগুলি পড়ার পরে আমি এটি স্ট্রিং ছাড়াই কাজ করতে সক্ষম হয়েছি। আপনার যখন একই ইন্টারফেসের একাধিক বাস্তবায়ন হবে তখন ডিআই এগুলি একটি সংকলনে যুক্ত করবে, সুতরাং সংগ্রহ থেকে আপনি যে সংস্করণটি ব্যবহার করছেন তা ব্যবহার করে এটি ব্যবহার সম্ভব typeof

// In Startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped(IService, ServiceA);
    services.AddScoped(IService, ServiceB);
    services.AddScoped(IService, ServiceC);
}

// Any class that uses the service(s)
public class Consumer
{
    private readonly IEnumerable<IService> _myServices;

    public Consumer(IEnumerable<IService> myServices)
    {
        _myServices = myServices;
    }

    public UseServiceA()
    {
        var serviceA = _myServices.FirstOrDefault(t => t.GetType() == typeof(ServiceA));
        serviceA.DoTheThing();
    }

    public UseServiceB()
    {
        var serviceB = _myServices.FirstOrDefault(t => t.GetType() == typeof(ServiceB));
        serviceB.DoTheThing();
    }

    public UseServiceC()
    {
        var serviceC = _myServices.FirstOrDefault(t => t.GetType() == typeof(ServiceC));
        serviceC.DoTheThing();
    }
}

আইওসির উদ্দেশ্যকে পরাস্ত করে। আপনি পাশাপাশি কেবল লিখতে পারেন:var serviceA = new ServiceA();
জেমস কারান 20

2
@ জেমস কররান যদি সার্ভিসএর নির্ভরতা থাকে বা আপনি ক্লাস পরীক্ষা করতে চান তবে তা নয়।
জর্ন.বিয়ার্স

0

বাক্সটি প্রয়োগের বাইরে এটি প্রস্তাব দেয় না, এখানে একটি নমুনা প্রকল্প রয়েছে যা আপনাকে নামযুক্ত উদাহরণগুলি নিবন্ধকরণ করতে এবং তারপরে আপনার কোডে ইনমেড সার্ভিস ফ্যাক্টরী ইনজেক্ট করতে এবং নাম অনুসারে দৃষ্টান্তগুলি বের করতে সহায়তা করে। এখানে অন্যান্য বিষয়গুলির সমাধানগুলির মতো নয়, এটি আপনাকে একই বাস্তবায়নের একাধিক উদাহরণ নিবন্ধভুক্ত করার অনুমতি দেয় তবে আলাদাভাবে কনফিগার করা হয়েছে

https://github.com/macsux/DotNetDINamedInstances


0

পরিষেবাগুলির জন্য একটি পরিষেবা সম্পর্কে কীভাবে?

যদি আমাদের একটি আইএনমেড সার্ভিস ইন্টারফেস থাকে (.নেম সম্পত্তি সহ), আমরা .GetService (স্ট্রিং নাম) এর জন্য একটি আইসওয়ার সার্ভিস সংকলন লিখতে পারি, যেখানে এক্সটেনশানটি সেই স্ট্রিং প্যারামিটার গ্রহণ করে এবং প্রতিটি গেট সার্ভিস () নিজেই নিয়ে যায় এবং প্রতিটিটিতেই ফিরে আসে উদাহরণস্বরূপ, আইএনমেড সার্ভিস.নাম প্রদত্ত নামের সাথে মেলে এমন উদাহরণটি সন্ধান করুন।

এটার মত:

public interface INamedService
{
    string Name { get; }
}

public static T GetService<T>(this IServiceProvider provider, string serviceName)
    where T : INamedService
{
    var candidates = provider.GetServices<T>();
    return candidates.FirstOrDefault(s => s.Name == serviceName);
}

অতএব, আপনার আইএমআই সার্ভিস অবশ্যই আইএনমেড সার্ভিস প্রয়োগ করতে হবে, তবে আপনি কী-ভিত্তিক রেজোলিউশনটি চান তা পাবেন?

সত্য কথা বলতে গেলে এমনকি এই আইএনমেড সার্ভিস ইন্টারফেসটি দেখতে কুৎসিত মনে হয়, তবে আপনি যদি আরও এগিয়ে গিয়ে বিষয়গুলি আরও মার্জিত করে তুলতে চান তবে বাস্তবায়ন / শ্রেণীর উপর একটি [নামযুক্ত সার্ভিসঅ্যাট্রিবিউট ("এ")] এর কোড অনুসারে পাওয়া যেতে পারে এক্সটেনশান, এবং এটি ঠিক কাজ করবে। আরও সুস্পষ্ট হওয়ার জন্য, প্রতিবিম্বটি ধীরে ধীরে, তাই একটি অপ্টিমাইজেশন ক্রমযুক্ত হতে পারে তবে সত্যই এটি ডিআই ইঞ্জিনটি সাহায্য করবে। গতি এবং সরলতা টিসিওতে প্রতিটি গ্র্যান্ড অবদানকারী।

সর্বোপরি, একটি সুস্পষ্ট কারখানার প্রয়োজন নেই, কারণ "একটি নামযুক্ত পরিষেবা সন্ধান করা" এটি একটি পুনরায় ব্যবহারযোগ্য ধারণা এবং কারখানার ক্লাসগুলি সমাধান হিসাবে স্কেল করে না। এবং একটি ফানক <> ঠিক আছে বলে মনে হচ্ছে, তবে একটি স্যুইচ ব্লকটি খুব রক্তাক্ত এবং আবারও, আপনি যতক্ষণ ফ্যাক্টরি লিখতে চাইছেন ততবার আপনি ফানকস লিখবেন। কম কোড সহ সহজ, পুনরায় ব্যবহারযোগ্য, শুরু করুন এবং যদি এটির জন্য এটি না করা হয়ে যায়, তবে জটিল হয়ে যান।


2
এটিকে সার্ভিস লোকেটার প্যাটার্ন বলা হয় এবং সাধারণত একেবারে না চলতে
জো ফিলিপস

@ জোফিলিপস কেন আপনার কোনও ইনপুট রয়েছে কেন এটি ভাল সমাধান নয়? আমি এর কমনীয়তা পছন্দ। আমি কেবলমাত্র খারাপ দিকটিই ভাবতে পারি তা হ'ল আমি যখনই আপনি পেয়ে যাব প্রত্যেকটির একটি উদাহরণ তৈরি করি।
পিটার

2
@ পিটার মূল কারণ কারণ এটির সাথে কাজ করা খুব কঠিন। আপনি যদি কোনও সার্ভিস লোকেটর অবজেক্টে কোনও শ্রেণিতে চলে যাচ্ছেন, তবে শ্রেণিটি যে ম্যাজিক "godশ্বর" অবজেক্ট থেকে সমস্ত পেয়েছে সেগুলি শ্রেণীর কী নির্ভরতা ব্যবহার করে তা স্পষ্ট নয়। আপনি যে ধরণের পরিবর্তন করতে চান তার রেফারেন্সগুলি সন্ধান করুন gine আপনি যখন সার্ভিস লোকেটার অবজেক্টের মাধ্যমে সমস্ত কিছু পেয়ে যাচ্ছেন তখন সেই ক্ষমতাটি মূলত অদৃশ্য হয়ে যায়। কনস্ট্রাক্টর ইঞ্জেকশনটি আরও বেশি স্পষ্ট এবং নির্ভরযোগ্য
জো ফিলিপস

আমি জানিনা. সুস্পষ্টতা আমার পক্ষে বিয়োগ নয় ... কারণ যদি আমি আমার উপাদানগুলি কীভাবে তাদের নির্ভরতা লাভ করি সে সম্পর্কে নজর রাখি, তবে তার জন্য আমার ইউনিট পরীক্ষা ছিল ... পরীক্ষাগুলি যা কেবল প্রতিটি নির্ভরতা বোঝায় না, তবে আমাদের বুঝতে সহায়তা করে প্রতিটি নির্ভরতা কিভাবে প্রয়োজন। আর কীভাবে আপনি সচেতন হতে যাচ্ছেন, কনস্ট্রাক্টর পড়ে?!?
ক্রেগ ব্রুনেটি

0

আমি একই সমস্যায় পড়েছি এবং নামযুক্ত পরিষেবাদিগুলির অনুমতি দেওয়ার জন্য আমি একটি সাধারণ বর্ধনের সাথে কাজ করেছি। আপনি এখানে পেতে পারেন:

এটি আপনাকে এটির মতো বেশি (নামযুক্ত) পরিষেবা যুক্ত করতে দেয়:

 var serviceCollection = new ServiceCollection();
 serviceCollection.Add(typeof(IMyService), typeof(MyServiceA), "A", ServiceLifetime.Transient);
 serviceCollection.Add(typeof(IMyService), typeof(MyServiceB), "B", ServiceLifetime.Transient);

 var serviceProvider = serviceCollection.BuildServiceProvider();

 var myServiceA = serviceProvider.GetService<IMyService>("A");
 var myServiceB = serviceProvider.GetService<IMyService>("B");

লাইব্রেরি আপনাকে সহজে "ফ্যাক্টরি ধাঁচ" এর মতো সহজে প্রয়োগ করতে দেয়:

    [Test]
    public void FactoryPatternTest()
    {
        var serviceCollection = new ServiceCollection();
        serviceCollection.Add(typeof(IMyService), typeof(MyServiceA), MyEnum.A.GetName(), ServiceLifetime.Transient);
        serviceCollection.Add(typeof(IMyService), typeof(MyServiceB), MyEnum.B.GetName(), ServiceLifetime.Transient);

        serviceCollection.AddTransient<IMyServiceFactoryPatternResolver, MyServiceFactoryPatternResolver>();

        var serviceProvider = serviceCollection.BuildServiceProvider();

        var factoryPatternResolver = serviceProvider.GetService<IMyServiceFactoryPatternResolver>();

        var myServiceA = factoryPatternResolver.Resolve(MyEnum.A);
        Assert.NotNull(myServiceA);
        Assert.IsInstanceOf<MyServiceA>(myServiceA);

        var myServiceB = factoryPatternResolver.Resolve(MyEnum.B);
        Assert.NotNull(myServiceB);
        Assert.IsInstanceOf<MyServiceB>(myServiceB);
    }

    public interface IMyServiceFactoryPatternResolver : IFactoryPatternResolver<IMyService, MyEnum>
    {
    }

    public class MyServiceFactoryPatternResolver : FactoryPatternResolver<IMyService, MyEnum>, IMyServiceFactoryPatternResolver
    {
        public MyServiceFactoryPatternResolver(IServiceProvider serviceProvider)
        : base(serviceProvider)
        {
        }
    }

    public enum MyEnum
    {
        A = 1,
        B = 2
    }

আশা করি এটা সাহায্য করবে


0

IServiceCollectionব্যবহৃত WithNameএক্সটেনশনের উপরে আমি আমার নিজস্ব এক্সটেনশন তৈরি করেছি :

public static IServiceCollection AddScopedWithName<TService, TImplementation>(this IServiceCollection services, string serviceName)
        where TService : class
        where TImplementation : class, TService
    {
        Type serviceType = typeof(TService);
        Type implementationServiceType = typeof(TImplementation);
        ServiceCollectionTypeMapper.Instance.AddDefinition(serviceType.Name, serviceName, implementationServiceType.AssemblyQualifiedName);
        services.AddScoped<TImplementation>();
        return services;
    }

ServiceCollectionTypeMapperএকটি Singleton উদাহরণস্বরূপ মানচিত্রগুলি যে IService> NameOfService> Implementationযেখানে একটি ইন্টারফেস বিভিন্ন নাম অনেক বাস্তবায়নের থাকতে পারে, এই তুলনায় আমরা সমাধান যখন পুঁচকে প্রয়োজন এবং সমাধান একাধিক পরিষেবার চেয়ে ভিন্ন পদ্ধতির নির্বাচন করতে আমরা যা চাই করতে ধরনের নিবন্ধন করতে পারেন।

 /// <summary>
/// Allows to set the service register mapping.
/// </summary>
public class ServiceCollectionTypeMapper
{
    private ServiceCollectionTypeMapper()
    {
        this.ServiceRegister = new Dictionary<string, Dictionary<string, string>>();
    }

    /// <summary>
    /// Gets the instance of mapper.
    /// </summary>
    public static ServiceCollectionTypeMapper Instance { get; } = new ServiceCollectionTypeMapper();

    private Dictionary<string, Dictionary<string, string>> ServiceRegister { get; set; }

    /// <summary>
    /// Adds new service definition.
    /// </summary>
    /// <param name="typeName">The name of the TService.</param>
    /// <param name="serviceName">The TImplementation name.</param>
    /// <param name="namespaceFullName">The TImplementation AssemblyQualifiedName.</param>
    public void AddDefinition(string typeName, string serviceName, string namespaceFullName)
    {
        if (this.ServiceRegister.TryGetValue(typeName, out Dictionary<string, string> services))
        {
            if (services.TryGetValue(serviceName, out _))
            {
                throw new InvalidOperationException($"Exists an implementation with the same name [{serviceName}] to the type [{typeName}].");
            }
            else
            {
                services.Add(serviceName, namespaceFullName);
            }
        }
        else
        {
            Dictionary<string, string> serviceCollection = new Dictionary<string, string>
            {
                { serviceName, namespaceFullName },
            };
            this.ServiceRegister.Add(typeName, serviceCollection);
        }
    }

    /// <summary>
    /// Get AssemblyQualifiedName of implementation.
    /// </summary>
    /// <typeparam name="TService">The type of the service implementation.</typeparam>
    /// <param name="serviceName">The name of the service.</param>
    /// <returns>The AssemblyQualifiedName of the inplementation service.</returns>
    public string GetService<TService>(string serviceName)
    {
        Type serviceType = typeof(TService);

        if (this.ServiceRegister.TryGetValue(serviceType.Name, out Dictionary<string, string> services))
        {
            if (services.TryGetValue(serviceName, out string serviceImplementation))
            {
                return serviceImplementation;
            }
            else
            {
                return null;
            }
        }
        else
        {
            return null;
        }
    }

একটি নতুন পরিষেবা নিবন্ধন করতে:

services.AddScopedWithName<IService, MyService>("Name");

সমাধান সেবার আমরা ধরে একটি এক্সটেনশন প্রয়োজন IServiceProviderভালো।

/// <summary>
    /// Gets the implementation of service by name.
    /// </summary>
    /// <typeparam name="T">The type of service.</typeparam>
    /// <param name="serviceProvider">The service provider.</param>
    /// <param name="serviceName">The service name.</param>
    /// <returns>The implementation of service.</returns>
    public static T GetService<T>(this IServiceProvider serviceProvider, string serviceName)
    {
        string fullnameImplementation = ServiceCollectionTypeMapper.Instance.GetService<T>(serviceName);
        if (fullnameImplementation == null)
        {
            throw new InvalidOperationException($"Unable to resolve service of type [{typeof(T)}] with name [{serviceName}]");
        }
        else
        {
            return (T)serviceProvider.GetService(Type.GetType(fullnameImplementation));
        }
    }

যখন সমাধান:

serviceProvider.GetService<IWithdrawalHandler>(serviceName);

মনে রাখবেন যে সার্ভিস প্রোভাইডারটি আমাদের অ্যাপ্লিকেশনটিতে কোনও কনস্ট্রাক্টরের মধ্যে ইনজেকশন দেওয়া যেতে পারে IServiceProvider

আশা করি এটা কাজে লাগবে.

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.