.NET 4.0 के तहत SmtpClient, SendAsync और Dispose का उपयोग करने के लिए सर्वोत्तम अभ्यास क्या हैं


116

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

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

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


1
इस पोस्ट को बड़ी तस्वीर के बारे में देखें कि किस तरह से आईडीसॉरोबल और एसिंक्स को हैंडल किया जाता है: stackoverflow.com/questions/974945/…
क्रिस हास

जवाबों:


139

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


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

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एक कॉलबैक स्वीकार नहीं करता है।


क्या अंतिम पंक्ति में 'वेट' नहीं होना चाहिए?
नीको

19
awaitउपलब्ध होने से पहले यह कोड नहीं लिखा गया था। यह ईवेंट हैंडलर का उपयोग करके एक पारंपरिक कॉलबैक है। awaitयदि नए का उपयोग करना चाहिए SendMailAsync
TheCodeKing

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

1
क्या nullदूसरे पैरामीटर के रूप में प्रदान करना सुरक्षित है SendAsync(...)?
jocull

167

मूल प्रश्न .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 विधि का उपयोग करने से बचना बेहतर है।


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

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

2
@RodHartzell आप हमेशा उपयोग कर सकते हैं। ContinueWith ()
बोरिस

2
क्या इसका उपयोग करना बेहतर है - या निपटान - या कोई व्यावहारिक अंतर नहीं है? क्या SendMailAsync द्वारा निष्पादित होने से पहले smtpClient को ब्लॉक किया जा सकता है, उस अंतिम 'ब्लॉक' का उपयोग करना संभव नहीं है?
नीको

6
MailMessageका भी डिस्पोजल होना चाहिए।
TheCodeKing

16

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

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

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

6

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

मैं कई SmtpClients को कई मेल भेज रहा हूँ जो अतुल्यकालिक रूप से भेज रहा है। मेरा समाधान TheCodeKing के समान है, लेकिन मैं इसके बजाय कॉलबैक ऑब्जेक्ट का निपटान कर रहा हूं। मैं MailMessage को UserToken के रूप में भी भेज रहा हूं ताकि 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);
}

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

1
हाँ, अतुल्यकालिक भेजने के लिए, जब तक आप कॉलबैक में ग्राहक का निपटान करते हैं ...
jmelhus

1
धन्यवाद! और सिर्फ एक संक्षिप्त विवरण के लिए: www.codef Mania.net/2012/01/30/how-asynchronous-is-smtpclient-sendasync
Martín Coll

1
यह सबसे सरल और सटीक उत्तरों में से एक है जो मुझे smtpclient.sendAsync फ़ंक्शन और इसके संबंधित डिस्पोज़ल हैंडलिंग के लिए स्टैकओवरफ़्लो पर मिला । मैंने एक अतुल्यकालिक थोक मेल भेजने वाली लाइब्रेरी लिखी। जैसा कि मैं हर कुछ मिनट में 50+ संदेश भेजता हूं, इसलिए डिस्पोजिंग पद्धति को निष्पादित करना मेरे लिए बहुत महत्वपूर्ण कदम था। इस कोड ने मुझे वह हासिल करने में मदद की। मैं इस मामले में जवाब दूंगा जब मुझे इस कोड में कुछ सूत्र बहु ​​थ्रेडिंग वातावरण के दौरान मिले।
vibs2006

1
जब तक आप एक्सचेंज सर्वर को कॉन्फ़िगर करने की क्षमता (यदि आप उपयोग करते हैं) की क्षमता नहीं है, तो मैं कह सकता हूं कि यह एक अच्छा तरीका नहीं है। सर्वर जैसे अपवाद को फेंक सकता है 4.3.2 The maximum number of concurrent connections has exceeded a limit, closing trasmission channel। इसके बजाय केवल एक उदाहरण का उपयोग करने का प्रयास करेंSmtpClient
ibubi

6

आप देख सकते हैं कि निम्नलिखित टिप्पणी से 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 अस्थाई सिस्टम समस्या। बाद में पुन: प्रयास करें (WS)। oo3sm17830090pdb.64 - gsmtp


1
यहाँ अपना अपवाद साझा करने के लिए धन्यवाद, क्योंकि मैं अब तक बिना निपटान के SMTP ग्राहक भेज रहा था। हालांकि मैं अपने खुद के एसएमटीपी सर्वर का उपयोग कर रहा हूं लेकिन एक अच्छा प्रोग्रामिंग अभ्यास हमेशा माना जाना चाहिए। आपकी त्रुटि को देखते हुए मुझे अब सतर्कता मिल गई है और प्लेटफ़ॉर्म विश्वसनीयता सुनिश्चित करने के लिए डिस्पोज़ फ़ंक्शंस को शामिल करने के लिए अपने कोड को सुधारना होगा।
vibs2006
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.