c# - "कॉपी स्थानीय" और परियोजना संदर्भों के लिए सबसे अच्छा अभ्यास क्या है?




.net visual-studio (12)

CopyLocal = false सेट करें बिल्ड समय को कम करेगा, लेकिन तैनाती के दौरान विभिन्न मुद्दों का कारण बन सकता है।

कई परिदृश्य हैं, जब आपको प्रतिलिपि स्थानीय 'को सही करने की आवश्यकता है, उदाहरण के लिए

  • शीर्ष-स्तरीय परियोजनाएं,
  • द्वितीय स्तर की निर्भरता,
  • डीएलएल प्रतिबिंब द्वारा बुलाया जाता है

SO प्रश्नों में वर्णित संभावित मुद्दे
" कॉपी-लोकल को कब सही किया जाना चाहिए और यह कब नहीं होना चाहिए? ",
" त्रुटि संदेश 'अनुरोधित प्रकारों में से एक या अधिक लोड करने में असमर्थ। अधिक जानकारी के लिए लोडर अपवाद संपत्ति पुनर्प्राप्त करें।' "
और इस सवाल के लिए का answer ।

CopyLocal = false सेट करने के साथ मेरा अनुभव सफल नहीं था। मेरे ब्लॉग पोस्ट "डॉट नॉट चेंज" कॉपी करें स्थानीय "परियोजना संदर्भों को झूठी, संदर्भों को समझने तक।"

मुद्दों को हल करने का समय कॉपीलोकल = झूठी सेटिंग के लाभों को अधिक वजन देता है।

मेरे पास एक बड़ी सी # समाधान फ़ाइल है (~ 100 परियोजनाएं), और मैं निर्माण के समय में सुधार करने की कोशिश कर रहा हूं। मुझे लगता है कि "कॉपी स्थानीय" हमारे लिए कई मामलों में अपमानजनक है, लेकिन मैं सर्वोत्तम प्रथाओं के बारे में सोच रहा हूं।

हमारे। एसएलएन में, हमारे पास असेंबली बी पर निर्भर करता है जो असेंबली सी पर निर्भर करता है। हमारे मामले में, दर्जनों "बी" और कुछ "सी" हैं। चूंकि ये सभी एसएसएलएन में शामिल हैं, इसलिए हम परियोजना संदर्भों का उपयोग कर रहे हैं। वर्तमान में सभी असेंबली $ (SolutionDir) / डीबग (या रिलीज) में बनती हैं।

डिफ़ॉल्ट रूप से, विजुअल स्टूडियो इन प्रोजेक्ट संदर्भों को "कॉपी स्थानीय" के रूप में चिह्नित करता है, जिसके परिणामस्वरूप प्रत्येक "सी" को "बी" बनाने के लिए एक बार $ (SolutionDir) / डीबग में कॉपी किया जाता है। यह अपमानजनक लगता है। अगर मैं सिर्फ "स्थानीय कॉपी करें" बंद कर देता हूं तो क्या गलत हो सकता है? बड़े सिस्टम वाले अन्य लोग क्या करते हैं?

जाँच करना:

बहुत सारे प्रतिक्रियाएं छोटे। एसएलएन फाइलों में निर्माण को तोड़ने का सुझाव देती हैं ... ऊपर दिए गए उदाहरण में, मैं पहले नींव वर्ग "सी" का निर्माण करता हूं, इसके बाद मॉड्यूल "बी" के बड़े पैमाने पर और फिर कुछ अनुप्रयोगों को " ए"। इस मॉडल में, मुझे बी से सी के लिए गैर-परियोजना संदर्भों की आवश्यकता है। जिस समस्या में मैं दौड़ता हूं वह यह है कि "डीबग" या "रिलीज" संकेत पथ में बेक हो जाता है और मैं अपने रिलीज बिल्ड को "बी" "सी" के डीबग बिल्ड के खिलाफ।

आप में से उन लोगों के लिए जो एकाधिक .sln फ़ाइलों में निर्माण को विभाजित करते हैं, आप इस समस्या का प्रबंधन कैसे करते हैं?


