আমি কীভাবে আমার ডাব্লুসিএফ পরিষেবাটিতে কনস্ট্রাক্টরের কাছে মানগুলি পাস করব?


103

আমি ক্লাসে কনস্ট্রাক্টরের মধ্যে মানগুলি পাস করতে চাই যা আমার পরিষেবা প্রয়োগ করে।

তবে সার্ভিস হস্ট আমাকে কেবল প্রকারের নামে তৈরি করতে দেয়, তার কনস্ট্রাক্টর্টর কাছে কোন যুক্তি দিতে হবে তা নয়।

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

আমি এ পর্যন্ত যা খুঁজে পেয়েছি:


6
আমি আশঙ্কা করছি যে জটিলতা ডাব্লুসিএফের অন্তর্নিহিত এবং ডাব্লুসিএফ ব্যবহার না করা বা এটি আরও ব্যবহারকারীর বান্ধব সম্মুখভাগের আড়াল না করে যেমন উইন্ডসর এর ডাব্লুসিএফ সুবিধা আপনি উইন্ডসর ব্যবহার করছেন
Krzysztof Kozmic এর

উত্তর:


122

আপনি কাস্টম সংমিশ্রণ বাস্তবায়ন করতে হবে ServiceHostFactory, ServiceHostএবং IInstanceProvider

এই নির্মাণকারীর স্বাক্ষর সহ একটি পরিষেবা দেওয়া হয়েছে:

public MyService(IDependency dep)

এখানে মাই সার্ভিস স্পিন করতে পারে এমন একটি উদাহরণ:

public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IDependency dep;

    public MyServiceHostFactory()
    {
        this.dep = new MyClass();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType,
        Uri[] baseAddresses)
    {
        return new MyServiceHost(this.dep, serviceType, baseAddresses);
    }
}

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(IDependency dep, Type serviceType, params Uri[] baseAddresses)
        : base(serviceType, baseAddresses)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        foreach (var cd in this.ImplementedContracts.Values)
        {
            cd.Behaviors.Add(new MyInstanceProvider(dep));
        }
    }
}

public class MyInstanceProvider : IInstanceProvider, IContractBehavior
{
    private readonly IDependency dep;

    public MyInstanceProvider(IDependency dep)
    {
        if (dep == null)
        {
            throw new ArgumentNullException("dep");
        }

        this.dep = dep;
    }

    #region IInstanceProvider Members

    public object GetInstance(InstanceContext instanceContext, Message message)
    {
        return this.GetInstance(instanceContext);
    }

    public object GetInstance(InstanceContext instanceContext)
    {
        return new MyService(this.dep);
    }

    public void ReleaseInstance(InstanceContext instanceContext, object instance)
    {
        var disposable = instance as IDisposable;
        if (disposable != null)
        {
            disposable.Dispose();
        }
    }

    #endregion

    #region IContractBehavior Members

    public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters)
    {
    }

    public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
    }

    public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime)
    {
        dispatchRuntime.InstanceProvider = this;
    }

    public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint)
    {
    }

    #endregion
}

আপনার মাই সার্ভিস.এসভিসি ফাইলে মাই সার্ভিসহোস্টফ্যাক্টরি নিবন্ধন করুন, বা স্ব-হোস্টিং পরিস্থিতিগুলির জন্য কোডটিতে সরাসরি মাই সার্ভিসহোস্ট ব্যবহার করুন।

আপনি সহজেই এই পদ্ধতিরটিকে সাধারণীকরণ করতে পারেন এবং বাস্তবে কিছু ডিআই কনটেইনার আপনার জন্য এটি ইতিমধ্যে করেছে (সংকেত: উইন্ডসর এর ডাব্লুসিএফ সুবিধা)।


