2010-11-05 12 views
43

मेरे पास एक प्रोजेक्ट है जो DLLs और EXE के बगल में \Templates फ़ोल्डर में टेम्पलेट स्टोर करता है।मैं विधानसभा को कैसे परिवर्तित कर सकता हूं। CodeBase C# में एक फाइल सिस्टम पथ में?

मैं क्रम में इस फ़ाइल पथ निर्धारित करने के लिए चाहते हैं, लेकिन एक तकनीक है कि एक इकाई परीक्षण के अंदर के साथ ही उत्पादन में काम करेंगे का उपयोग कर (और मैं NUnit में छाया-नकल निष्क्रिय करने के लिए नहीं चाहता!)

Assembly.Location कोई अच्छा नहीं है क्योंकि यह न्यूटिट के तहत चलते समय छाया-प्रतिबिंबित असेंबली के पथ को लौटाता है।

Environment.CommandLine क्योंकि NUnit एट अल यह NUnit करने के लिए पथ, अपने प्रोजेक्ट के लिए नहीं देता में सीमित उपयोग का भी है।

Assembly.CodeBase होनहार लग रहा है, लेकिन यह एक यूएनसी पथ यहां है:

file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe 

अब मैं यह एक स्थानीय फाइल सिस्टम पथ में स्ट्रिंग परिवर्तन का उपयोग कर बदल सकती है, लेकिन मैं वहाँ करने का एक क्लीनर जिस तरह से यह में दफन है पर शक .NET ढांचे कहीं कहीं। किसी को यह करने का एक अनुशंसित तरीका पता है?

