ডাব্লুসিএফ ক্লায়েন্ট-ব্যবহার `ব্লক ইস্যুটির জন্য সেরা কাজটি কী?


404

আমি আমার ব্লগের মধ্যে আমার ডাব্লুসিএফ পরিষেবা ক্লায়েন্টদের ইনস্ট্যান্ট করা পছন্দ করি usingকারণ এটি বাস্তবায়িত সংস্থানগুলি ব্যবহারের মানক উপায় IDisposable:

using (var client = new SomeWCFServiceClient()) 
{
    //Do something with the client 
}

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

এমএসডিএন নিবন্ধে প্রস্তাবিত কাজটি হ'ল সম্পূর্ণরূপে একটি usingব্লক ব্যবহার এড়ানো , এবং পরিবর্তে আপনার ক্লায়েন্টদের তাত্ক্ষণিকভাবে ব্যবহার করা এবং এ জাতীয় কিছু ব্যবহার করুন:

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

usingব্লকের তুলনায় , আমি মনে করি এটি কুৎসিত। এবং প্রতিবার আপনার ক্লায়েন্টের দরকার পড়ার জন্য প্রচুর কোড।

ভাগ্যক্রমে, আমি বেশ কয়েকটি অন্যান্য কাজের সন্ধান পেয়েছি, যেমন আইএসভারসিয়েন্টে এটির মতো। আপনি এটি দিয়ে শুরু করুন:

public delegate void UseServiceDelegate<T>(T proxy); 

public static class Service<T> 
{ 
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 

    public static void Use(UseServiceDelegate<T> codeBlock) 
    { 
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel(); 
        bool success = false; 
        try 
        { 
            codeBlock((T)proxy); 
            proxy.Close(); 
            success = true; 
        } 
        finally 
        { 
            if (!success) 
            { 
                proxy.Abort(); 
            } 
        } 
     } 
} 

যা তখন অনুমতি দেয়:

Service<IOrderService>.Use(orderService => 
{ 
    orderService.PlaceOrder(request); 
}); 

এটি খারাপ নয়, তবে আমি মনে করি না যে এটি usingব্লকের মতোই অভিব্যক্তিপূর্ণ এবং সহজেই বোধগম্য ।

আমি বর্তমানে যে ওয়ার্কআউন্ডটি ব্যবহার করার চেষ্টা করছি সেটি প্রথম আমি ব্লগ.ড্যাভিডবারেট.এন.এ পড়লাম । মূলত আপনি ক্লায়েন্টের Dispose()পদ্ধতিটি যেখানেই ব্যবহার করুন সেখানে ওভাররাইড করুন । কিছুটা এইরকম:

public partial class SomeWCFServiceClient : IDisposable
{
    void IDisposable.Dispose() 
    {
        if (this.State == CommunicationState.Faulted) 
        {
            this.Abort();
        } 
        else 
        {
            this.Close();
        }
    }
}

এটি usingত্রুটিযুক্ত রাষ্ট্র ব্যতিক্রমকে মুখোশের ঝুঁকি ছাড়াই আবার ব্লকটিকে অনুমতি দিতে সক্ষম বলে মনে হয় ।

সুতরাং, এই কাজের ক্ষেত্রগুলি ব্যবহার করার জন্য আমাকে খুঁজে বের করতে হবে এমন আরও কোনও গটচ আছে? কেউ কি আরও ভাল কিছু নিয়ে এসেছেন?


42
শেষটি (যা এটি পর্যালোচনা করে) স্টেটটি একটি জাতি; আপনি বুলিয়ানটি পরীক্ষা করার সময় এটির ত্রুটিযুক্ত নাও হতে পারে, তবে আপনি ক্লোজ () কল করার সময় ত্রুটিযুক্ত হতে পারে।
ব্রায়ান

15
আপনি রাষ্ট্র পড়া; এটা দোষযুক্ত না। আপনি ক্লোজ () কল করার আগে চ্যানেলটি ত্রুটিযুক্ত। বন্ধ () নিক্ষেপ খেলা শেষ.
ব্রায়ান

4
সময় কেটে যায়। এটি খুব স্বল্প সময়ের হতে পারে তবে প্রযুক্তিগতভাবে চ্যানেলের অবস্থা পরীক্ষা করে এটি বন্ধ করতে বলার মধ্যে সময়ের মধ্যে চ্যানেলের অবস্থা পরিবর্তন হতে পারে।
এরিক কিং

8
আমি এর Action<T>পরিবর্তে ব্যবহার করব UseServiceDelegate<T>। গৌণ.
এইচপিপি

2
আমি সত্যই এই স্থিতিশীল সহায়কটিকে পছন্দ করি না Service<T>কারণ এটি ইউনিট পরীক্ষাকে জটিল করে তোলে (বেশিরভাগ স্থির জিনিস যেমন করে)। আমি এটি অ-স্থিতিশীল হতে পছন্দ করব যাতে এটি যে ক্লাসটি ব্যবহার করছে সেটিতে এটি ectedুকিয়ে দেওয়া যায়।
ফ্যাবিও মাররেকো

উত্তর:


137

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

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
}); 

(প্রতিটি মন্তব্য সম্পাদনা করুন)

যেহেতু Useরিটার্নগুলি অকার্যকর, তাই রিটার্ন মানগুলি হ্যান্ডেল করার সহজতম উপায় হ'ল ক্যাপচারড ভেরিয়েবলের মাধ্যমে:

int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
  {
    newOrderId = orderService.PlaceOrder(request);
  });
Console.WriteLine(newOrderId); // should be updated

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

16
আপনি সহজেই মোড়কে পরিবর্তন করতে পারেন যাতে ফলাফলের জন্য ক্যাপচার ভেরিয়েবলের প্রয়োজন হয় না। এরকম কিছু: public static TResult Use<TResult>(Func<T, TResult> codeBlock) { ... }
খ্রিস্ট

3
সম্ভবত দরকারী https://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/ এবং https://devzone.channeladam.com/articles/2014/09/how-to-easily-call-wcf-service-properly/ এবং http://dzimchuk.net/post/wcf-error-helpers
প্রিগ্যান্টকোজনো ক্যাব্রেন

এইভাবে ব্যবহার করে আমি কীভাবে শংসাপত্র যুক্ত করতে পারি?
হিপ্পাসাস

2
আমার মতে, সবচেয়ে সঠিক সমাধানটি হবে: 1) রেস শর্ত ছাড়াই ক্লোজ / অ্যাওর্ট প্যাটার্ন সম্পাদন করুন 2) পরিষেবা অপারেশন ব্যতিক্রম ছুঁড়ে মারলে পরিস্থিতি পরিচালনা করুন 3) ক্লোজ এবং অ্যাওর্ট পদ্ধতি উভয়ই ব্যতিক্রম ছুঁড়ে ফেলা হলে পরিস্থিতি পরিচালনা করুন 4) হ্যান্ডেল থ্রেডঅবর্ট এক্সপ্লেশন https://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/
কিউইনেট

88

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

সুতরাং, এটি পেতে, আমি একটি সমাধান নিয়োগ করেছি যা উভয় বিশ্বের সেরা মিশ্রিত করে।

void IDisposable.Dispose()
{
    bool success = false;
    try 
    {
        if (State != CommunicationState.Faulted) 
        {
            Close();
            success = true;
        }
    } 
    finally 
    {
        if (!success) 
            Abort();
    }
}

2
'ট্রাই-শেষ' (বা সিনট্যাকটিকাল চিনি - "ব্যবহার করে) পরিচালনা না করা সংস্থানগুলি দিয়ে বিবৃতিটি ব্যবহার করা ঝুঁকিপূর্ণ নয়? ঘটনাচক্রে, যদি "ক্লোজ" বিকল্পটি ব্যর্থ হয়, ব্যতিক্রম ধরা পড়ে না, এবং শেষ পর্যন্ত নাও চলতে পারে। এছাড়াও, শেষ বিবৃতিতে যদি কোনও ব্যতিক্রম থাকে তবে এটি অন্যান্য ব্যতিক্রমগুলি মাস্ক করতে পারে। আমি মনে করি সে কারণেই চেষ্টা করুন-ক্যাচ পছন্দ করা হয়।
জ্যাক জান্নসেন

জ্যাক, আপনার বস্তুর উপর পরিষ্কার নয়; আমি কি মিস করছি? যদি ক্লোজ পদ্ধতিটি একটি ব্যতিক্রম ছুঁড়ে, অবশেষে ব্লকটি ব্যতিক্রমটি ছুঁড়ে ফেলার আগেই কার্যকর করা হবে। রাইট?
প্যাট্রিক জাজালাপস্কি

1
@ জোমরনো, আমি আপনার সম্পাদনাটি বাতিল করে দিয়েছি। আপনি যদি খেয়াল করেন তবে পদ্ধতিতে কোনও ক্যাচ ব্লক নেই। ধারণাটি হ'ল যে কোনও ব্যতিক্রম ঘটে (শেষ পর্যন্ত) নিক্ষেপ করা উচিত, নীরবে ধরা পড়েনি।
ম্যাট ডেভিস

5
@ ম্যাটডাভিস আপনার কেন successপতাকা লাগার দরকার নেই ? না কেন try { Close(); } catch { Abort(); throw; }?
কনস্ট্যান্টিন স্পিরিন

চারপাশে চেষ্টা / ধরা সম্পর্কে কী Close(); success = true;? আমি যদি শেষ অবধি সফলভাবে এটি বাতিল করতে পারি তবে আমি একটি ব্যতিক্রম ছুঁড়ে ফেলতে চাই না। আমি যদি কেবলমাত্র অ্যাওর্ট () ক্ষেত্রে ব্যর্থ হয় তবে আমি কেবল ব্যতিক্রম চাই thrown এইভাবে, চেষ্টা / ধরাটি সম্ভাব্য রেসের শর্ত ব্যতিক্রমকে আড়াল করবে এবং তবুও আপনাকে শেষ অবধি সংযোগটি বাতিল করতে দেয়।
goku_da_master

32

এটিকে সঠিকভাবে কাজ করতে আমি একটি উচ্চতর অর্ডার ফাংশন লিখেছি । আমরা এটি বেশ কয়েকটি প্রকল্পে ব্যবহার করেছি এবং এটি দুর্দান্ত কাজ করছে বলে মনে হচ্ছে। "ব্যবহার" উদাহরণ বা অন্য কিছু না করে জিনিসগুলি শুরু থেকেই এইভাবে করা উচিত ছিল।

TReturn UseService<TChannel, TReturn>(Func<TChannel, TReturn> code)
{
    var chanFactory = GetCachedFactory<TChannel>();
    TChannel channel = chanFactory.CreateChannel();
    bool error = true;
    try {
        TReturn result = code(channel);
        ((IClientChannel)channel).Close();
        error = false;
        return result;
    }
    finally {
        if (error) {
            ((IClientChannel)channel).Abort();
        }
    }
}

আপনি এই জাতীয় কল করতে পারেন:

int a = 1;
int b = 2;
int sum = UseService((ICalculator calc) => calc.Add(a, b));
Console.WriteLine(sum);

এটি উদাহরণস্বরূপ আপনি যেমন করেছেন তেমনই। কিছু প্রকল্পে, আমরা দৃ strongly়ভাবে টাইপ করা সহায়ক পদ্ধতিগুলি লিখি, তাই আমরা "Wcf.UseFooService (f => f ...)" এর মতো জিনিস লিখি।

আমি এটি বেশ মার্জিত মনে করি, সমস্ত বিষয় বিবেচনা করা হয়। আপনি কোন বিশেষ সমস্যা সম্মুখীন হয়েছে?

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


আমি ব্যতিক্রম পাচ্ছি: চ্যানেলফ্যাক্টরিতে ঠিকানা সম্পত্তি nd চ্যানেলফ্যাক্টারের শেষ পয়েন্টে অবশ্যই একটি বৈধ ঠিকানা নির্দিষ্ট থাকতে হবেGetCachedFactoryপদ্ধতি কী ?
মার্শাল

28

ডাব্লুসিএফ ক্লায়েন্ট কলগুলি পরিচালনা করার জন্য এটি মাইক্রোসফ্টের প্রস্তাবিত উপায়:

আরও বিশদের জন্য দেখুন: প্রত্যাশিত ব্যতিক্রম

try
{
    ...
    double result = client.Add(value1, value2);
    ...
    client.Close();
}
catch (TimeoutException exception)
{
    Console.WriteLine("Got {0}", exception.GetType());
    client.Abort();
}
catch (CommunicationException exception)
{
    Console.WriteLine("Got {0}", exception.GetType());
    client.Abort();
}

অতিরিক্ত তথ্য অনেক লোক ডাব্লুসিএফ-তে এই প্রশ্ন জিজ্ঞাসা করছে বলে মনে হচ্ছে যে মাইক্রোসফ্ট এমনকি ব্যতিক্রমগুলি কীভাবে পরিচালনা করতে হবে তা প্রদর্শনের জন্য একটি উত্সর্গীকৃত নমুনা তৈরি করেছিল:

C: \ WF_WCF_Samples \ WCF \ বেসিক \ ক্লায়েন্ট \ ExpectedExceptions \ সি এস \ ক্লায়েন্ট

নমুনাটি ডাউনলোড করুন: সি # বা ভিবি

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

ধরতে alচ্ছিক অতিরিক্ত ব্যর্থতা

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

  // The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
catch (ChannelTerminatedException cte)
{
secureSecretService.Abort();
// todo: Implement delay (backoff) and retry
}

// The following is thrown when a remote endpoint could not be found or reached.  The endpoint may not be found or 
// reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
catch (EndpointNotFoundException enfe)
{
secureSecretService.Abort();
// todo: Implement delay (backoff) and retry
}

// The following exception that is thrown when a server is too busy to accept a message.
catch (ServerTooBusyException stbe)
{
secureSecretService.Abort();
// todo: Implement delay (backoff) and retry
}

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


1
নমুনা থেকে কোড এখনও সমস্যা সৃষ্টি করে? আমি ইউজিং ইউজিং প্রকল্পটি চালানোর চেষ্টা করেছি (ভিএস ২০১৩) তবে লাইনটি "Hope this code wasn't important, because it might not happen."এখনও কার্যকর করা হয়েছে ...
janv8000

14

অবশেষে আমি এই সমস্যার পরিষ্কার সমাধানের দিকে কিছু দৃ steps় পদক্ষেপ পেয়েছি।

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

কোডপ্লেক্সের এক্সপেনশন হ্যান্ডলিং ডাব্লুসিএফ প্রক্সি জেনারেটর নামে একটি প্রকল্প রয়েছে । এটি মূলত ভিজ্যুয়াল স্টুডিও ২০০৮ এ একটি নতুন কাস্টম সরঞ্জাম ইনস্টল করে, তারপরে নতুন পরিষেবা প্রক্সি তৈরি করার জন্য এই সরঞ্জামটি ব্যবহার করুন (পরিষেবা রেফারেন্স যুক্ত করুন) । ত্রুটিযুক্ত চ্যানেল, সময়সীমা এবং নিরাপদ নিষ্পত্তি করার জন্য এর কিছু দুর্দান্ত কার্যকারিতা রয়েছে। এটি কীভাবে কাজ করে ঠিক তা ব্যাখ্যা করে এখানে এক্সপেশনহ্যান্ডলিংপ্রক্সি র্যাপার নামে একটি দুর্দান্ত ভিডিও রয়েছে ।

আপনি Usingআবারও নিরাপদে বিবৃতিটি ব্যবহার করতে পারেন এবং যদি চ্যানেলটি কোনও অনুরোধে (টাইমআউটএক্সেপশন বা কমিউনিকেশন এক্সেপশন) ত্রুটিযুক্ত হয় তবে র‍্যাপার ফল্ট চ্যানেলটিকে পুনরায় আরম্ভ করবে এবং কোয়েরিটি আবার চেষ্টা করবে। যদি এটি ব্যর্থ হয় তবে এটি Abort()আদেশটি কল করবে এবং প্রক্সিটি নিষ্পত্তি করবে এবং ব্যতিক্রমটিকে নতুন করে করবে row যদি পরিষেবাটি কোনও FaultExceptionকোড নিক্ষেপ করে তবে এটি কার্যকর করা বন্ধ করবে এবং প্রত্যাশা অনুযায়ী সঠিক ব্যতিক্রমটি নিরাপদে ছড়িয়ে দেওয়া প্রক্সিটি বাতিল করা হবে।


@ শিমি স্ট্যাটাস বিটা তারিখ: শনি জুলাই 11, 2009 দ্বারা মিশেল বুস্টামন্টে । ডেড প্রকল্প?
কিকিনেট

11

মার্ক গ্র্যাভেল, মাইকেলজিজি, এবং ম্যাট ডেভিসের উত্তরের ভিত্তিতে আমাদের বিকাশকারীরা নিম্নলিখিতগুলি নিয়ে এসেছেন:

public static class UsingServiceClient
{
    public static void Do<TClient>(TClient client, Action<TClient> execute)
        where TClient : class, ICommunicationObject
    {
        try
        {
            execute(client);
        }
        finally
        {
            client.DisposeSafely();
        }
    }

    public static void DisposeSafely(this ICommunicationObject client)
    {
        if (client == null)
        {
            return;
        }

        bool success = false;

        try
        {
            if (client.State != CommunicationState.Faulted)
            {
                client.Close();
                success = true;
            }
        }
        finally
        {
            if (!success)
            {
                client.Abort();
            }
        }
    }
}

ব্যবহারের উদাহরণ:

string result = string.Empty;

UsingServiceClient.Do(
    new MyServiceClient(),
    client =>
    result = client.GetServiceResult(parameters));

এটি যথাসম্ভব "ব্যবহার করে" সিনট্যাক্সের খুব কাছাকাছি, শূন্য পদ্ধতিতে কল করার সময় আপনাকে ডামি মান ফেরত দিতে হবে না, এবং আপনি টিউপস ব্যবহার না করে পরিষেবাতে একাধিক কল করতে (এবং একাধিক মান ফিরিয়ে দিতে) করতে পারেন।

এছাড়াও, আপনি চাইলে ClientBase<T>চ্যানেলফ্যাক্টির পরিবর্তে বংশধরদের সাথে এটি ব্যবহার করতে পারেন ।

যদি কোনও বিকাশকারী তার পরিবর্তে প্রক্সি / চ্যানেলটি ম্যানুয়ালি নিষ্পত্তি করতে চায় তবে এক্সটেনশন পদ্ধতিটি উন্মোচিত হবে।


যদি আমি পুলিংডুপ্লেক্স ব্যবহার করছি এবং কোনও কল করার পরে সংযোগটি বন্ধ না করে তবে এটির ক্লায়েন্ট পরিষেবাটি কয়েক দিন বেঁচে থাকতে পারে এবং সার্ভার কলব্যাকগুলি পরিচালনা করতে পারে যদি এটি ব্যবহার করে sense আমি যতদূর বুঝতে পারি যে সমাধানটি এখানে আলোচনা করা হয়েছে তাতে প্রতি সেশনের জন্য একটি কলের অর্থ কী?
SLL

@ এসএলএল - এটি কল রিটার্নের সাথে সাথে সংযোগ বন্ধ করার জন্য (প্রতি সেশনে একটি কল)।
ট্রুউইল

@ কচো DisposeSafelyবেসরকারী করা অবশ্যই একটি বিকল্প এবং বিভ্রান্তি এড়াতে পারে। এমন ব্যবহারের ক্ষেত্রেও হতে পারে যেখানে কেউ সরাসরি এটি কল করতে চাইবে, তবে আমি একটি অফহন্ড নিয়ে আসতে পারি না।
ট্রুউইল

@ কেবলমাত্র ডকুমেন্টেশনের জন্যই, এটি উল্লেখ করাও গুরুত্বপূর্ণ যে এই পদ্ধতিটি থ্রেড-নিরাপদ?
কচো সান্তা

1
আমার মতে, সবচেয়ে সঠিক সমাধানটি হবে: 1) রেস শর্ত ছাড়াই ক্লোজ / অ্যাওর্ট প্যাটার্ন সম্পাদন করুন 2) পরিষেবা অপারেশন ব্যতিক্রম ছুঁড়ে মারলে পরিস্থিতি পরিচালনা করুন 3) ক্লোজ এবং অ্যাওর্ট পদ্ধতি উভয়ই ব্যতিক্রম ছুঁড়ে ফেলা হলে পরিস্থিতি পরিচালনা করুন 4) হ্যান্ডেল যেমন ThreadAbortException যেমন অ্যাসিঙ্ক্রোনাস ব্যতিক্রম https://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/
Kiquenet

8

@ মার্ক গ্র্যাভেল

এটি ব্যবহার করা ঠিক হবে না:

public static TResult Using<T, TResult>(this T client, Func<T, TResult> work)
        where T : ICommunicationObject
{
    try
    {
        var result = work(client);

        client.Close();

        return result;
    }
    catch (Exception e)
    {
        client.Abort();

        throw;
    }
}

বা, (Func<T, TResult>)ক্ষেত্রে একই জিনিসService<IOrderService>.Use

এগুলি ভেরিয়েবলগুলি সহজতর করে তুলবে।


2
+1 @ মার্কগ্রাভেল আমি মনে করি আপনার উত্তরও 'আরও ভাল করতে পারে': পি (এবং ন্যাক্ট রিটার্ন সহ ফানকের শর্তাবলী কার্যকর করা যেতে পারে) ( এই পুরো পৃষ্ঠাটি একটি জগাখিচুড়ি - আমি এই এক দশক ডাব্লুসিএফ ব্যবহারের কল্পনা করে যদি আমি একটি ইউনিফাইড তৈরি করি এবং ডুপস সম্পর্কে মন্তব্য করব ...
রুবেন বারটেলিংক

7

এটা কি?

এটি গ্রহণযোগ্য উত্তরের সিডাব্লু সংস্করণ তবে এর সাথে (আমি কী বিবেচনা করি সম্পূর্ণ) ব্যতিক্রম হ্যান্ডলিং অন্তর্ভুক্ত।

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

সাধারণ ডাব্লুসিএফ ক্লায়েন্টের ব্যবহার

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

Service<IOrderService>.Use(orderService=>
{
  orderService.PlaceOrder(request);
});

ServiceDelegate.cs

আপনার সমাধানটিতে এই ফাইলটি যুক্ত করুন। এই ফাইলটিতে কোনও পরিবর্তন দরকার নেই, যদি না আপনি পুনরায় চেষ্টা করার সংখ্যা বা কোন ব্যতিক্রমগুলি আপনি পরিচালনা করতে চান তা পরিবর্তন করতে না চান।

public delegate void UseServiceDelegate<T>(T proxy);

public static class Service<T>
{
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 

    public static void Use(UseServiceDelegate<T> codeBlock)
    {
        IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
        bool success = false;


       Exception mostRecentEx = null;
       int millsecondsToSleep = 1000;

       for(int i=0; i<5; i++)  // Attempt a maximum of 5 times 
       {
           try
           {
               codeBlock((T)proxy);
               proxy.Close();
               success = true; 
               break;
           }

           // The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
           catch (ChannelTerminatedException cte)
           {
              mostRecentEx = cte;
               proxy.Abort();
               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep  * (i + 1)); 
           }

           // The following is thrown when a remote endpoint could not be found or reached.  The endpoint may not be found or 
           // reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
           catch (EndpointNotFoundException enfe)
           {
              mostRecentEx = enfe;
               proxy.Abort();
               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }

           // The following exception that is thrown when a server is too busy to accept a message.
           catch (ServerTooBusyException stbe)
           {
              mostRecentEx = stbe;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }
           catch (TimeoutException timeoutEx)
           {
               mostRecentEx = timeoutEx;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           } 
           catch (CommunicationException comException)
           {
               mostRecentEx = comException;
               proxy.Abort();

               //  delay (backoff) and retry 
               Thread.Sleep(millsecondsToSleep * (i + 1)); 
           }
           catch(Exception )
           {
                // rethrow any other exception not defined here
                // You may want to define a custom Exception class to pass information such as failure count, and failure type
                proxy.Abort();
                throw ;  
           }
       }
       if (success == false && mostRecentEx != null) 
       { 
           proxy.Abort();
           throw new Exception("WCF call failed after 5 retries.", mostRecentEx );
       }

    }
}

পিএস: আমি এই পোস্টটিকে একটি সম্প্রদায় উইকি করেছি। আমি এই উত্তরটি থেকে "পয়েন্ট" সংগ্রহ করব না, তবে আপনি যদি প্রয়োগের সাথে একমত হন, বা এটি আরও ভাল করার জন্য এটি সম্পাদনা করেন তবে আপনি এটিকে উজ্জীবিত করতে পছন্দ করেন।


আমি নিশ্চিত নই যে আমি এই উত্তরের চরিত্রায়নের সাথে একমত। এটি ব্যতিক্রম হ্যান্ডলিংয়ের আপনার ধারণার সাথে সিডাব্লু সংস্করণ ।
জন স্যান্ডার্স

@ জনসন্ডার্স - সত্য (ব্যতিক্রম পরিচালনার বিষয়ে আমার ধারণা)। আমি যে ব্যতিক্রম আমি মিস করছি বা ভুল পরিচালনা করছি তা আমাকে জানান।
শুভগুইস_অ্যাক্টিভেট

সাফল্যের পরিবর্তনশীল সম্পর্কে কী? এটি উত্স কোড যুক্ত করতে হবে: যদি (সাফল্য) ফিরে; ??
কিকিনেট

যদি প্রথম কলটি ছুড়ে যায় এবং দ্বিতীয়বার সর্বাধিকতম রিসেন্টেক্স নিখুঁত হবে না তাই আপনি ব্যতিক্রম নিক্ষেপ করছেন যে কোনওভাবেই 5 চেষ্টা করে ব্যর্থ হয়েছে। নাকি আমি কিছু মিস করছি? 2 য়, 3 য়, 4 র্থ বা 5 তম চেষ্টা সফল হলে আপনি সর্বাধিক সাম্প্রতিকতম কোথায় পরিষ্কার করবেন তা আমি দেখতে পাচ্ছি না। এছাড়াও একটি রিটার্ন দেখতে পাবেন না সফল। আমার এখানে কিছু মিস করা উচিত, তবে কোনও ব্যতিক্রম ছোঁড়া না দেওয়া থাকলে এই কোডটি সর্বদা 5 বার চলবে না?
বার্ট ক্যালিক্সটো

@ বার্ট - আমি success == falseবিবৃতিতে ফাইনালে যোগ করেছি
গুডগুইজ_একটিভেট

7

নীচে প্রশ্ন থেকে উত্সটির বর্ধিত সংস্করণ রয়েছে এবং একাধিক চ্যানেল কারখানাগুলি ক্যাশে করা হয়েছে এবং চুক্তি নাম অনুসারে কনফিগারেশন ফাইলের শেষ পয়েন্টটি দেখার চেষ্টা করা হয়েছে।

এটি নেট 4 ব্যবহার করে (বিশেষত: বিপরীতে, লিনকুই, var):

/// <summary>
/// Delegate type of the service method to perform.
/// </summary>
/// <param name="proxy">The service proxy.</param>
/// <typeparam name="T">The type of service to use.</typeparam>
internal delegate void UseServiceDelegate<in T>(T proxy);

/// <summary>
/// Wraps using a WCF service.
/// </summary>
/// <typeparam name="T">The type of service to use.</typeparam>
internal static class Service<T>
{
    /// <summary>
    /// A dictionary to hold looked-up endpoint names.
    /// </summary>
    private static readonly IDictionary<Type, string> cachedEndpointNames = new Dictionary<Type, string>();

    /// <summary>
    /// A dictionary to hold created channel factories.
    /// </summary>
    private static readonly IDictionary<string, ChannelFactory<T>> cachedFactories =
        new Dictionary<string, ChannelFactory<T>>();

    /// <summary>
    /// Uses the specified code block.
    /// </summary>
    /// <param name="codeBlock">The code block.</param>
    internal static void Use(UseServiceDelegate<T> codeBlock)
    {
        var factory = GetChannelFactory();
        var proxy = (IClientChannel)factory.CreateChannel();
        var success = false;

        try
        {
            using (proxy)
            {
                codeBlock((T)proxy);
            }

            success = true;
        }
        finally
        {
            if (!success)
            {
                proxy.Abort();
            }
        }
    }

    /// <summary>
    /// Gets the channel factory.
    /// </summary>
    /// <returns>The channel factory.</returns>
    private static ChannelFactory<T> GetChannelFactory()
    {
        lock (cachedFactories)
        {
            var endpointName = GetEndpointName();

            if (cachedFactories.ContainsKey(endpointName))
            {
                return cachedFactories[endpointName];
            }

            var factory = new ChannelFactory<T>(endpointName);

            cachedFactories.Add(endpointName, factory);
            return factory;
        }
    }

    /// <summary>
    /// Gets the name of the endpoint.
    /// </summary>
    /// <returns>The name of the endpoint.</returns>
    private static string GetEndpointName()
    {
        var type = typeof(T);
        var fullName = type.FullName;

        lock (cachedFactories)
        {
            if (cachedEndpointNames.ContainsKey(type))
            {
                return cachedEndpointNames[type];
            }

            var serviceModel = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).SectionGroups["system.serviceModel"] as ServiceModelSectionGroup;

            if ((serviceModel != null) && !string.IsNullOrEmpty(fullName))
            {
                foreach (var endpointName in serviceModel.Client.Endpoints.Cast<ChannelEndpointElement>().Where(endpoint => fullName.EndsWith(endpoint.Contract)).Select(endpoint => endpoint.Name))
                {
                    cachedEndpointNames.Add(type, endpointName);
                    return endpointName;
                }
            }
        }

        throw new InvalidOperationException("Could not find endpoint element for type '" + fullName + "' in the ServiceModel client configuration section. This might be because no configuration file was found for your application, or because no endpoint element matching this name could be found in the client element.");
    }
}

1
এর UseServiceDelegate<T>পরিবর্তে কেন ব্যবহার করবেন Action<T>?
মাইক মায়ার

1
কেবলমাত্র আমি ভাবতে পারি যে আসল লেখক এটি করেছিলেন তা হ'ল একটি দৃ strongly়-টাইপিত প্রতিনিধিকে বিকাশকারীটি জানতে পারে কোনও পরিষেবা কল করার সাথে সম্পর্কিত। তবে যতদূর আমি দেখতে পাচ্ছি Action<T>ঠিক তেমনি কাজ করে।
জেসি সি স্লিকার

5

এর মতো একটি মোড়ক কাজ করবে:

public class ServiceClientWrapper<ServiceType> : IDisposable
{
    private ServiceType _channel;
    public ServiceType Channel
    {
        get { return _channel; }
    }

    private static ChannelFactory<ServiceType> _channelFactory;

    public ServiceClientWrapper()
    {
        if(_channelFactory == null)
             // Given that the endpoint name is the same as FullName of contract.
            _channelFactory = new ChannelFactory<ServiceType>(typeof(T).FullName);
        _channel = _channelFactory.CreateChannel();
        ((IChannel)_channel).Open();
    }

    public void Dispose()
    {
        try
        {
            ((IChannel)_channel).Close();
        }
        catch (Exception e)
        {
            ((IChannel)_channel).Abort();
            // TODO: Insert logging
        }
    }
}

এটি আপনাকে কোড লিখতে সক্ষম করবে:

ResponseType response = null;
using(var clientWrapper = new ServiceClientWrapper<IService>())
{
    var request = ...
    response = clientWrapper.Channel.MyServiceCall(request);
}
// Use your response object.

যদি প্রয়োজন হয় তবে মোড়ক অবশ্যই আরও ব্যতিক্রম করতে পারে তবে নীতিটি একই থাকে remains


আমি মনে করি ডিসপোজ সংক্রান্ত আলোচনাটি নির্দিষ্ট শর্তে ডাকা হবে না ... এর ফলে মেমরি ফাঁস ডব্লু / ডাব্লুসিএফ হয়।
গুডগুইস_অ্যাক্টিভেট

আমি নিশ্চিত নই যে এটি মেমরি ফাঁসের ফলে ঘটেছে তবে সমস্যাটি এটি। আপনি যখন Disposeকোনও আইচানলে ডাকেন তখন চ্যানেলটি ত্রুটিযুক্ত অবস্থায় থাকলে এটি ব্যতিক্রম করতে পারে, মাইক্রোসফ্ট যেহেতু নির্দিষ্ট করে যে Disposeএটি কখনই ছুঁড়ে না ফেলে এটি একটি সমস্যা । সুতরাং উপরের কোডটি কী করবে Closeকেসটি হ্যান্ডলিং করা যখন ব্যতিক্রম ছোঁড়ে। যদি Abortছুড়ে ফেলে তবে এটি মারাত্মক কিছু ভুল হতে পারে। আমি গত ডিসেম্বর এ সম্পর্কে একটি ব্লগ পোস্ট লিখেছিলাম: blog.tomasjansson.com/2010/12/disposible-wcf-client-wrapper
টমাস

4

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

Func<object> createChannel = () =>
    ChannelFactory<IHelloWorldService>
        .CreateChannel(new NetTcpBinding(), new EndpointAddress(uri));
var factory = new WcfProxyFactory();
var proxy = factory.Create<IDisposableHelloWorldService>(createChannel);
proxy.HelloWorld();

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

কোডটি দেখুন, এটি আসলে বেশ সহজ: ডাব্লুসিএফ ডায়নামিক প্রক্সি


4

একটি এক্সটেনশন পদ্ধতি ব্যবহার করুন:

public static class CommunicationObjectExtensions
{
    public static TResult MakeSafeServiceCall<TResult, TService>(this TService client, Func<TService, TResult> method) where TService : ICommunicationObject
    {
        TResult result;

        try
        {
            result = method(client);
        }
        finally
        {
            try
            {
                client.Close();
            }
            catch (CommunicationException)
            {
                client.Abort(); // Don't care about these exceptions. The call has completed anyway.
            }
            catch (TimeoutException)
            {
                client.Abort(); // Don't care about these exceptions. The call has completed anyway.
            }
            catch (Exception)
            {
                client.Abort();
                throw;
            }
        }

        return result;
    }
}

4

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

public class AutoCloseWcf : IDisposable
{

    private ICommunicationObject CommunicationObject;

    public AutoDisconnect(ICommunicationObject CommunicationObject)
    {
        this.CommunicationObject = CommunicationObject;
    }

    public void Dispose()
    {
        if (CommunicationObject == null)
            return;
        try {
            if (CommunicationObject.State != CommunicationState.Faulted) {
                CommunicationObject.Close();
            } else {
                CommunicationObject.Abort();
            }
        } catch (CommunicationException ce) {
            CommunicationObject.Abort();
        } catch (TimeoutException toe) {
            CommunicationObject.Abort();
        } catch (Exception e) {
            CommunicationObject.Abort();
            //Perhaps log this

        } finally {
            CommunicationObject = null;
        }
    }
}

তারপরে আপনি যখন সার্ভারটি অ্যাক্সেস করছেন তখন আপনি ক্লায়েন্ট তৈরি করেন এবং usingস্ব-সংযোগে ব্যবহার করুন:

var Ws = new ServiceClient("netTcpEndPointName");
using (new AutoCloseWcf(Ws)) {

    Ws.Open();

    Ws.Test();
}

3

সারসংক্ষেপ

এই উত্তরে বর্ণিত কৌশলগুলি ব্যবহার করে নিম্নলিখিত সিনট্যাক্স সহ যে কোনও একটি ব্যবহার ব্লকে ডাব্লুসিএফ পরিষেবা গ্রহণ করতে পারে:

var channelFactory = new ChannelFactory<IMyService>("");

var serviceHelper = new ServiceHelper<IMyService>(channelFactory);
var proxy = serviceHelper.CreateChannel();
using (proxy as IDisposable)
{
    proxy.DoWork();
}

আপনার অবস্থার সাথে সুনির্দিষ্ট আরও সংক্ষিপ্ত প্রোগ্রামিং মডেল অর্জনের জন্য আপনি অবশ্যই এটিকে আরও মানিয়ে নিতে পারেন - তবে মূল বিষয়টি হ'ল আমরা IMyServiceচ্যানেলটিকে নিন্দা করার একটি প্রয়োগ তৈরি করতে পারি যা সঠিকভাবে ডিসপোজেবল প্যাটার্নকে কার্যকর করে imple


বিস্তারিত

এখন পর্যন্ত প্রদত্ত সমস্ত উত্তর ডাব্লুসিএফ চ্যানেল প্রয়োগের "বাগ" এর আশেপাশের সমস্যার সমাধান করে IDisposable। এর জবাব হলো, সবচেয়ে সংক্ষিপ্ত প্রোগ্রামিং (আপনি ব্যবহার করতে সক্ষম হবেন মডেল প্রস্তাব বলে মনে হয় usingঅপরিচালিত সম্পদের উপর মীমাংসা করা ব্লক) হয় এই এক যেখানে প্রক্সি বাস্তবায়ন modifed হয় - IDisposableএকটি বাগ-মুক্ত বাস্তবায়ন। এই পদ্ধতির সমস্যাটি হ'ল রক্ষণাবেক্ষণযোগ্যতা - আমাদের ব্যবহৃত প্রক্সির জন্য আমাদের এই কার্যকারিতাটি পুনরায় প্রয়োগ করতে হবে। এই উত্তরের পরিবর্তনে আমরা দেখতে পাব কীভাবে আমরা এই কৌশলটি জেনেরিক করার জন্য উত্তরাধিকারের চেয়ে রচনাটি ব্যবহার করতে পারি ।

প্রথম প্রচেষ্টা

বাস্তবায়নের জন্য বিভিন্ন বাস্তবায়ন রয়েছে বলে মনে হয় IDisposable, তবে যুক্তির স্বার্থে আমরা বর্তমানে গৃহীত উত্তর দ্বারা ব্যবহৃত একটি রূপান্তর ব্যবহার করব ।

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    void DoWork();
}

public class ProxyDisposer : IDisposable
{
    private IClientChannel _clientChannel;


    public ProxyDisposer(IClientChannel clientChannel)
    {
        _clientChannel = clientChannel;
    }

    public void Dispose()
    {
        var success = false;
        try
        {
            _clientChannel.Close();
            success = true;
        }
        finally
        {
            if (!success)
                _clientChannel.Abort();
            _clientChannel = null;
        }
    }
}

public class ProxyWrapper : IMyService, IDisposable
{
    private IMyService _proxy;
    private IDisposable _proxyDisposer;

    public ProxyWrapper(IMyService proxy, IDisposable disposable)
    {
        _proxy = proxy;
        _proxyDisposer = disposable;
    }

    public void DoWork()
    {
        _proxy.DoWork();
    }

    public void Dispose()
    {
        _proxyDisposer.Dispose();
    }
}

উপরের ক্লাসগুলি দিয়ে সজ্জিত আমরা এখন লিখতে পারি

public class ServiceHelper
{
    private readonly ChannelFactory<IMyService> _channelFactory;

    public ServiceHelper(ChannelFactory<IMyService> channelFactory )
    {
        _channelFactory = channelFactory;
    }

    public IMyService CreateChannel()
    {
        var channel = _channelFactory.CreateChannel();
        var channelDisposer = new ProxyDisposer(channel as IClientChannel);
        return new ProxyWrapper(channel, channelDisposer);
    }
}

এটি আমাদের usingব্লকটি ব্যবহার করে আমাদের পরিষেবা গ্রাস করতে দেয় :

ServiceHelper serviceHelper = ...;
var proxy = serviceHelper.CreateChannel();
using (proxy as IDisposable)
{
    proxy.DoWork();
}

এই জেনেরিক করা

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

public class ServiceHelper<T>
{
    private readonly ChannelFactory<T> _channelFactory;

    private static readonly Func<T, IDisposable, T> _channelCreator;

    static ServiceHelper()
    {
        /** 
         * Create a method that can be used generate the channel. 
         * This is effectively a compiled verion of new ProxyWrappper(channel, channelDisposer) for our proxy type
         * */
        var assemblyName = Guid.NewGuid().ToString();
        var an = new AssemblyName(assemblyName);
        var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(an, AssemblyBuilderAccess.Run);
        var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName);

        var proxyType = CreateProxyType(moduleBuilder, typeof(T), typeof(IDisposable));

        var channelCreatorMethod = new DynamicMethod("ChannelFactory", typeof(T),
            new[] { typeof(T), typeof(IDisposable) });

        var ilGen = channelCreatorMethod.GetILGenerator();
        var proxyVariable = ilGen.DeclareLocal(typeof(T));
        var disposableVariable = ilGen.DeclareLocal(typeof(IDisposable));
        ilGen.Emit(OpCodes.Ldarg, proxyVariable);
        ilGen.Emit(OpCodes.Ldarg, disposableVariable);
        ilGen.Emit(OpCodes.Newobj, proxyType.GetConstructor(new[] { typeof(T), typeof(IDisposable) }));
        ilGen.Emit(OpCodes.Ret);

        _channelCreator =
            (Func<T, IDisposable, T>)channelCreatorMethod.CreateDelegate(typeof(Func<T, IDisposable, T>));

    }

    public ServiceHelper(ChannelFactory<T> channelFactory)
    {
        _channelFactory = channelFactory;
    }

    public T CreateChannel()
    {
        var channel = _channelFactory.CreateChannel();
        var channelDisposer = new ProxyDisposer(channel as IClientChannel);
        return _channelCreator(channel, channelDisposer);
    }

   /**
    * Creates a dynamic type analogous to ProxyWrapper, implementing T and IDisposable.
    * This method is actually more generic than this exact scenario.
    * */
    private static Type CreateProxyType(ModuleBuilder moduleBuilder, params Type[] interfacesToInjectAndImplement)
    {
        TypeBuilder tb = moduleBuilder.DefineType(Guid.NewGuid().ToString(),
            TypeAttributes.Public | TypeAttributes.Class);

        var typeFields = interfacesToInjectAndImplement.ToDictionary(tf => tf,
            tf => tb.DefineField("_" + tf.Name, tf, FieldAttributes.Private));

        #region Constructor

        var constructorBuilder = tb.DefineConstructor(
            MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName |
            MethodAttributes.RTSpecialName,
            CallingConventions.Standard,
            interfacesToInjectAndImplement);

        var il = constructorBuilder.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0]));

        for (var i = 1; i <= interfacesToInjectAndImplement.Length; i++)
        {
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Ldarg, i);
            il.Emit(OpCodes.Stfld, typeFields[interfacesToInjectAndImplement[i - 1]]);
        }
        il.Emit(OpCodes.Ret);

        #endregion

        #region Add Interface Implementations

        foreach (var type in interfacesToInjectAndImplement)
        {
            tb.AddInterfaceImplementation(type);
        }

        #endregion

        #region Implement Interfaces

        foreach (var type in interfacesToInjectAndImplement)
        {
            foreach (var method in type.GetMethods())
            {
                var methodBuilder = tb.DefineMethod(method.Name,
                    MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig |
                    MethodAttributes.Final | MethodAttributes.NewSlot,
                    method.ReturnType,
                    method.GetParameters().Select(p => p.ParameterType).ToArray());
                il = methodBuilder.GetILGenerator();

                if (method.ReturnType == typeof(void))
                {
                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldfld, typeFields[type]);
                    il.Emit(OpCodes.Callvirt, method);
                    il.Emit(OpCodes.Ret);
                }
                else
                {
                    il.DeclareLocal(method.ReturnType);

                    il.Emit(OpCodes.Nop);
                    il.Emit(OpCodes.Ldarg_0);
                    il.Emit(OpCodes.Ldfld, typeFields[type]);

                    var methodParameterInfos = method.GetParameters();
                    for (var i = 0; i < methodParameterInfos.Length; i++)
                        il.Emit(OpCodes.Ldarg, (i + 1));
                    il.Emit(OpCodes.Callvirt, method);

                    il.Emit(OpCodes.Stloc_0);
                    var defineLabel = il.DefineLabel();
                    il.Emit(OpCodes.Br_S, defineLabel);
                    il.MarkLabel(defineLabel);
                    il.Emit(OpCodes.Ldloc_0);
                    il.Emit(OpCodes.Ret);
                }

                tb.DefineMethodOverride(methodBuilder, method);
            }
        }

        #endregion

        return tb.CreateType();
    }
}

আমাদের নতুন সহায়ক শ্রেণীর সাহায্যে আমরা এখন লিখতে পারি

var channelFactory = new ChannelFactory<IMyService>("");

var serviceHelper = new ServiceHelper<IMyService>(channelFactory);
var proxy = serviceHelper.CreateChannel();
using (proxy as IDisposable)
{
    proxy.DoWork();
}

মনে রাখবেন যে আপনি স্বয়ংক্রিয়ভাবে উত্পাদিত ক্লায়েন্টদের ClientBase<>(ব্যবহারের পরিবর্তে ChannelFactory<>) উত্তরাধিকার সূত্রেও একই কৌশল (সামান্য পরিবর্তন সহ) ব্যবহার করতে পারেন, বা যদি আপনি IDisposableচ্যানেলটি বন্ধ করতে কোনও আলাদা বাস্তবায়ন ব্যবহার করতে চান ।


2

সংযোগ বন্ধ করার এই পদ্ধতিটি আমার পছন্দ:

var client = new ProxyClient();
try
{
    ...
    client.Close();
}
finally
{
    if(client.State != CommunicationState.Closed)
        client.Abort();
}

1

আমি একটি সাধারণ বেস ক্লাস লিখেছি যা এটি পরিচালনা করে। এটি একটি নিউগেট প্যাকেজ হিসাবে উপলব্ধ এবং এটি ব্যবহার করা বেশ সহজ।

//MemberServiceClient is the class generated by SvcUtil
public class MemberServiceManager : ServiceClientBase<MemberServiceClient>
{
    public User GetUser(int userId)
    {
        return PerformServiceOperation(client => client.GetUser(userId));
    }

    //you can also check if any error occured if you can't throw exceptions       
    public bool TryGetUser(int userId, out User user)
    {
        return TryPerformServiceOperation(c => c.GetUser(userId), out user);
    }
}

VS2013-.net 4.5.1 এর জন্য কোনও আপডেট? স্ট্যাকওভারফ্লো . com/a/9370880/206730 এর মতো পুনরায় চেষ্টা করার জন্য কোনও বিকল্প ? -
কিকিনেট

@ কিকিনেট আমি আর ডাব্লুসিএফ-তে কাজ করছি না। আপনি যদি আমাকে একটি টানার অনুরোধ প্রেরণ করেন তবে আমি এটিকে মার্জ করে প্যাকেজ আপডেট করতে পারি।
উফুক হ্যাকোওলুলার

1
public static class Service<TChannel>
{
    public static ChannelFactory<TChannel> ChannelFactory = new ChannelFactory<TChannel>("*");

    public static TReturn Use<TReturn>(Func<TChannel,TReturn> codeBlock)
    {
        var proxy = (IClientChannel)ChannelFactory.CreateChannel();
        var success = false;
        try
        {
            var result = codeBlock((TChannel)proxy);
            proxy.Close();
            success = true;
            return result;
        }
        finally
        {
            if (!success)
            {
                proxy.Abort();
            }
        }
    }
}

সুতরাং এটি সুন্দরভাবে রিটার্নের বিবৃতি লিখতে দেয়:

return Service<IOrderService>.Use(orderService => 
{ 
    return orderService.PlaceOrder(request); 
}); 

1

আমি চ্যানেলফ্যাক্ট্রির পরিবর্তে সার্ভিসক্লিয়েন্ট ব্যবহারের ক্ষেত্রে মার্ক গ্র্যাভেলের উত্তর থেকে পরিষেবাটির বাস্তবায়ন যুক্ত করতে চাই ।

public interface IServiceConnector<out TServiceInterface>
{
    void Connect(Action<TServiceInterface> clientUsage);
    TResult Connect<TResult>(Func<TServiceInterface, TResult> channelUsage);
}

internal class ServiceConnector<TService, TServiceInterface> : IServiceConnector<TServiceInterface>
    where TServiceInterface : class where TService : ClientBase<TServiceInterface>, TServiceInterface, new()
{
    public TResult Connect<TResult>(Func<TServiceInterface, TResult> channelUsage)
    {
        var result = default(TResult);
        Connect(channel =>
        {
            result = channelUsage(channel);
        });
        return result;
    }

    public void Connect(Action<TServiceInterface> clientUsage)
    {
        if (clientUsage == null)
        {
            throw new ArgumentNullException("clientUsage");
        }
        var isChanneldClosed = false;
        var client = new TService();
        try
        {
            clientUsage(client);
            client.Close();
            isChanneldClosed = true;
        }
        finally
        {
            if (!isChanneldClosed)
            {
                client.Abort();
            }
        }
    }
}

1

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

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

নোট করুন যে এই বিশেষ প্রয়োগটি কনফিগার করার ক্ষমতা সরবরাহ করে ServiceEndpoint রানটাইমটিতে ।


কোড:

Namespace Service
  Public NotInheritable Class Disposable(Of T)
    Public Shared ChannelFactory As New ChannelFactory(Of T)(Service)

    Public Shared Sub Use(Execute As Action(Of T))
      Dim oProxy As IClientChannel

      oProxy = ChannelFactory.CreateChannel

      Try
        Execute(oProxy)
        oProxy.Close()

      Catch
        oProxy.Abort()
        Throw

      End Try
    End Sub



    Public Shared Function Use(Of TResult)(Execute As Func(Of T, TResult)) As TResult
      Dim oProxy As IClientChannel

      oProxy = ChannelFactory.CreateChannel

      Try
        Use = Execute(oProxy)
        oProxy.Close()

      Catch
        oProxy.Abort()
        Throw

      End Try
    End Function



    Public Shared ReadOnly Property Service As ServiceEndpoint
      Get
        Return New ServiceEndpoint(
          ContractDescription.GetContract(
            GetType(T),
            GetType(Action(Of T))),
          New BasicHttpBinding,
          New EndpointAddress(Utils.WcfUri.ToString))
      End Get
    End Property
  End Class
End Namespace

ব্যবহার:

Public ReadOnly Property Jobs As List(Of Service.Job)
  Get
    Disposable(Of IService).Use(Sub(Client) Jobs = Client.GetJobs(Me.Status))
  End Get
End Property

Public ReadOnly Property Jobs As List(Of Service.Job)
  Get
    Return Disposable(Of IService).Use(Function(Client) Client.GetJobs(Me.Status))
  End Get
End Property

1

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

কাস্টম শংসাপত্র এবং স্টাফ জন্য চ্যানেল সেট আপ করতে কনস্ট্রাক্টরে কাজ করা দরকার ছিল যাতে এটি এখানেও ...

public abstract class PFServer2ServerClientBase<TChannel> : ClientBase<TChannel>, IDisposable where TChannel : class
{
    private bool disposed = false;

    public PFServer2ServerClientBase()
    {
        // Copy information from custom identity into credentials, and other channel setup...
    }

    ~PFServer2ServerClientBase()
    {
        this.Dispose(false);
    }

    void IDisposable.Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }

    public void Dispose(bool disposing)
    {
        if (!this.disposed)
        {
            try
            {
                    if (this.State == CommunicationState.Opened)
                        this.Close();
            }
            finally
            {
                if (this.State == CommunicationState.Faulted)
                    this.Abort();
            }
            this.disposed = true;
        }
    }
}

তারপরে একজন ক্লায়েন্ট কেবল:

internal class TestClient : PFServer2ServerClientBase<ITest>, ITest
{
    public string TestMethod(int value)
    {
        return base.Channel.TestMethod(value);
    }
}

এবং কলার এইগুলির মধ্যে যে কোনও একটি করতে পারেন:

public SomeClass
{
    [Dependency]
    public ITest test { get; set; }

    // Not the best, but should still work due to finalizer.
    public string Method1(int value)
    {
        return this.test.TestMethod(value);
    }

    // The good way to do it
    public string Method2(int value)
    {
        using(ITest t = unityContainer.Resolve<ITest>())
        {
            return t.TestMethod(value);
        }
    }
}

আপনি কখনই আপনার নিষ্পত্তি পদ্ধতিতে পরামিতিগুলি নিষ্পত্তি করার জন্য ব্যবহার করবেন না
ক্যাফজিক

@Chad - আমি Microsoft এর সাধারণ চূড়ান্ত নিম্নলিখিত ছিল / নিষ্পত্তি নকশা প্যাটার্ন: msdn.microsoft.com/en-us/library/b1yfkh5e%28VS.71%29.aspx এটা সত্য যে আমি পরিবর্তনশীল যদিও ব্যবহার করছি না কারণ আমি ডন একটি সাধারণ নিষ্পত্তি এবং একটি চূড়ান্তকরণের মধ্যে কোনও আলাদা ক্লিনআপ করার দরকার নেই। এটি কেবলমাত্র কলটি ডিসপোজ () কে চূড়ান্ত করতে এবং কোডটি ডিসপোজ (বুল) থেকে ডিসপোজ () এ স্থানান্তরিত করতে পুনরায় লেখা যেতে পারে।
কোডিংবিথস্পাইকে

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

0

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

আমি WCF ক্লায়েন্টটি যাতে DoSomethingWithClient()পদ্ধতিটি ব্যবহার করার আগে এটির সাথে কিছু করার ক্ষমতা চেয়েছিলাম ।

public interface IServiceClientFactory<T>
{
    T DoSomethingWithClient();
}
public partial class ServiceClient : IServiceClientFactory<ServiceClient>
{
    public ServiceClient DoSomethingWithClient()
    {
        var client = this;
        // do somthing here as set client credentials, etc.
        //client.ClientCredentials = ... ;
        return client;
    }
}

এখানে সহায়ক শ্রেণি:

public static class Service<TClient>
    where TClient : class, ICommunicationObject, IServiceClientFactory<TClient>, new()
{
    public static TReturn Use<TReturn>(Func<TClient, TReturn> codeBlock)
    {
        TClient client = default(TClient);
        bool success = false;
        try
        {
            client = new TClient().DoSomethingWithClient();
            TReturn result = codeBlock(client);
            client.Close();
            success = true;
            return result;
        }
        finally
        {
            if (!success && client != null)
            {
                client.Abort();
            }
        }
    }
}

এবং আমি এটি ব্যবহার করতে পারি:

string data = Service<ServiceClient>.Use(x => x.GetData(7));

বাইন্ডিং এবং এন্ডপোয়িং ব্যবহার করে ক্লায়েন্ট কনস্ট্রাক্টর সম্পর্কে কী? টিসিলেট (বাঁধাই করা, শেষ করা)
কিকুইনেট

0

নীচে ডিসপোজ প্রয়োগ করে এমন একটি চ্যানেলের জন্য আমার নিজের নিজস্ব মোড়ক রয়েছে:

public void Dispose()
{
        try
        {
            if (channel.State == CommunicationState.Faulted)
            {
                channel.Abort();
            }
            else
            {
                channel.Close();
            }
        }
        catch (CommunicationException)
        {
            channel.Abort();
        }
        catch (TimeoutException)
        {
            channel.Abort();
        }
        catch (Exception)
        {
            channel.Abort();
            throw;
        }
}

এটি ভালভাবে কাজ করে বলে মনে হচ্ছে এবং একটি ব্যবহারের ব্লক ব্যবহার করার অনুমতি দেয়।


0

নিম্নলিখিত সহায়কটি কল voidএবং অকার্যকর পদ্ধতিতে অনুমতি দেয়। ব্যবহার:

var calculator = new WcfInvoker<CalculatorClient>(() => new CalculatorClient());
var sum = calculator.Invoke(c => c.Sum(42, 42));
calculator.Invoke(c => c.RebootComputer());

ক্লাস নিজেই:

public class WcfInvoker<TService>
    where TService : ICommunicationObject
{
    readonly Func<TService> _clientFactory;

    public WcfInvoker(Func<TService> clientFactory)
    {
        _clientFactory = clientFactory;
    }

    public T Invoke<T>(Func<TService, T> action)
    {
        var client = _clientFactory();
        try
        {
            var result = action(client);
            client.Close();
            return result;
        }
        catch
        {
            client.Abort();
            throw;
        }
    }

    public void Invoke(Action<TService> action)
    {
        Invoke<object>(client =>
        {
            action(client);
            return null;
        });
    }
}

0

ক্লায়েন্টবেস ভিত্তিক প্রক্সি ক্লাস তৈরি করার প্রয়োজন ছাড়াই ক্লায়েন্টের ডিসপোজ () ওভাররাইড করুন, এছাড়াও চ্যানেল তৈরি এবং ক্যাশে পরিচালনা করার প্রয়োজন ছাড়াই ! (দ্রষ্টব্য যে ডাব্লুসিএফসিলেট একটি অবিস্ট্রাক্ট ক্লাস নয় এবং ক্লায়েন্টবেসের উপর ভিত্তি করে)

// No need for a generated proxy class
//using (WcfClient<IOrderService> orderService = new WcfClient<IOrderService>())
//{
//    results = orderService.GetProxy().PlaceOrder(input);
//}

public class WcfClient<TService> : ClientBase<TService>, IDisposable
    where TService : class
{
    public WcfClient()
    {
    }

    public WcfClient(string endpointConfigurationName) :
        base(endpointConfigurationName)
    {
    }

    public WcfClient(string endpointConfigurationName, string remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public WcfClient(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
        base(endpointConfigurationName, remoteAddress)
    {
    }

    public WcfClient(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
        base(binding, remoteAddress)
    {
    }

    protected virtual void OnDispose()
    {
        bool success = false;

        if ((base.Channel as IClientChannel) != null)
        {
            try
            {
                if ((base.Channel as IClientChannel).State != CommunicationState.Faulted)
                {
                    (base.Channel as IClientChannel).Close();
                    success = true;
                }
            }
            finally
            {
                if (!success)
                {
                    (base.Channel as IClientChannel).Abort();
                }
            }
        }
    }

    public TService GetProxy()
    {
        return this.Channel as TService;
    }

    public void Dispose()
    {
        OnDispose();
    }
}

0

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

using System;
using System.ServiceModel;
using MyApp.MyService; // The name you gave the service namespace

namespace MyApp.Helpers.Services
{
    public class MyServiceClientSafe : MyServiceClient, IDisposable
    {
        void IDisposable.Dispose()
        {
            if (State == CommunicationState.Faulted)
            {
                Abort();
            }
            else if (State != CommunicationState.Closed)
            {
                Close();
            }

            // Further error checks and disposal logic as desired..
        }
    }
}

দ্রষ্টব্য: এটি নিষ্পত্তি করার কেবল একটি সহজ বাস্তবায়ন, আপনি চাইলে আরও জটিল নিষ্পত্তি যুক্তি প্রয়োগ করতে পারেন।

তারপরে আপনি নিয়মিত পরিষেবা ক্লায়েন্টের সাথে করা আপনার সমস্ত কলকে নিরাপদ ক্লায়েন্টগুলির সাথে প্রতিস্থাপন করতে পারেন:

using (MyServiceClientSafe client = new MyServiceClientSafe())
{
    var result = client.MyServiceMethod();
}

আমি এই সমাধানটি পছন্দ করি কারণ এর জন্য আমার ইন্টারফেস সংজ্ঞাগুলিতে অ্যাক্সেস পাওয়ার প্রয়োজন হয় না এবং usingআমার কোডটি কম বেশি একইরকম দেখাতে দেওয়ার সময় আমি যে বিবৃতিটি আশা করব তা ব্যবহার করতে পারি।

এই থ্রেডের অন্যান্য মন্তব্যে নির্দেশিত হিসাবে ফেলে দেওয়া যেতে পারে এমন ব্যতিক্রমগুলি আপনাকে এখনও পরিচালনা করতে হবে।


-2

পদ্ধতিটি DynamicProxyপ্রসারিত করতে আপনি একটি ব্যবহার করতে পারেন Dispose()। এইভাবে আপনি কিছু করতে পারেন:

using (var wrapperdProxy = new Proxy<yourProxy>())
{
   // Do whatever and dispose of Proxy<yourProxy> will be called and work properly.
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.