+1 (তবে ইয়াক, # অঞ্চলগুলি যদিও এটি অপরাধের সর্বনিম্ন গুরুতর ঘটনা, আমি স্পষ্টভাবে ইন্টারফেসে নিজেকে রূপান্তর করি: পি)
রুবেন বারটেলিংক

5
আমি কীভাবে এটি স্ব হোস্টিংয়ের জন্য ব্যবহার করতে পারি? ক্রিয়েট সার্ভিসহোস্টে কল করার পরে আমি একটি ব্যতিক্রম পাই। আমি কেবল সুরক্ষিত পদ্ধতিতে সর্বজনীন ওভাররাইড সার্ভিস হোস্টবেস ক্রিয়েট সার্ভিসহোস্টে কল করতে পারি (স্ট্রিং কনস্ট্রাক্টরস্ট্রিং, উরি [] বেসএড্রেসস); ব্যতিক্রমটি হ'ল ব্যতিক্রম বার্তাটি ছিল: 'সার্ভিস হস্টফ্যাক্টরি .ক্রেটসোর্সহোস্ট' বর্তমান হোস্টিং পরিবেশের মধ্যেই প্রার্থনা করা যাবে না। এই এপিআইয়ের প্রয়োজন যে কলিং অ্যাপ্লিকেশনটি আইআইএস বা ডাব্লুএসএতে হোস্ট করা উচিত।
গাই

2
@ গুয় আমার নমুনা সমস্যা হচ্ছে। কারণ ফাংশনটি protectedআমি নিজেকে মেইন () থেকে কল করতে পারি না
অ্যান্ড্রি দ্রোজডিয়ুক

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

2
@ মার্কসিম্যান আমি কেবল ভাবছি, আপনি কেন depপ্রতিটি চুক্তির ইনস্ট্যান্সপ্রোভাডার ইনজেক্ট করলেন । আপনি করতে পারেন: ImplementedContracts.Values.First(c => c.Name == "IMyService").ContractBehaviors.Add(new MyInstanceProvider(dep));যেখানে IMyService আপনার একটি চুক্তি ইন্টারফেস MyService(IDependency dep)। সুতরাং IDependencyকেবল ইনস্ট্যান্সপ্রোভাইডারে ইনজেক্ট করুন যা আসলে এটির প্রয়োজন।
ভয়েটেক

14

আপনি কেবল নিজের উদাহরণটি তৈরি করতে পারেন এবং Serviceসেই উদাহরণটি ServiceHostঅবজেক্টে পাস করতে পারেন । আপনাকে কেবলমাত্র যা করতে হবে তা হল [ServiceBehaviour]আপনার পরিষেবার জন্য একটি অ্যাট্রিবিউট যুক্ত করা এবং সমস্ত ফিরে আসা অবজেক্টগুলিকে [DataContract]অ্যাট্রিবিউট দিয়ে চিহ্নিত করা।

এখানে একটি উপহাস:

namespace Service
{
    [ServiceContract]
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class MyService
    {
        private readonly IDependency _dep;

        public MyService(IDependency dep)
        {
            _dep = dep;
        }

        public MyDataObject GetData()
        {
            return _dep.GetData();
        }
    }

    [DataContract]
    public class MyDataObject
    {
        public MyDataObject(string name)
        {
            Name = name;
        }

        public string Name { get; private set; }
    }

    public interface IDependency
    {
        MyDataObject GetData();
    }
}

এবং ব্যবহার:

var dep = new Dependecy();
var myService = new MyService(dep);
var host = new ServiceHost(myService);

host.Open();

আমি আশা করি এটি কারওর জন্য জীবন সহজ করে দেবে।


5
এটি কেবল সিলেটলেটনের জন্য কাজ করে (যেমন নির্দেশিত InstanceContextMode.Single)।
জন রেনল্ডস

11

মার্কের সাথে উত্তরটি IInstanceProviderসঠিক।

কাস্টম সার্ভিস হস্টফ্যাক্টরি ব্যবহার না করে আপনি একটি কাস্টম বৈশিষ্ট্য (বলুন MyInstanceProviderBehaviorAttribute) ব্যবহার করতে পারেন । এটি থেকে উত্পন্ন Attribute, এটিকে কার্যকর করার মতো পদ্ধতিটি বাস্তবায়ন IServiceBehaviorএবং প্রয়োগ করুনIServiceBehavior.ApplyDispatchBehavior

// YourInstanceProvider implements IInstanceProvider
var instanceProvider = new YourInstanceProvider(<yourargs>);

foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
{
    foreach (var epDispatcher in dispatcher.Endpoints)
    {
        // this registers your custom IInstanceProvider
        epDispatcher.DispatchRuntime.InstanceProvider = instanceProvider;
    }
}

তারপরে, আপনার পরিষেবা বাস্তবায়ন ক্লাসে অ্যাট্রিবিউটটি প্রয়োগ করুন

[ServiceBehavior]
[MyInstanceProviderBehavior(<params as you want>)]
public class MyService : IMyContract

তৃতীয় বিকল্প: আপনি কনফিগারেশন ফাইল ব্যবহার করে কোনও পরিষেবা আচরণ প্রয়োগ করতে পারেন।


2
প্রযুক্তিগতভাবে, এটিও একটি সমাধানের মতো দেখায়, তবে সেই পদ্ধতির সাথে, আপনি পরিষেবাটির সাথে IInstanceProvider কে দৃly়ভাবে জুটি দিন।
মার্ক Seemann

2
মাত্র একটি দ্বিতীয় বিকল্প, এর চেয়ে ভাল এর মূল্যায়ন নেই। আমি কাস্টম সার্ভিস হস্টফ্যাক্টরি কয়েকবার ব্যবহার করেছি (বিশেষত যখন আপনি বেশ কয়েকটি আচরণ নিবন্ধন করতে চান)।
ডালো

1
সমস্যাটি হ'ল আপনি উদাহরণস্বরূপ ডিআই কন্টেইনারটি কেবলমাত্র অ্যাট্রিবিউট কনস্ট্রাক্টরেই শুরু করতে পারেন .. আপনি অস্তিত্বের ডেটা প্রেরণ করতে পারবেন না।
গাই

5

আমি মার্কের উত্তর থেকে কাজ করেছি, তবে (আমার দৃশ্যের জন্য) এটি অযথা জটিল ছিল। এক ServiceHostকনস্ট্রাকটর সেবা, যা আপনাকে থেকে সরাসরি মধ্যে পাস করতে পারেন একটি দৃষ্টান্ত গ্রহণ ServiceHostFactoryবাস্তবায়ন।

মার্কের উদাহরণটিকে পিগব্যাক করার জন্য এটি দেখতে এটির মতো হবে:

public class MyServiceHostFactory : ServiceHostFactory
{
    private readonly IDependency _dep;

    public MyServiceHostFactory()
    {
        _dep = new MyClass();
    }

    protected override ServiceHost CreateServiceHost(Type serviceType,
        Uri[] baseAddresses)
    {
        var instance = new MyService(_dep);
        return new MyServiceHost(instance, serviceType, baseAddresses);
    }
}

public class MyServiceHost : ServiceHost
{
    public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses)
        : base(instance, baseAddresses)
    {
    }
}

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

