2011-09-01 8 views
86

के तहत निपटने के लिए सर्वोत्तम प्रथाएं क्या हैं I SmtpClient को प्रबंधित करने के तरीके पर थोड़ा उलझन में है कि यह डिस्पोजेबल है, खासकर यदि मैं SendAsync का उपयोग करके कॉल करता हूं। संभवतः मुझे SendAsync पूरा होने तक निपटान नहीं करना चाहिए। लेकिन क्या मुझे इसे कभी भी कॉल करना चाहिए (उदाहरण के लिए, "उपयोग" का उपयोग करना)। परिदृश्य एक डब्ल्यूसीएफ सेवा है जो कॉल किए जाने पर समय-समय पर ईमेल भेजती है। अधिकांश गणना तेजी से है, लेकिन ईमेल भेजने से दूसरा या तो ऐसा हो सकता है, इसलिए Async बेहतर होगा।SmtpClient, SendAsync का उपयोग करने और .NET 4.0

क्या मुझे मेल भेजने पर हर बार एक नया SmtpClient बनाना चाहिए? क्या मुझे पूरे डब्ल्यूसीएफ के लिए एक बनाना चाहिए? मदद!

अद्यतन यदि यह कोई फर्क पड़ता है, तो प्रत्येक ईमेल हमेशा उपयोगकर्ता को अनुकूलित किया जाता है। डब्ल्यूसीएफ को एज़ूर पर होस्ट किया जाता है और जीमेल का उपयोग मेलर के रूप में किया जाता है।

+1

कैसे संभाल करने पर बड़ी तस्वीर के बारे में यह पोस्ट देखें IDisposable और async: http://stackoverflow.com/questions/974945/how-to-dispose-objects-having-asynchronous-methods -क्या –

उत्तर

107

नोट: .NET 4.5 SmtpClient async awaitable विधि SendMailAsync लागू करता है। निचले संस्करणों के लिए, नीचे वर्णित अनुसार SendAsync का उपयोग करें।


तुम हमेशा जल्द से जल्द संभावना पर IDisposable उदाहरणों के निपटान करना चाहिए। एसिंक कॉल के मामले में, संदेश भेजने के बाद यह कॉलबैक पर है।

var message = new MailMessage("from", "to", "subject", "body")) 
var client = new SmtpClient("host"); 
client.SendCompleted += (s, e) => { 
          client.Dispose(); 
          message.Dispose(); 
         }; 
client.SendAsync(message, null); 

यह थोड़ा कष्टप्रद SendAsync एक कॉलबैक को स्वीकार नहीं करता है।

+0

को अंतिम पंक्ति 'प्रतीक्षा' नहीं करनी चाहिए? – niico

+15

कोई भी कोड 'प्रतीक्षा' उपलब्ध होने से पहले लिखा गया था। यह घटना हैंडलर का उपयोग कर एक पारंपरिक कॉलबैक है। नए 'SendMailAsync' का उपयोग करते समय' प्रतीक्षा 'का उपयोग किया जाना चाहिए। – TheCodeKing

+1

SmtpException: मेल भेजने में विफलता .--> System.InvalidOperationException: इस समय एक एसिंक्रोनस ऑपरेशन शुरू नहीं किया जा सकता है। असीमित संचालन केवल एक एसिंक्रोनस हैंडलर या मॉड्यूल के भीतर या पृष्ठ जीवन चक्र में कुछ घटनाओं के दौरान शुरू किया जा सकता है। यदि कोई पृष्ठ निष्पादित करते समय यह अपवाद हुआ, तो सुनिश्चित करें कि पृष्ठ <% @ पृष्ठ Async = "true"%> चिह्नित है। यह अपवाद "एसिंक शून्य" विधि को कॉल करने का प्रयास भी इंगित कर सकता है, जो आम तौर पर एएसपी.NET अनुरोध प्रसंस्करण के भीतर असमर्थित है। इसके बजाए, एसिंक्रोनस विधि को कार्य वापस करना चाहिए, और कॉलर को इसका इंतजार करना चाहिए। – Mrchief

12

सामान्य रूप से, आईडीस्पोजेबल ऑब्जेक्ट्स जितनी जल्दी हो सके निपटान किया जाना चाहिए; किसी ऑब्जेक्ट पर आईडीस्पोजेबल को कार्यान्वित करना इस तथ्य को संवाद करने का इरादा है कि प्रश्न में कक्षा महंगे संसाधन रखती है जिसे निर्धारित रूप से जारी किया जाना चाहिए। हालांकि, अगर उन संसाधनों को बनाना महंगा है और आपको इन वस्तुओं में से बहुत से निर्माण करने की आवश्यकता है, तो यह एक उदाहरण को स्मृति में रखने और इसे पुन: उपयोग करने के लिए बेहतर (प्रदर्शन के अनुसार) हो सकता है। यह जानने का एक ही तरीका है कि इससे कोई फर्क पड़ता है: प्रोफाइल करें!

पुन: निपटान और असिनक: आप स्पष्ट रूप से using का उपयोग नहीं कर सकते हैं। इसके बजाय आप आमतौर पर SendCompleted स्थिति में वस्तु निपटान:

