2017-02-01 6 views
6

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

इसे लागू करने के लिए मैंने this question से कोड अनुकूलित किया। सवाल में कोड निर्माता में

string dllLocation = @"C:MyLocation\dllLocation"; 
DirectoryInfo dir = new DirectoryInfo(dllLocation); 
var tempfiles = dir.GetFiles("*Adapter*.dll", SearchOption.AllDirectories);  // This will need to be changed when we go live 

    foreach (var file in tempfiles) 
    { 
     Assembly tempAssembly = null; 

     //Before loading the assembly, check all current loaded assemblies in case already loaded 
     //has already been loaded as a reference to another assembly 
     //Loading the assembly twice can cause major issues 
     foreach (Assembly loadedAssembly in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      //Check the assembly is not dynamically generated as we are not interested in these 
      if (loadedAssembly.ManifestModule.GetType().Namespace != "System.Reflection.Emit") 
      { 
       //Get the loaded assembly filename 
       string loadedFilename = loadedAssembly.CodeBase.Substring(loadedAssembly.CodeBase.LastIndexOf('/') + 1); 

       //If the filenames match, set the assembly to the one that is already loaded 
       if (loadedFilename.ToUpper() == file.Name.ToUpper()) 
       { 
        tempAssembly = loadedAssembly; 
        break; 
       } 
      } 
     } 

     //If the assembly is not aleady loaded, load it manually 
     if (tempAssembly == null) 
     { 
      tempAssembly = Assembly.LoadFrom(file.FullName); 
     } 

     Assembly a = tempAssembly; 

बाद में इस प्रकार जब विधि चलाता है हम इस

private IEnumerable<IUniversalDataAdapter> DataAdapters 
{ 
    get 
    { 
     foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) 
     { 
      foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IUniversalDataAdapter)))) 
      { 
       if (type.IsAbstract) continue; // can't create abstract classes 

       if (!dataAdapters.Any(y => y.GetType().Equals(type))) 
       { 
        IUniversalDataAdapter adapter = (IUniversalDataAdapter)Activator.CreateInstance(type); 
        dataAdapters.Add(adapter); 
       } 
      } 
     } 
     return dataAdapters; 
    } 
} 

जो सफलतापूर्वक डेटा एडेप्टर लोड करता है और उन्हें के रूप में मैं उम्मीद करेंगे इस्तेमाल की अनुमति देता है स्थित है।

प्रश्न के लिए अब

, कोड के पहले बिट में हम अगर मैं

var tempfiles = dir.GetFiles("*.dll", SearchOption.AllDirectories); 

दिनचर्या दुर्घटनाओं के लिए इसे बदल कोड की दूसरी बिट इस पर चलाता है से पहले लाइन

var tempfiles = dir.GetFiles("*Adapter*.dll", SearchOption.AllDirectories); 

है दिनचर्या

private IEnumerable<IDataValidator> DataValidators 
{ 
    get 
    { 
     if (validators.Count == 0) 
     { 
      foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) 
      { 
       foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IDataValidator)))) 
       { 
        if (!type.IsAbstract) 
        { 
         var validator = (IDataValidator)Activator.CreateInstance(type, context); 
         validators.Add(validator); 
        } 
       } 
      } 
     } 
     return validators; 
    } 
} 

संपादित करें: अपवाद जोड़ा

System.Reflection.ReflectionTypeLoadException was unhandled 
    HResult=-2146232830 
    Message=Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information. 
    Source=mscorlib 
    StackTrace: 
    at System.Reflection.RuntimeModule.GetTypes(RuntimeModule module) 
    at System.Reflection.RuntimeModule.GetTypes() 
    at System.Reflection.Assembly.GetTypes() 
    at TTi.Data.Pipeline.Server.Common.DataPipeline.get_DataValidators() in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 124 
    at TTi.Data.Pipeline.Server.Common.DataPipeline.CheckConfiguration(DataConfiguration config) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 528 
    at TTi.Data.Pipeline.Server.Common.DataPipeline.ProcessDataSource(IDataSource dataSource, DataConfiguration config) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Pipeline.Server.Common\DataPipeline.cs:line 213 
    at TTi.Data.Test.Program.ImportTest(String testFolders) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Test\Program.cs:line 362 
    at TTi.Data.Test.Program.Main(String[] args) in C:\Users\anorcross\Source\Workspaces\Universal System\Data\Main\TTi.Data\TTi.Data.Test\Program.cs:line 48 
    at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) 
    at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) 
    at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() 
    at System.Threading.ThreadHelper.ThreadStart_Context(Object state) 
    at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx) 
    at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) 
    at System.Threading.ThreadHelper.ThreadStart() 
InnerException: 

EndEdit:

DataValidators निश्चित रूप से DataAdapters दिनचर्या से पहले चलाता है। डेटा वैलिडेटर्स मुख्य कोड बेस में निहित कोड के बिट्स हैं और यह सुनिश्चित करने के लिए जांचें कि आयातित डेटा अपेक्षित प्रारूप का है। इस बिंदु पर हम उन्हें केवल लोड कर रहे हैं ताकि हम सुनिश्चित कर सकें कि आवश्यक लोग मौजूद हैं।

लोड किए गए असेंबली को देखते हुए, कोड के दोनों संस्करण एडाप्टर को आवश्यकतानुसार लोड करते हैं, लेकिन दूसरा संस्करण पहले की तुलना में अधिक लोड करता है जैसा कि मैं अपेक्षा करता हूं।

