2013-05-03 7 views
7

के साथ विफल रहता है मैं अलग-अलग ऐपडोमेन में अपना प्लगइन डीएल लोड करने की कोशिश कर रहा हूं, लेकिन लोड() विधि FileNotFoundException के साथ विफल हो जाती है। इसके अलावा, ऐसा लगता है कि AppDomainSetup की PrivateBinPath प्रॉपर्टी को कोई प्रभाव नहीं पड़ता है, क्योंकि लॉग में मैं "प्रारंभिक PrivatePath = NULL" देखता हूं। सभी प्लगइन मजबूत नाम है। आम तौर पर प्रत्येक प्लगइन [एप्लिकेशन स्टार्टप पथ] \ postplugins \ [plugindir] में संग्रहीत किया जाता है। अगर मैं [एप्लिकेशन स्टार्टप पथ] निर्देशिका के अंतर्गत प्लगइन उपनिर्देशिका डालता हूं, तो सब कुछ काम करता है। मैंने ऐपबेस संपत्ति को मैन्युअल रूप से बदलने की कोशिश की है लेकिन यह नहीं बदलेगा। यहाँAppDomain.Load() FileNotFoundException

public void LoadPostPlugins(IPluginsHost host, string pluginsDir) 
    { 
     _Host = host; 
     var privatePath = ""; 
     var paths = new List<string>(); 
     //build PrivateBinPath 
     var dirs = new DirectoryInfo(pluginsDir).GetDirectories(); 
     foreach (var d in dirs) 
     { 
      privatePath += d.FullName; 
      privatePath += ";"; 
     } 
     if (privatePath.Length > 1) privatePath = privatePath.Substring(0, privatePath.Length - 1); 
     //create new domain 
     var appDomainSetup = new AppDomainSetup { PrivateBinPath = privatePath }; 
     Evidence evidence = AppDomain.CurrentDomain.Evidence; 
     var sandbox = AppDomain.CreateDomain("sandbox_" + Guid.NewGuid(), evidence, appDomainSetup); 
     try 
     { 
      foreach (var d in dirs) 
      { 
       var files = d.GetFiles("*.dll"); 
       foreach (var f in files) 
       { 
        try 
        { 
         //try to load dll - here I get FileNotFoundException 
         var ass = sandbox.Load(AssemblyName.GetAssemblyName(f.FullName)); 
         var f1 = f; 
         paths.AddRange(from type in ass.GetTypes() 
             select type.GetInterface("PluginsCore.IPostPlugin") 
             into iface 
             where iface != null 
             select f1.FullName); 
        } 
        catch (FileNotFoundException ex) 
        { 
         Debug.WriteLine(ex); 
        } 
       } 
      } 
     } 
     finally 
     { 
      AppDomain.Unload(sandbox); 
     } 
     foreach (var plugin in from p in paths 
           select Assembly.LoadFrom(p) 
            into ass 
            select 
             ass.GetTypes().FirstOrDefault(t => t.GetInterface("PluginsCore.IPostPlugin") != null) 
             into type 
             where type != null 
             select (IPostPlugin)Activator.CreateInstance(type)) 
     { 
      plugin.Init(host); 
      plugin.GotPostsPartial += plugin_GotPostsPartial; 
      plugin.GotPostsFull += plugin_GotPostsFull; 
      plugin.PostPerformed += plugin_PostPerformed; 
      _PostPlugins.Add(plugin); 
     } 
    } 

और लॉग है:
यहाँ कोड है

'FBTest.vshost.exe' (Managed (v4.0.30319)): Loaded 'D:\VS2010Projects\PNotes - NET\pnfacebook\FBTest\bin\Debug\postplugins\pnfacebook\pnfacebook.dll', Symbols loaded. 
A first chance exception of type 'System.IO.FileNotFoundException' occurred in FBTest.exe 
System.IO.FileNotFoundException: Could not load file or assembly 'pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7' or one of its dependencies. The system cannot find the file specified. 
File name: 'pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7' 
    at System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) 
    at System.Reflection.RuntimeAssembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) 
    at System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, RuntimeAssembly reqAssembly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) 
    at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean forIntrospection) 
    at System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) 
    at System.Reflection.Assembly.Load(String assemblyString) 
    at System.UnitySerializationHolder.GetRealObject(StreamingContext context) 

    at System.AppDomain.Load(AssemblyName assemblyRef) 
    at PNotes.NET.PNPlugins.LoadPostPlugins(IPluginsHost host, String pluginsDir) in D:\VS2010Projects\PNotes - NET\pnfacebook\FBTest\PNPlugins.cs:line 71 


=== Pre-bind state information === 
LOG: User = ANDREYHP\Andrey 
LOG: DisplayName = pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7 
(Fully-specified) 
LOG: Appbase = file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/ 
LOG: Initial PrivatePath = NULL 
Calling assembly : (Unknown). 
=== 
LOG: This bind starts in default load context. 
LOG: No application configuration file found. 
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\v4.0.30319\config\machine.config. 
LOG: Post-policy reference: pnfacebook, Version=1.0.0.0, Culture=neutral, PublicKeyToken=9e2a2192d22aadc7 
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook.DLL. 
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook/pnfacebook.DLL. 
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook.EXE. 
LOG: Attempting download of new URL file:///D:/VS2010Projects/PNotes - NET/pnfacebook/FBTest/bin/Debug/pnfacebook/pnfacebook.EXE. 

उत्तर

14

जब आप उस तरह से AppDomain में एक विधानसभा लोड करते हैं, यह वर्तमान AppDomain के PrivateBinPath कि इस्तेमाल किया जाता है असेंबली खोजने के लिए।