var smtpClient = new SmtpClient(); 
smtpClient.SendCompleted += (s, e) => smtpClient.Dispose(); 
smtpClient.SendAsync(...); 
128

मूल प्रश्न .NET 4 के लिए पूछा गया था, लेकिन यदि यह .NET 4.5 SmtpClient लागू करता है तो async प्रतीक्षा करने योग्य विधि SendMailAsync लागू करता है।

नतीजतन, अतुल्यकालिक रूप से ईमेल भेजने के लिए निम्नलिखित है:

public async Task SendEmail(string toEmailAddress, string emailSubject, string emailMessage) 
{ 
    using (var message = new MailMessage()) 
    { 
     message.To.Add(toEmailAddress); 

     message.Subject = emailSubject; 
     message.Body = emailMessage; 

     using (var smtpClient = new SmtpClient()) 
     { 
      await smtpClient.SendMailAsync(message); 
     } 
    } 
} 

यह SendAsync विधि का उपयोग कर से बचने के लिए बेहतर है।

+0

इससे बचने के लिए बेहतर क्यों है? मुझे लगता है कि यह आवश्यकताओं पर निर्भर करता है। – Jowen

+10

SendMailAsync() SendAsync() विधि के आसपास एक रैपर है वैसे भी। async/प्रतीक्षा रास्ता neater और अधिक सुरुचिपूर्ण है। यह बिल्कुल वही आवश्यकताओं को प्राप्त करेगा। –

+0

@BorisLipschitz SendMailAsync पर कॉलबैक विधि को मान पास करने का कोई तरीका है जैसे SendAsync पर था? UserState अब TaskCompletionSource प्रकार का है। –

5

ठीक है, पुराना सवाल मुझे पता है। लेकिन जब मैंने कुछ ऐसा करने की आवश्यकता थी तो मैंने खुद पर ठोकर खाई। मैं बस कुछ कोड साझा करना चाहता था।

मैं कई मेल को असीमित रूप से भेजने के लिए कई SmtpClients पर पुनरावृत्ति कर रहा हूं। मेरा समाधान TheCodeKing के समान है, लेकिन मैं इसके बजाय कॉलबैक ऑब्जेक्ट का निपटारा कर रहा हूं। मैं MailMessage को SendCompleted ईवेंट में प्राप्त करने के लिए उपयोगकर्ता के रूप में भी पास कर रहा हूं ताकि मैं उस पर भी निपटान कर सकूं।इस तरह:

foreach (Customer customer in Customers) 
{ 
    SmtpClient smtpClient = new SmtpClient(); //SmtpClient configuration out of this scope 
    MailMessage message = new MailMessage(); //MailMessage configuration out of this scope 

    smtpClient.SendCompleted += (s, e) => 
    { 
     SmtpClient callbackClient = s as SmtpClient; 
     MailMessage callbackMailMessage = e.UserState as MailMessage; 
     callbackClient.Dispose(); 
     callbackMailMessage.Dispose(); 
    }; 

    smtpClient.SendAsync(message, message); 
} 
+1

क्या प्रत्येक ईमेल भेजने के लिए एक नया SmtpClient बनाने का सबसे अच्छा अभ्यास है? –

+1

हां, एसिंक्रोनस भेजने के लिए, जब तक आप कॉलबैक में क्लाइंट का निपटान करते हैं ... – jmelhus

+1

धन्यवाद! और सिर्फ एक संक्षिप्त स्पष्टीकरण के लिए: www.codefrenzy.net/2012/01/30/how-asynchronous-is-smtpclient-sendasync –

4

आप देख सकते हैं क्यों यह निम्नलिखित टिप्पणी द्वारा SmtpClient के निपटान के लिए विशेष रूप से महत्वपूर्ण है:

public class SmtpClient : IDisposable 
    // Summary: 
    //  Sends a QUIT message to the SMTP server, gracefully ends the TCP connection, 
    //  and releases all resources used by the current instance of the System.Net.Mail.SmtpClient 
    //  class. 
    public void Dispose(); 

मेरी परिदृश्य ग्राहक निपटाने के बिना जीमेल का प्रयोग कई मेल भेजना में, मैं करने के लिए इस्तेमाल प्राप्त करें:

संदेश: सेवा उपलब्ध नहीं है, ट्रांसमिशन चैनल बंद कर रहा है। सर्वर प्रतिक्रिया थी: 4.7.0 अस्थायी सिस्टम समस्या। बाद में (डब्ल्यूएस) पुनः प्रयास करें। oo3sm17830090pdb.64 - gsmtp

+0

के केवल एक उदाहरण का उपयोग करने का प्रयास करें, यहां अपवाद को साझा करने के लिए धन्यवाद क्योंकि मैं अब तक बिना किसी निपटारे के एसएमटीपी क्लाइंट भेज रहा था। हालांकि मैं अपने स्वयं के एसएमटीपी सर्वर का उपयोग कर रहा हूं लेकिन एक अच्छा प्रोग्रामिंग अभ्यास हमेशा माना जाना चाहिए। आपकी त्रुटि से देखकर मुझे अब सावधानी बरतनी है और प्लेटफार्म विश्वसनीयता सुनिश्चित करने के लिए निपटान कार्यों को शामिल करने के लिए मेरे कोड को सुधारने के लिए सुधार होगा। – vibs2006