2011-06-29 14 views
8

मैं एक छोटी प्लगइन्स लाइब्रेरी लिख रहा हूं जो .NET Framework 4.0 का उपयोग करके प्लगइन को अलग करने के लिए ऐप डोमेन का उपयोग करता है। इसलिए प्रत्येक प्लगइन में जो कोड जाता है वह मेरे नियंत्रण से बाहर होता है। जब प्लगइन में से एक में एक अनचाहे अपवाद उठाया जाता है, तो मैंने परिणामों को एक मिश्रित बैग के रूप में देखा है। वे इस प्रकार हैं।चाइल्ड ऐप में अनचाहे अपवाद मुख्य प्रक्रिया को दुर्घटनाग्रस्त होने से रोका जा सकता है?

जब प्लगइन के मुख्य थ्रेड में अनचाहे अपवाद फेंक दिया जाता है, प्लगइन की निष्पादन विधि को कॉल करने वाला मुख्य प्लग करने योग्य ऐप इसे साफ़ करने और इसे साफ़ करने में सक्षम होता है। वहां कोई समस्या नहीं है। हालांकि,

  1. प्लगइन एक WinForms प्लगइन में आधारित एप्लिकेशन की विधि निष्पादित और एक बिना क्रिया का अपवाद WinForm आवेदन में फेंक दिया जाता है के लिए एक संदेश पाश शुरू होता है (यानी एक रूप में) तो प्लगेबल एप्लिकेशन केवल पकड़ कर सकते हैं अगर यह दृश्य स्टूडियो डीबगर से चल रहा है तो अपवाद। अन्यथा (जब वीएस के बाहर बुलाया जाता है) मुख्य प्लग करने योग्य ऐप प्लगइन के साथ दुर्घटनाग्रस्त हो जाता है।

  2. यदि अनचाहे अपवाद प्लगइन की निष्पादन विधि द्वारा उत्पन्न एक अलग थ्रेड में फेंक दिया गया है, तो प्लग करने योग्य ऐप को अपवाद को पकड़ने का कोई मौका नहीं है और यह क्रैश हो जाता है।

मैंने नीचे दिए गए लिंक पर इस व्यवहार को अनुकरण करने के लिए एक साधारण वीएस 2010 प्रोजेक्ट बनाया है। http://www.mediafire.com/file/1af3q7tzl68cx1p/PluginExceptionTest.zip

इसमें प्लगेबल अनुप्रयोग में मुख्य विधि इस

namespace PluginExceptionTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      Console.WriteLine("Press enter to load plugin"); 
      Console.ReadLine(); 

      Assembly entryAsm = Assembly.GetEntryAssembly(); 
      string assemblyFileName = Path.Combine(Path.GetDirectoryName(entryAsm.Location), "EvilPlugin.exe"); 


      AppDomainSetup domainSetup = new AppDomainSetup(); 
      AppDomain domain = AppDomain.CreateDomain("PluginDomain", null, domainSetup); 
      PluginBase plugin = (PluginBase)domain.CreateInstanceFromAndUnwrap(assemblyFileName, "EvilPlugin.Plugin"); 

      Console.WriteLine("Plugin Loaded."); 

      //SCENARIO 1: WinForms based plugin 
      Console.WriteLine("Press Enter to execute winforms plugin. (Remember to click on the button in the form to raise exception)"); 
      Console.ReadLine(); 

      try 
      { 
       plugin.ExecuteWinApp(); 
      } 
      catch (Exception) 
      { 
       //The exception is caught and this gets executed only when running in visual studio debugger. Else application exits. Why? 
       Console.WriteLine("WinForms plugin exception caught. However same does not happen when run out of visual studio debugger. WHY?"); 
      } 

      //SCENARIO 2: WinForms based plugin 
      Console.WriteLine("Press Enter to execute threading plugin, wait for 3 seconds and the app will exit. How to prevent app from exiting due to this?"); 
      Console.ReadLine(); 
      try 
      { 
       plugin.ExecuteThread(); 
      } 
      catch (Exception) 
      { 
       //This never gets executed as the exception is never caught. Application exits. Why? 
       Console.WriteLine("WinForms plugin exception caught"); 
      } 

      Console.ReadLine(); 
     } 
    } 
} 