आप अपनी परियोजनाओं के संदर्भ डीएलएस के डीबग संस्करणों को इंगित कर सकते हैं। अपनी एमएसबिल्ड स्क्रिप्ट पर, आप /p:Configuration=Release सेट कर सकते हैं, इस प्रकार आपके पास आपके एप्लिकेशन और सभी सैटेलाइट असेंबली का रिलीज़ संस्करण होगा।


आपको CopyLocal मानों को बदलने की आवश्यकता नहीं है। आपको बस इतना करना है कि समाधान में सभी परियोजनाओं के लिए एक सामान्य $ (आउटपुटपैथ) पूर्व निर्धारित करें और $ (UseCommonOutputDirectory) को सत्य पर प्रीसेट करें। इसे देखें: http://blogs.msdn.com/b/kirillosenkov/archive/2015/04/04/using-a-common-intermediate-and-output-directory-for-your-solution.aspx


आम तौर पर, आपको केवल स्थानीय प्रतिलिपि बनाने की आवश्यकता होती है यदि आप अपनी परियोजना को अपने बिन बनाम डीएलएल का उपयोग करना चाहते हैं। कहीं और क्या है (जीएसी, अन्य परियोजनाएं, आदि)

मैं उन अन्य लोगों से सहमत हूं कि यदि आप संभवतः तो उस समाधान को तोड़ने के लिए प्रयास कर सकते हैं।

आप कॉन्फ़िगरेशन मैनेजर का उपयोग उस समाधान के भीतर स्वयं को अलग-अलग कॉन्फ़िगरेशन बनाने के लिए भी कर सकते हैं जो केवल परियोजनाओं के दिए गए सेट बनाएगा।

अगर सभी 100 परियोजनाएं एक-दूसरे पर भरोसा करती हैं तो यह अजीब लगेगा, इसलिए आपको इसे तोड़ने या कॉन्फ़िगरेशन प्रबंधक का उपयोग करने में मदद करने में सक्षम होना चाहिए।


तुम सही हो। CopyLocal पूरी तरह से अपने निर्माण के समय को मार डालेगा। यदि आपके पास एक बड़ा स्रोत पेड़ है तो आपको CopyLocal अक्षम करना चाहिए। दुर्भाग्यवश यह उतना आसान नहीं है जितना इसे साफ तरीके से अक्षम करना चाहिए। मैंने MSLUILD से .NET में संदर्भों के लिए CopyLocal (Private) सेटिंग को ओवरराइड करते हुए CopyLocal को अक्षम करने के बारे में इस सटीक प्रश्न का उत्तर दिया है। इसकी जांच - पड़ताल करें। साथ ही विजुअल स्टूडियो (2008) में बड़े समाधानों के लिए सर्वोत्तम अभ्यास।

कॉपीलोकल पर कुछ और जानकारी यहां दी गई है जैसा कि मैंने इसे देखा है।

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

मैंने लेख में बड़े स्रोत पेड़ों के निर्माण से निपटने के तरीके के बारे में लिखा है एमएसबिल्ड: विश्वसनीय निर्माण, भाग 2 बनाने के लिए सर्वोत्तम अभ्यास