अपने उदाहरण के लिए, जब मैं अपने App.config के लिए निम्न जोड़ा यह ठीक भाग गया:

<runtime> 
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> 
    <probing privatePath="[PATH_TO_PLUGIN]"/> 
    </assemblyBinding> 
</runtime> 

यह ही आप के लिए बहुत उपयोगी नहीं है।

मैं क्या बजाय एक वर्ग कहा जाता लोडर है कि इस तरह देखा एक नया विधानसभा कि IPostPlugin और IPluginsHost इंटरफेस निहित बनाने के लिए किया गया था, और यह भी:

public class Loader : MarshalByRefObject 
{ 
    public IPostPlugin[] LoadPlugins(string assemblyName) 
    { 
     var assemb = Assembly.Load(assemblyName); 

     var types = from type in assemb.GetTypes() 
       where typeof(IPostPlugin).IsAssignableFrom(type) 
       select type; 

     var instances = types.Select(
      v => (IPostPlugin)Activator.CreateInstance(v)).ToArray(); 

     return instances; 
    } 
} 

मुझे लगता है कि रखने के आवेदन जड़ में नए विधानसभा, और इसे प्लगइन निर्देशिकाओं में मौजूद होने की आवश्यकता नहीं है (यह कर सकता है लेकिन इसका उपयोग नहीं किया जाएगा क्योंकि एप्लिकेशन रूट पहले खोजा जाएगा)।

तब मुख्य AppDomain में मैं बजाय ऐसा किया:

sandbox.Load(typeof(Loader).Assembly.FullName); 

Loader loader = (Loader)Activator.CreateInstance(
    sandbox, 
    typeof(Loader).Assembly.FullName, 
    typeof(Loader).FullName, 
    false, 
    BindingFlags.Public | BindingFlags.Instance, 
    null, 
    null, 
    null, 
    null).Unwrap(); 

var plugins = loader.LoadPlugins(AssemblyName.GetAssemblyName(f.FullName).FullName); 

foreach (var p in plugins) 
{ 
    p.Init(this); 
} 

_PostPlugins.AddRange(plugins); 

तो मैं जाना जाता लोडर प्रकार का एक उदाहरण बनाने के लिए, और फिर उस प्लगइन AppDomain भीतर से प्लगइन उदाहरण बना करने के लिए मिल । इस तरह से PrivateBinPaths का उपयोग किया जाता है क्योंकि आप उन्हें बनना चाहते हैं।

एक और बात, निजी बिन पथ d.FullName जोड़ने के बजाय सापेक्ष हो सकते हैं ताकि आप अंतिम पथ सूची को छोटा रखने के लिए pluginsDir + Path.DirectorySeparatorChar + d.Name जोड़ सकें। हालांकि यह सिर्फ मेरी व्यक्तिगत वरीयता है! उम्मीद है की यह मदद करेगा।

+0

जेम्स, बहुत बहुत धन्यवाद! आखिर में मैं मार्शलबीरफॉफजेक्ट का उपयोग करने के बारे में स्पष्ट स्पष्टीकरण देखता हूं। दुर्भाग्यवश मेरे पास एक उत्तर को उपयोगी के रूप में चिह्नित करने के लिए पर्याप्त प्रतिष्ठा नहीं है (कम से कम 15 की आवश्यकता है) :( – dedpichto

+0

कोई समस्या नहीं! खुशी हुई यह मदद मिली :) –

+0

जब मैं इसे आज़माता हूं, हालांकि मैंने लोडप्लगिन-विधि जेनेरिक बनाया है, तो मुझे एक सीरियलाइजेशन अपवाद मिलता है। कोई सुझाव क्यों है कि यह क्यों हो सकता है? मैं देख सकता हूं कि असेंबली सैंडबॉक्स ऐप डोमेन में लोड की गई है। –

0

डेडपिक्टो और जेम्स थर्ले के लिए बहुत बहुत धन्यवाद; मैं एक पूर्ण समाधान को लागू करने में सक्षम था, मैंने this post में पोस्ट किया था।

मुझे एमिल बधा के समान समस्या थी: यदि आप "लोडर" कक्षा से वापस आने का प्रयास करते हैं तो एक इंटरफ़ेस जो वर्तमान ऐपडोमेन में अज्ञात एक ठोस वर्ग का प्रतिनिधित्व करता है, आपको "सीरियलाइजेशन अपवाद" मिलता है।

ऐसा इसलिए है क्योंकि ठोस प्रकार deserialized करने की कोशिश करता है। समाधान: मैं "लोडर" वर्ग से "कस्टम प्रॉक्सी" का एक ठोस प्रकार वापस लौटने में सक्षम था और यह काम करता है। विवरण के लिए संदर्भित पोस्ट देखें:

// Our CUSTOM PROXY: the concrete type which will be known from main App 
[Serializable] 
public class ServerBaseProxy : MarshalByRefObject, IServerBase 
{ 
    private IServerBase _hostedServer; 

    /// <summary> 
    /// cstor with no parameters for deserialization 
    /// </summary> 
    public ServerBaseProxy() 
    { 

    } 

    /// <summary> 
    /// Internal constructor to use when you write "new ServerBaseProxy" 
    /// </summary> 
    /// <param name="name"></param> 
    public ServerBaseProxy(IServerBase hostedServer) 
    { 
     _hostedServer = hostedServer; 
    }  

    public string Execute(Query q) 
    { 
     return(_hostedServer.Execute(q)); 
    } 

} 

यह प्रॉक्सी वापस लौटाया जा सकता है और इसका उपयोग वास्तविक कंक्रीट प्रकार के रूप में किया जा सकता है!

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