3

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

public class MyService : IMyService
{
    private readonly Dependencies _dependencies;

    // set this before creating service host. this can use your IOC container or whatever.
    // if you don't like the mutability shown here (IoC containers are usually immutable after being configured)
    // you can use some sort of write-once object
    // or more advanced approach like authenticated access
    public static Func<Dependencies> GetDependencies { get; set; }     
    public class Dependencies
    {
        // whatever your service needs here.
        public Thing1 Thing1 {get;}
        public Thing2 Thing2 {get;}

        public Dependencies(Thing1 thing1, Thing2 thing2)
        {
            Thing1 = thing1;
            Thing2 = thing2;
        }
    }

    public MyService ()
    {
        _dependencies = GetDependencies(); // this will blow up at run time in the exact same way your IoC container will if it hasn't been properly configured up front. NO DIFFERENCE
    }
}

পরিষেবার নির্ভরতাগুলি তার নেস্টেড Dependenciesবর্গের চুক্তিতে স্পষ্টভাবে নির্দিষ্ট করা হয়েছে । আপনি যদি কোনও আইওসি পাত্রে ব্যবহার করছেন (এমন একটি যা ইতিমধ্যে আপনার জন্য ডাব্লুসিএফ জগাখিচুড়ি ঠিক করে না), আপনি Dependenciesপরিষেবার পরিবর্তে উদাহরণটি তৈরি করতে এটি কনফিগার করতে পারেন । আপনি ডাব্লুসিএফ দ্বারা আরোপিত খুব বেশি হুপের মধ্য দিয়ে ঝাঁপিয়ে পড়ার সময় আপনার ধারকটি আপনাকে যে উষ্ণ अस्पष्ट অনুভূতি দেয় সেভাবে পান।