(एक अपवाद फेंकने अगर यूएनसी पथ नहीं है एक file:/// यूआरएल इस संदर्भ में पूरी तरह से ठीक है)

+0

संभावित डुप्ल आईसीएटी [क्या फाइल यूआरआई को ड्राइव अक्षरों के साथ पथ में बदलने के लिए एक .NET Framework विधि है?] (http://stackoverflow.com/questions/278761/is-there-a-net-framework-method-for-converting- फ़ाइल-यूरिस-टू-पथ-साथ-ड्राइव-ले) – nawfal

उत्तर

87

आप System.Uri.LocalPath उपयोग करने की आवश्यकता:

string localPath = new Uri("file:///D:/projects/MyApp/MyApp/bin/debug/MyApp.exe").LocalPath; 

तो अगर आप चाहते हैं वर्तमान में क्रियान्वित विधानसभा के मूल स्थान:

string localPath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath; 
+0

सुंदर। बहुत धन्यवाद। –

+0

Awesomeballs! धन्यवाद धन्यवाद धन्यवाद! –

+4

ध्यान दें कि यह तब काम नहीं करता है जब किसी निर्देशिका में '#' नाम होता है – drake7707

5

यह काम करना चाहिए:

ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap(); 
Assembly asm = Assembly.GetCallingAssembly(); 
String path = Path.GetDirectoryName(new Uri(asm.EscapedCodeBase).LocalPath); 

string strLog4NetConfigPath = System.IO.Path.Combine(path, "log4net.config"); 

मैं इसका उपयोग एक स्टैंडअलोन log4net.config फ़ाइल का उपयोग कर डीएलएल पुस्तकालयों के भीतर से लॉग इन करने में सक्षम होने के लिए कर रहा हूं।

17

Assembly.CodeBase होनहार लग रहा है, लेकिन यह एक यूएनसी पथ यहां है:

कि यह कुछ का अनुमान है ध्यान दें है एक file uri, एक UNC path नहीं।


आप हाथ से स्ट्रिंग मैनिपुलेशन करके इसे हल करते हैं। गंभीरता से।

आप निम्नलिखित निर्देशिका (शब्दशः) के साथ इतने पर पा सकते हैं अन्य सभी तरीकों का प्रयास करें:

C:\Test\Space()(h#)(p%20){[a&],[email protected],p%,+}.,\Release 

यह एक वैध, अगर कुछ हद तक असामान्य, विंडोज मार्ग है। (कुछ लोगों को या तो वहाँ रास्तों में इन पात्रों में से एक, का अधिकार होगा, और आप आप विधि उन सभी के लिए काम करने के लिए चाहेगा?)

उपलब्ध कोड बेस (we do not want Location, right?) गुण तो (पर हैं मेरे विन 7 के साथ।नेट 4):

assembly.CodeBase -> file:///C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release 

assembly.EscapedCodeBase -> file:///C:/Test/Space(%20)(h%23)(p%20)%7B%5Ba%26%5D,[email protected],p%,+%7D.,/Release 

आप ध्यान देंगे:

  • CodeBase भाग निकले नहीं है सब पर, यह सिर्फ नियमित रूप से स्थानीय पथ file:/// लगी होती है और बैकस्लैश बदल दिया। इस प्रकार, यह System.Uri पर इसे खिलाने के लिए काम नहीं करता है।
  • EscapedCodeBase पूरी तरह से भाग निकले नहीं है (मैं नहीं जानते हैं कि यह एक बग है या अगर यह URI scheme की एक कमी है):
    • नोट कैसे अंतरिक्ष चरित्र () %20
    • करने के लिए अनुवाद लेकिन %20 अनुक्रम भी%20 पर अनुवाद करता है! (प्रतिशत % बिल्कुल से बच नहीं है)
    • कोई भी इस उलझन में मूल को पुनर्निर्माण कर सकता है!
स्थानीय फ़ाइलों के लिए

(और है कि वास्तव में सब है मैं, CodeBase सामान के लिए के बारे में परवाह करता हूँ क्योंकि अगर फ़ाइल स्थानीय नहीं है, तो आप शायद .Location मेरे लिए वैसे भी निम्नलिखित कार्यों का उपयोग करना चाहते हैं (ध्यान दें कि यह नहीं है सबसे सुंदर या तो:

public static string GetAssemblyFullPath(Assembly assembly) 
    { 
     string codeBasePseudoUrl = assembly.CodeBase; // "pseudo" because it is not properly escaped 
     if (codeBasePseudoUrl != null) { 
      const string filePrefix3 = @"file:///"; 
      if (codeBasePseudoUrl.StartsWith(filePrefix3)) { 
       string sPath = codeBasePseudoUrl.Substring(filePrefix3.Length); 
       string bsPath = sPath.Replace('/', '\\'); 
       Console.WriteLine("bsPath: " + bsPath); 
       string fp = Path.GetFullPath(bsPath); 
       Console.WriteLine("fp: " + fp); 
       return fp; 
      } 
     } 
     System.Diagnostics.Debug.Assert(false, "CodeBase evaluation failed! - Using Location as fallback."); 
     return Path.GetFullPath(assembly.Location); 
    } 

मुझे यकीन है एक बेहतर समाधान के साथ आ सकता है कर रहा हूँ शायद एक भी एक समाधान है कि उचित URL एन/CodeBase संपत्ति अगर की डिकोडिंग करता है के साथ आ सकता है यह एक स्थानीय मार्ग है, लेकिन यह देखते हुए कि कोई भी file:/// को बंद कर सकता है डी इसके साथ किया जा सकता है, मैं कहूंगा कि यह समाधान काफी अच्छा है, अगर निश्चित रूप से वास्तव में बदसूरत है।

+1

यदि यह यूएनसी पथ है तो यह फ़ाइल है: //server/share/path/to/assembly.dll (केवल 2 स्लेश)। – Joshua

+0

@ जोशुआ - आपका कहना है कि एक '\\ सर्वर \ ...' पथ स्थानीय ड्राइव होने पर 3 की बजाय केवल दो स्लैश के साथ एन्कोड किया गया है? –

+0

@ जोशुआ - क्या आप जानते हैं कि कैसे \\? \ UNC \ server \ share' पथ एन्कोड किए गए हैं? –

1

आप इस प्रश्न में चिह्नित के बाद से NUnit, आप भी AssemblyHelper.GetDirectoryName उपयोग कर सकते हैं मूल क्रियान्वित विधानसभा की सूची प्राप्त करने के लिए: जटिल रास्तों सहित

using System.Reflection; 
using NUnit.Framework.Internal; 
... 
string path = AssemblyHelper.GetDirectoryName(Assembly.GetExecutingAssembly()) 
2

एक और समाधान,:

public static string GetPath(this Assembly assembly) 
    { 
     return Path.GetDirectoryName(assembly.GetFileName()); 
    } 

    public static string GetFileName(this Assembly assembly) 
    { 
     return assembly.CodeBase.GetPathFromUri(); 
    } 

    public static string GetPathFromUri(this string uriString) 
    { 
     var uri = new Uri(Uri.EscapeUriString(uriString)); 
     return String.Format("{0}{1}", Uri.UnescapeDataString(uri.PathAndQuery), Uri.UnescapeDataString(uri.Fragment)); 
    } 

और परीक्षण:

[Test] 
    public void GetPathFromUriTest() 
    { 
     Assert.AreEqual(@"C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release", @"file:///C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release".GetPathFromUri()); 
     Assert.AreEqual(@"C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release", @"file://C:/Test/Space()(h#)(p%20){[a&],[email protected],p%,+}.,/Release".GetPathFromUri()); 
    } 

    [Test] 
    public void AssemblyPathTest() 
    { 
     var asm = Assembly.GetExecutingAssembly(); 

     var path = asm.GetPath(); 
     var file = asm.GetFileName(); 

     Assert.IsNotEmpty(path); 
     Assert.IsNotEmpty(file); 

     Assert.That(File  .Exists(file)); 
     Assert.That(Directory.Exists(path)); 
    } 
+0

अच्छा! लेकिन मैं बैकस्लाश पसंद करूंगा, इसलिए मैं 'GetPathFromUri' से' Path.GetFullPath' के माध्यम से परिणाम पास कर दूंगा। – tm1

+0

नेटवर्क पथों का समर्थन करने के लिए आपको Uri.Host को ध्यान में रखना होगा। – tm1

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

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