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




.net visual-studio (15)

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

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

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

जाँच करना:

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

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


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

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

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

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


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

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


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

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


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


खैर, मुझे निश्चित रूप से पता नहीं है कि समस्याएं कैसे काम करती हैं, लेकिन मेरे पास एक निर्माण समाधान से संपर्क था जिसने स्वयं को ऐसी सभी फाइलों में मदद की जो प्रतीकात्मक लिंक की मदद से रैमडिस्क डालते थे।

  • सी: \ समाधान फ़ोल्डर \ bin -> रैमडिस्क आर: \ समाधान फ़ोल्डर \ bin \
  • सी: \ समाधान फ़ोल्डर \ obj -> रैमडिस्क आर: \ समाधान फ़ोल्डर \ obj \

  • आप अतिरिक्त दृश्य स्टूडियो भी बता सकते हैं जो निर्माण के लिए उपयोग की जाने वाली temp निर्देशिका है।

असल में यह सब कुछ नहीं था। लेकिन यह वास्तव में प्रदर्शन की मेरी समझ मारा।
100% प्रोसेसर उपयोग और सभी निर्भरताओं के साथ 3 मिनट से कम में एक विशाल परियोजना।


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


मैं आपको उस विषय पर पेट्रिक स्मेचिया के लेख पढ़ने के लिए सुझाव दूंगा:

CC.Net VS प्रोजेक्ट प्रतिलिपि स्थानीय संदर्भ असेंबली विकल्प पर सेट पर भरोसा करते हैं। [...] न केवल यह संकलन समय (एनयूनीट के मामले में x3) में काफी वृद्धि हुई है, बल्कि यह आपके कामकाजी माहौल को भी खराब कर देती है। अंतिम लेकिन कम से कम नहीं, ऐसा करने से संभावित समस्याओं को संस्करणित करने का जोखिम सामने आता है। बीटीडब्ल्यू, एनडॉन्डर एक चेतावनी उत्सर्जित करेगा यदि उसे समान नाम के साथ 2 अलग-अलग निर्देशिकाओं में 2 असेंबली मिलती हैं, लेकिन समान सामग्री या संस्करण नहीं।

करने के लिए सही बात यह है कि 2 निर्देशिका $ RootDir $ \ bin \ Debug और $ RootDir $ \ bin \ Release को परिभाषित करें, और इन निर्देशिकाओं में असेंबली उत्सर्जित करने के लिए अपनी VisualStudio परियोजनाओं को कॉन्फ़िगर करें। सभी परियोजना संदर्भों को डीबग निर्देशिका में असेंबली का संदर्भ देना चाहिए।

आप इस परियोजना को भी पढ़ सकते हैं ताकि आप अपनी परियोजना संख्या को कम कर सकें और अपना संकलन समय सुधार सकें।


हमारी "सर्वोत्तम अभ्यास" कई परियोजनाओं के समाधान से बचने के लिए है। हमारे पास असेंबली के मौजूदा संस्करणों के साथ "मैट्रिक्स" नामक एक निर्देशिका है, और सभी संदर्भ इस निर्देशिका से हैं। यदि आप कुछ प्रोजेक्ट बदलते हैं और आप कह सकते हैं "अब परिवर्तन पूरा हो गया है" तो आप असेंबली को "मैट्रिक्स" निर्देशिका में कॉपी कर सकते हैं। इसलिए इस परियोजना पर निर्भर सभी परियोजनाओं में वर्तमान (= नवीनतम) संस्करण होगा।

यदि आपके पास समाधान में कुछ परियोजनाएं हैं, तो निर्माण प्रक्रिया बहुत तेज है।

आप विजुअल स्टूडियो मैक्रोज़ या "मेनू -> टूल्स -> बाहरी टूल्स ..." के साथ "प्रतिलिपि असेंबली में मैट्रिक्स निर्देशिका" चरण को स्वचालित कर सकते हैं।


आप ऐसे फ़ोल्डर का उपयोग करने का प्रयास कर सकते हैं जहां परियोजनाओं के बीच साझा की जाने वाली सभी असेंबली की प्रतिलिपि बनाई जाएगी, फिर एक DEVPATH पर्यावरण चर और सेट करें

<developmentMode developerInstallation="true" />

प्रत्येक डेवलपर के वर्कस्टेशन पर machine.config फ़ाइल में। केवल एक चीज जो आपको करने की ज़रूरत है वह है अपने फ़ोल्डर में किसी भी नए संस्करण की प्रतिलिपि बनाना जहां DEVPATH परिवर्तनीय बिंदु।

यदि संभव हो तो अपने समाधान को कुछ छोटे समाधानों में विभाजित करें।


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


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


मुझे आश्चर्य है कि किसी ने हार्डलिंक का उपयोग करके उल्लेख नहीं किया है। फ़ाइलों की प्रतिलिपि बनाने के बजाय, यह मूल फ़ाइल में एक हार्डलिंक बनाता है। यह डिस्क स्पेस के साथ-साथ निर्माण को बहुत तेज बनाता है। यह निम्न गुणों के साथ कमांड लाइन पर सक्षम हो सकता है:

/ P: CreateHardLinksForAdditionalFilesIfPossible = true CreateHardLinksForCopyAdditionalFilesIfPossible = true CreateHardLinksForCopyFilesToOutputDirectoryIfPossible = true CreateHardLinksForCopyLocalIfPossible = true CreateHardLinksForPublishFilesIfPossible = true

आप इसे केंद्रीय आयात फ़ाइल में भी जोड़ सकते हैं ताकि आपकी सभी परियोजनाएं भी इस लाभ को प्राप्त कर सकें।


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

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

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

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


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


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

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

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

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

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

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







msbuild