আমি এই পদ্ধতির উপর কোনও ঘুম হারাতে চাই না। অন্য কারও উচিত নয়। সর্বোপরি, আপনি আইওসি পাত্রে একটি বড়, চর্বিযুক্ত, প্রতিনিধিদের স্ট্যাটিক সংগ্রহ যা আপনার জন্য স্টাফ তৈরি করে। আরও একটি যুক্ত কি?


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

একবার লেখার জন্য আমার স্ট্যাকওভারফ্লো
প্রশ্নগুলি /

0

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

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

public class Service1 : MyLogicNamespace.MyService
{
    public Service1() : base(new MyDependency1(), new MyDependency2()) {}
}

মাই সার্ভিস বেস ক্লাসটি পরিষেবাটির প্রকৃত বাস্তবায়ন। এই বেস ক্লাসে প্যারামিটারলেস কনস্ট্রাক্টর থাকা উচিত নয়, তবে পরামিতিগুলির সাথে নির্ভরশীলতা গ্রহণকারী কেবল নির্মাণকারী।

আসল মাই সার্ভিসের পরিবর্তে পরিষেবাটি এই শ্রেণিটি ব্যবহার করা উচিত।

এটি একটি সহজ সমাধান এবং কবজ :-D এর মতো কাজ করে


4
আপনি সার্ভিস 1 এর নির্ভরতা থেকে ডিকপল করেননি, এটি ছিল এক প্রকার বিন্দু। আপনি কেবল সার্ভিস 1 এর জন্য কনস্ট্রাক্টরের নির্ভরতাগুলি ইনস্ট্যান্ট করেছেন, যা আপনি বেস ক্লাস ছাড়াই করতে পারেন।
সেল

0

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

public class MyServiceHost : WebServiceHost
{
    public MyServiceHost(MyService instance, Type serviceType, params Uri[] baseAddresses)
        : base(instance, baseAddresses)
    {
    }
}

এটি আইআইএসে আপনার শেষ পয়েন্টগুলির জন্য সমস্ত প্রয়োজনীয় বাইন্ডিং ইত্যাদি তৈরি করবে।


-2

আমি আমার ধরণের স্ট্যাটিক ভেরিয়েবল ব্যবহার করি। এটি সর্বোত্তম উপায় কিনা তা নিশ্চিত নন তবে এটি আমার পক্ষে কার্যকর:

public class MyServer
{   
    public static string CustomerDisplayName;
    ...
}

যখন আমি পরিষেবা হোস্ট ইনস্ট্যান্ট করি তখন আমি নিম্নলিখিতগুলি করি:

protected override void OnStart(string[] args)
{
    MyServer.CustomerDisplayName = "Test customer";

    ...

    selfHost = new ServiceHost(typeof(MyServer), baseAddress);

    ....
}

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