तो, tempfiles का दूसरा संस्करण कोड के पूरी तरह से असंबंधित हिस्से की तरह दिखता है? और यदि हम पर्याप्त डेटा एडेप्टर जोड़ते हैं तो क्या यह कोड क्रैश हो जाएगा?

+3

अपवाद और स्टैक ट्रेस क्या है? – rene

+1

कुछ प्रश्न: क्या सभी फ़ाइलें .dll वास्तव में .NET dlls के साथ समाप्त हो रही हैं? यदि आप अप्रबंधित डीएलएस लोड करने का प्रयास करते हैं तो यह क्रैश हो जाएगा। क्या कोई डीएलएस है जो आपके डीएलएस द्वारा उसी स्थान पर संदर्भित किया जाता है? या कहीं जहां सिस्टम उन्हें ढूंढ सकता है (यानी बिन फ़ोल्डर या% windir% \ system32 आदि)? क्या आप 64 बिट प्रक्रिया के रूप में चल रहे हैं और क्या आप किसी भी असेंबली को 32 बिट अनमांडेड डीएलएल संदर्भित करने का प्रयास करते हैं (यह भी क्रैश होगा)? – mortb

+0

@mortb हाँ, जहां तक ​​मैं देख सकता हूं कि वे हमारे कोड या Nuget संकुल के सभी बिट्स हैं। कार्यक्रम 32 या 64 बिट के रूप में विशिष्ट है और नेट 4.6 चला रहा है। मैं विशेष रूप से समाधान फ़ोल्डर में देख रहा हूँ। – Andrew

उत्तर

1

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

इसे ठीक करने के लिए अपने लूप को अधिक विशिष्ट बनाएं। यह स्पष्ट है कि आपके एडाप्टर को किसी भी सिस्टम डीएल में घोषित नहीं किया जाएगा, तो आप उनको फिर से क्यों लागू करेंगे?

foreach (var asm in AppDomain.CurrentDomain.GetAssemblies().Where(IsMyAssembly)) 
      { 
       foreach (var type in asm.GetTypes().Where(x => x.GetInterfaces().Contains(typeof(IDataValidator)))) 
       { 
//... 

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

+0

मैं एडाप्टर के साथ संस्करण का उपयोग करना चाहता था, लेकिन जब मैंने पूछा कि मुझे बताया गया था कि हम एडाप्टर पर नाम का हिस्सा होने पर भरोसा नहीं कर सकते। मेरे लिए अजीब लगता है क्योंकि वे सभी एडाप्टर होने जा रहे हैं तो उन्हें क्यों नहीं बुलाओ? मैं एक कॉन्फ़िगरेशन फ़ाइल का उपयोग करने का विचार लाऊंगा, हमारे पास उनमें से कई संख्याएं हैं – Andrew

+0

यह समस्या की तरह दिखता है। मैंने कुछ गिनती की (जो मुझे शायद पहले किया जाना चाहिए था)। कुछ भी लोड किए बिना मेरे पास 26 असेंबली लोड हो गईं। * एडाप्टर * के साथ यह 32 तक चला गया, अभी तक 6 एडाप्टर कोड किए गए हैं। केवल * 9 4 लोड किए गए थे, इसलिए संभवत: अतिरिक्त 62 असेंबली में कहीं कुछ डोडी चल रहा था। मैं सिस्टम में एक गैर-कोडिंग परिवर्तन कर दूंगा :) – Andrew

1

हमारे पास एक ही समस्या थी जब हमने सभी मिलान प्रकारों को एक डीएल से प्राप्त करने के लिए एक समारोह लिखा था। कोशिश पकड़ो नोट करें।

private static IEnumerable<Type> MatchingTypesFromDll<TBaseType>(string dllPath) 
    { 
     try 
     { 

      return Assembly 
       .LoadFrom(dllPath) 
       .GetExportedTypes() 
       .Where(TypeSatisfies<TBaseType>); 

     } 
     catch (Exception e) 
     { 
       Debug.WriteLine($"Exception {e} when trying to load from {dllPath}"); 
       return new Type[] {}; 
     } 
    } 

हमने अपवादों को अनदेखा कर दिया। यहां तक ​​कि न्यूजेट पैकेज में कुछ देशी डीएलएस या संभावित रूप से .dll नाम की फ़ाइलें हैं जो आप अपेक्षा नहीं करते हैं। अपवाद को पकड़ने और टूटी हुई फ़ाइल को अनदेखा करने की कोशिश करने के लिए कम प्रयास है, जो कि प्रबंधित डीएलएस हैं और जो नहीं हैं।

+0

मुझे समझ में दिलचस्पी है कि एक और क्यों है और यदि यह कभी भी मारा जाता है। – peval27

+0

ओउप्स .. मैंने कुछ अप्रासंगिक सामग्री को हटाने के लिए कोड को साफ़ करने का प्रयास किया। मैं इसे ठीक कर दूंगा। – bradgonesurfing

+0

तो आपकी सलाह है कि सभी 'डीएलएल' को ठीक से फ़िल्टर करने और केवल सही लोड करने का प्रयास करने के लिए, एक सामान्य 'अपवाद' पकड़ना है, न कि ओपीएस कोड फेंकता है ('प्रतिबिंब टाइप टाइप अपवाद') और केवल अनदेखा करें यह? भले ही आप कोई अपवाद पकड़े हों? – TheLethalCoder

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