पिछली परियोजना में मैंने परियोजना संदर्भों के साथ एक बड़े समाधान के साथ काम किया और प्रदर्शन की समस्या में भी टक्कर लगी। समाधान तीन गुना था:

  1. हमेशा स्थानीय संपत्ति को कॉपी पर सेट करें और कस्टम msbuild चरण के माध्यम से इसे लागू करें

  2. प्रत्येक प्रोजेक्ट के लिए एक ही निर्देशिका में आउटपुट निर्देशिका सेट करें (अधिमानतः $ (SolutionDir) के सापेक्ष

  3. डिफ़ॉल्ट सीएस लक्ष्य जो फ्रेमवर्क के साथ भेजे जाते हैं, वर्तमान में निर्मित प्रोजेक्ट की आउटपुट निर्देशिका में कॉपी किए जाने वाले संदर्भों के सेट की गणना करते हैं। चूंकि इसके लिए 'संदर्भ' संबंध के तहत एक पारगमन बंद करने की गणना की आवश्यकता है, यह बहुत महंगा हो सकता है। इसके लिए मेरा कामकाज GetCopyToOutputDirectoryItems को एक सामान्य लक्ष्य फ़ाइल (जैसे सामान्य. Common.targets ) में लक्षित करना था जिसे Microsoft.CSharp.targets के आयात के बाद प्रत्येक प्रोजेक्ट में आयात किया गया था। निम्नलिखित प्रतीत होने के लिए प्रत्येक प्रोजेक्ट फ़ाइल में परिणाम:

    <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        ... snip ...
      </ItemGroup>
      <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
      <Import Project="[relative path to Common.targets]" />
      <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
           Other similar extension points exist, see Microsoft.Common.targets.
      <Target Name="BeforeBuild">
      </Target>
      <Target Name="AfterBuild">
      </Target>
      -->
    </Project>
    

इसने हमारे निर्माण समय को कुछ घंटों (ज्यादातर स्मृति बाधाओं के कारण) से कुछ मिनटों में दिए गए समय पर कम कर दिया।

पुनः परिभाषित GetCopyToOutputDirectoryItems को GetCopyToOutputDirectoryItems C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets Common.targets C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets Common.targets C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets को Common.targets . Common.targets में Common.targets और 2,474-2,524 लाइनों की प्रतिलिपि बनाकर बनाया जा सकता है।

पूर्णता के लिए परिणामी लक्ष्य परिभाषा तब बन जाती है:

<!-- This is a modified version of the Microsoft.Common.targets
     version of this target it does not include transitively
     referenced projects. Since this leads to enormous memory
     consumption and is not needed since we use the single
     output directory strategy.
============================================================
                    GetCopyToOutputDirectoryItems

Get all project items that may need to be transferred to the
output directory.
============================================================ -->
<Target
    Name="GetCopyToOutputDirectoryItems"
    Outputs="@(AllItemsFullPathWithTargetPath)"
    DependsOnTargets="AssignTargetPaths;_SplitProjectReferencesByFileExistence">

    <!-- Get items from this project last so that they will be copied last. -->
    <CreateItem
        Include="@(ContentWithTargetPath->'%(FullPath)')"
        Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
            >
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(ContentWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>

    <CreateItem
        Include="@(_EmbeddedResourceWithTargetPath->'%(FullPath)')"
        Condition="'%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
            >
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(_EmbeddedResourceWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>

    <CreateItem
        Include="@(Compile->'%(FullPath)')"
        Condition="'%(Compile.CopyToOutputDirectory)'=='Always' or '%(Compile.CopyToOutputDirectory)'=='PreserveNewest'">
        <Output TaskParameter="Include" ItemName="_CompileItemsToCopy"/>
    </CreateItem>
    <AssignTargetPath Files="@(_CompileItemsToCopy)" RootFolder="$(MSBuildProjectDirectory)">
        <Output TaskParameter="AssignedFiles" ItemName="_CompileItemsToCopyWithTargetPath" />
    </AssignTargetPath>
    <CreateItem Include="@(_CompileItemsToCopyWithTargetPath)">
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(_CompileItemsToCopyWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>

    <CreateItem
        Include="@(_NoneWithTargetPath->'%(FullPath)')"
        Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always' or '%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"
            >
        <Output TaskParameter="Include" ItemName="AllItemsFullPathWithTargetPath"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectoryAlways"
                Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='Always'"/>
        <Output TaskParameter="Include" ItemName="_SourceItemsToCopyToOutputDirectory"
                Condition="'%(_NoneWithTargetPath.CopyToOutputDirectory)'=='PreserveNewest'"/>
    </CreateItem>
</Target>

इस कामकाज के साथ मैंने इसे एक समाधान में 120 परियोजनाओं के रूप में काम करने योग्य पाया, इसका मुख्य लाभ यह है कि परियोजनाओं का निर्माण आदेश अभी भी आपके समाधान को विभाजित करके हाथ से ऐसा करने के बजाय वीएस द्वारा निर्धारित किया जा सकता है ।


मेरा सुझाव है कि निर्भरता पेड़ के शीर्ष पर स्थित किसी भी को छोड़कर लगभग सभी परियोजनाओं के लिए स्थानीय = झूठी प्रतिलिपि बनाना। और शीर्ष सेट पर एक के सभी संदर्भों के लिए स्थानीय = सत्य कॉपी करें। मैं कई लोगों को आउटपुट निर्देशिका साझा करने का सुझाव देता हूं; मुझे लगता है कि यह अनुभव के आधार पर एक भयानक विचार है। यदि आपकी स्टार्टअप प्रोजेक्ट में एक डीएल के संदर्भ हैं जो कि किसी भी अन्य प्रोजेक्ट में आपके लिए एक संदर्भ है, तो किसी भी समय किसी एक्सेस \ साझाकरण उल्लंघन का अनुभव होगा, भले ही स्थानीय = प्रत्येक चीज़ पर झूठी प्रतिलिपि हो और आपका निर्माण विफल हो जाए। यह मुद्दा बहुत परेशान और ट्रैक करने में मुश्किल है। मैं पूरी तरह से एक शर्ड आउटपुट निर्देशिका से दूर रहने का सुझाव देता हूं और निर्भरता श्रृंखला के शीर्ष पर प्रोजेक्ट रखने के बजाय आवश्यक असेंबली को संबंधित फ़ोल्डर में लिखता हूं। यदि आपके पास "शीर्ष" पर कोई प्रोजेक्ट नहीं है, तो मैं सही जगह पर सबकुछ प्राप्त करने के लिए पोस्ट-बिल्ड कॉपी का सुझाव दूंगा। इसके अलावा, मैं कोशिश करता हूं और डीबगिंग की आसानी को ध्यान में रखता हूं। कोई भी exe परियोजनाओं मैं अभी भी स्थानीय = सच कॉपी छोड़ दें ताकि F5 डीबगिंग अनुभव काम करेगा।


मेरी राय में, 100 परियोजनाओं के साथ समाधान करना एक बड़ी गलती है। आप शायद अपने समाधान को वैध तार्किक छोटी इकाइयों में विभाजित कर सकते हैं, इस प्रकार रखरखाव और निर्माण दोनों को सरल बना सकते हैं।


मैं एक सामान्य निर्देशिका (उदाहरण के लिए .. \ bin) में निर्माण करता हूं, इसलिए मैं छोटे परीक्षण समाधान बना सकता हूं।


यदि आप प्रतिलिपि स्थानीय झूठी प्रतिलिपि बनाकर डीएलएल का संदर्भ देने के लिए एक केंद्रीय स्थान चाहते हैं तो जीएसी के बिना असफल हो जाएंगे जबतक कि आप ऐसा नहीं करते।

http://nbaked.wordpress.com/2010/03/28/gac-alternative/


यदि संदर्भ जीएसी के भीतर निहित नहीं है, तो हमें प्रतिलिपि स्थानीय को सही पर सेट करना होगा ताकि एप्लिकेशन काम करेगा, अगर हमें यकीन है कि संदर्भ जीएसी में पूर्वस्थापित किया जाएगा तो इसे गलत पर सेट किया जा सकता है।


यह सबसे अच्छा प्रेटिस नहीं हो सकता है, लेकिन इस तरह मैं काम करता हूं।

मैंने देखा कि प्रबंधित सी ++ अपनी सभी बाइनरी को $ (SolutionDir) / 'DebugOrRelease' में डंप करता है। तो मैंने वहां भी अपनी सभी सी # परियोजनाओं को छोड़ दिया। मैंने समाधान में परियोजनाओं के सभी संदर्भों के "स्थानीय प्रतिलिपि" को भी बंद कर दिया। मेरे छोटे 10 परियोजना समाधान में मुझे समय सुधार का उल्लेखनीय था। यह समाधान सी #, प्रबंधित सी ++, देशी सी ++, सी # webservice, और इंस्टॉलर परियोजनाओं का मिश्रण है।

शायद कुछ तोड़ दिया गया है, लेकिन चूंकि यह एकमात्र तरीका है जो मैं काम करता हूं, मुझे यह नहीं पता है।

यह जानना दिलचस्प होगा कि मैं क्या तोड़ रहा हूं।






msbuild