तरह लग रहा है इस प्लगइन परियोजना के लिए कोड है। यह प्लगइनबेस क्लास से ऊपर प्लग करने योग्य ऐप प्रोजेक्ट में विरासत में मिलता है।

namespace EvilPlugin 
{ 
    public class Plugin:PluginBase 
    { 
     public Plugin():base() 
     { 

     } 

     public override void ExecuteWinApp() 
     {    
      Application.Run(new Form1());    
     } 

     public override void ExecuteThread() 
     { 
      Thread t = new Thread(new ThreadStart(RaiseEx));   
      t.Start(); 
     } 

     private void RaiseEx() 
     { 
      Thread.Sleep(3000); 
      throw new Exception("Another Evil Exception in a seperate thread"); 
     } 
    } 
} 

अंत में इस प्लगइन

namespace EvilPlugin 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void btnException_Click(object sender, EventArgs e) 
     { 
      throw new Exception("Evil Exception"); 
     } 
    } 
} 

कैसे मैं दो स्थितियों (1 और 2) ऊपर उल्लेख किया है की वजह से बाहर निकलने से मुख्य प्रक्रिया को रोका जा सकता में फार्म से कोड है?

अग्रिम धन्यवाद।

उत्तर

1

WinForms अपवाद को संभालने के लिए। आप PluginBase कक्षा में इस तरह के ThreadExceptions के लिए "जाल" सेट कर सकते हैं:

public abstract class PluginBase:MarshalByRefObject 
{ 
    protected PluginBase() 
    { 
     System.Windows.Forms.Application.ThreadException += 
      (o, args) => 
      { 
       throw new Exception("UntrappedThread Exception:" + args.Exception); 
      }; 

    } 

    public abstract void ExecuteWinApp(); 
    public abstract void ExecuteThread(); 
} 

डिफ़ॉल्ट रूप से, यह आप "अपवाद विंडो" दिखाई देगा। लेकिन अगर उपलब्ध कराया गया तो इस हैंडलर को मिल जाएगा।

अन्य धागे से अपवाद को पकड़ने के लिए। अब कोई रास्ता नहीं है। सबसे अच्छा आप कर सकते हैं अपवाद को फेंकने के बारे में एक अधिसूचना है।

AppDomain domain = AppDomain.CreateDomain("PluginDomain", null, domainSetup); 
    domain.UnhandledException += 
     (o, eventArgs) => 
      { 
       Console.WriteLine("Exception was caught from other AppDomain: " + eventArgs.ExceptionObject); 
       Console.WriteLine("CLR is terminating?: " + eventArgs.IsTerminating); 
      }; 
+0

तो ऐसा लगता है कि एक ऐपडोमेन दृष्टिकोण प्लगइन्स लाइब्रेरी के लिए जाने का तरीका नहीं है क्योंकि मैं नहीं चाहता कि मेरा मुख्य ऐप केवल क्रैश हो जाए क्योंकि प्लगइन ने इसे थ्रेड के अंदर अपवाद का कारण बना दिया था। मेरे लिए एक प्रक्रिया के अंदर लपेटने के पुराने तरीके पर मुझे लगता है। जब एमएसडीएन कहता है कि ऐपडोमेन्स असेंबली को अलग करने का एक तरीका प्रदान करते हैं तो यह 100% सही नहीं है। – Harindaka

+1

उत्तर के लिए धन्यवाद DiVan – Harindaka

+1

AppDomain डेटा को अलग करता है, निष्पादन नहीं। – DiVan

संबंधित मुद्दे