<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><title>rod.pl</title><link>http://zine.net.pl/blogs/rod/default.aspx</link><description>projektowe perypetie Daniela Dąbrowskiego</description><dc:language /><generator>CommunityServer 2.1 SP2 (Build: 61129.2)</generator><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/rodpl" type="application/rss+xml" /><feedburner:feedFlare href="http://add.my.yahoo.com/rss?url=http%3A%2F%2Ffeeds.feedburner.com%2Frodpl" src="http://us.i1.yimg.com/us.yimg.com/i/us/my/addtomyyahoo4.gif">Subscribe with My Yahoo!</feedburner:feedFlare><feedburner:feedFlare href="http://www.newsgator.com/ngs/subscriber/subext.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Frodpl" src="http://www.newsgator.com/images/ngsub1.gif">Subscribe with NewsGator</feedburner:feedFlare><feedburner:feedFlare href="http://feeds.my.aol.com/add.jsp?url=http%3A%2F%2Ffeeds.feedburner.com%2Frodpl" src="http://o.aolcdn.com/favorites.my.aol.com/webmaster/ffclient/webroot/locale/en-US/images/myAOLButtonSmall.gif">Subscribe with My AOL</feedburner:feedFlare><feedburner:feedFlare href="http://www.bloglines.com/sub/http://feeds.feedburner.com/rodpl" src="http://www.bloglines.com/images/sub_modern11.gif">Subscribe with Bloglines</feedburner:feedFlare><feedburner:feedFlare href="http://www.netvibes.com/subscribe.php?url=http%3A%2F%2Ffeeds.feedburner.com%2Frodpl" src="http://www.netvibes.com/img/add2netvibes.gif">Subscribe with Netvibes</feedburner:feedFlare><feedburner:feedFlare href="http://fusion.google.com/add?feedurl=http%3A%2F%2Ffeeds.feedburner.com%2Frodpl" src="http://buttons.googlesyndication.com/fusion/add.gif">Subscribe with Google</feedburner:feedFlare><feedburner:feedFlare href="http://www.pageflakes.com/subscribe.aspx?url=http%3A%2F%2Ffeeds.feedburner.com%2Frodpl" src="http://www.pageflakes.com/ImageFile.ashx?instanceId=Static_4&amp;fileName=ATP_blu_91x17.gif">Subscribe with Pageflakes</feedburner:feedFlare><item><title>Bezpieczne mockowanie internal methods.</title><link>http://feedproxy.google.com/~r/rodpl/~3/jini_RqBNuk/bezpieczne-mockowanie-internal-methods.aspx</link><pubDate>Tue, 30 Jun 2009 10:42:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:3935</guid><dc:creator>rod</dc:creator><slash:comments>1</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/3935.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=3935</wfw:commentRss><description>&lt;p&gt;Trafił mi się dość skomplikowany proces biznesowy, który ma być uruchamiany metodą &lt;em&gt;void Process()&lt;/em&gt;. W celu uproszczenia, rozbiłem ciało tej metody na wiele pomniejszych metod.&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Process()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     List&amp;lt;TelesalesCompanyInfoApplication&amp;gt; applicationsFromDb = &lt;span class="kwrd"&gt;this&lt;/span&gt;.GetApplicationsFromDatabaseForProcessing();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (applicationsFromDb == &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; CriticalBusinessLogicException(&lt;span class="str"&gt;&amp;quot;Warstwa bazy danych, podczas podawania listy zgloszen nie powinna zwrócic null.&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;     &lt;span class="kwrd"&gt;this&lt;/span&gt;.SetLockStatus(applicationsFromDb);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;     &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (TelesalesCompanyInfoApplication application &lt;span class="kwrd"&gt;in&lt;/span&gt; applicationsFromDb)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.IsOriginalDateOlderThanApplicationDate(application))&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt; ...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Dzięki temu zabiegowi kod stał sie czytelniejszy oraz łatwiej będzie napisać testy jednostkowe. Chciałbym jednak uniknąć upubliczniania wszystkich metod w tej klasie. Do testów wystarczy że ustawimy je jako “internal” oraz zaufamy naszemu projektowi testującemu. Wystarczy w jakimkolwiek pliku dać wpis jak:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; [assembly:System.Runtime.CompilerServices.InternalsVisibleTo(&lt;span style="color:#006080;"&gt;&amp;quot;Services.UnitTests, PublicKey=A3DS...&amp;quot;&lt;/span&gt;)]&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Teraz bez problemu w naszej klasie testowej możemy testować “pomniejsze”, “internal” metody:&lt;/p&gt;

&lt;div style="border-bottom:gray 1px solid;border-left:gray 1px solid;padding-bottom:4px;line-height:12pt;background-color:#f4f4f4;margin:20px 0px 10px;padding-left:4px;width:97.5%;padding-right:4px;font-family:consolas, 'Courier New', courier, monospace;max-height:200px;font-size:8pt;overflow:auto;border-top:gray 1px solid;cursor:text;border-right:gray 1px solid;padding-top:4px;"&gt;
  &lt;div style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;
    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   1:&lt;/span&gt; [Test]&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   2:&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; IsOriginalDateOlderThanApplicationDate_ApplicationVerificationDateIsGreaterThanSurveyEndDate_ReturnTrue()&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   3:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   4:&lt;/span&gt;     TelesalesCompanyInfoApplication application = TelesalesCompanyInfoApplicationObjectMother.Make&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   5:&lt;/span&gt;         .Customize(&lt;span style="color:#0000ff;"&gt;delegate&lt;/span&gt;(TelesalesCompanyInfoApplication x) { x.VerifySourceDocumentDate = DateTime.Now.AddDays(-2); })&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   6:&lt;/span&gt;         .WithSurveyAs(CompanyInfoSurveyObjectMother.Make.WithDuration(DateTime.Now.AddDays(-10), DateTime.Now.AddDays(-8)));&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   8:&lt;/span&gt;     Assert.GreaterThan(application.VerifySourceDocumentDate, application.Survey.SurveyEnd);&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;   9:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  10:&lt;/span&gt;     DefaultTelesalesCompanyInfoApplicationImportProcessingService service = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; DefaultTelesalesCompanyInfoApplicationImportProcessingService();&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:white;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  11:&lt;/span&gt;     Assert.IsTrue(service.IsOriginalDateOlderThanApplicationDate(application));&lt;/pre&gt;

    &lt;pre style="border-bottom-style:none;padding-bottom:0px;line-height:12pt;border-right-style:none;background-color:#f4f4f4;margin:0em;padding-left:0px;width:100%;padding-right:0px;font-family:consolas, 'Courier New', courier, monospace;border-top-style:none;color:black;font-size:8pt;border-left-style:none;overflow:visible;padding-top:0px;"&gt;&lt;span style="color:#606060;"&gt;  12:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Natomiast do&amp;#160; przetestowania metody “Process” najlepiej wykorzystać “partial mocking” np. tak: &lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="rem"&gt;// Klasa pomocnicza do mockowania&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MockedTestCase&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;private&lt;/span&gt; MockRepository mockery;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;     &lt;span class="kwrd"&gt;protected&lt;/span&gt; MockRepository Mockery&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt;         get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockery; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetUp()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.mockery = &lt;span class="kwrd"&gt;new&lt;/span&gt; MockRepository();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  14:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  15:&lt;/span&gt; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  16:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  17:&lt;/span&gt; &lt;span class="rem"&gt;// Bazowa klasa do testowania logiki biznesowej&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  18:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; ServiceTestCase&amp;lt;TService&amp;gt; : MockedTestCase &lt;span class="kwrd"&gt;where&lt;/span&gt; TService : IBaseService&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  19:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  20:&lt;/span&gt;     &lt;span class="kwrd"&gt;protected&lt;/span&gt; Func&amp;lt;TService&amp;gt; sutCreator;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  21:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  22:&lt;/span&gt;     &lt;span class="kwrd"&gt;private&lt;/span&gt; TService sut;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  23:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  24:&lt;/span&gt;     &lt;span class="kwrd"&gt;protected&lt;/span&gt; TService Sut&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  25:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  26:&lt;/span&gt;         get { &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;this&lt;/span&gt;.sut; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  27:&lt;/span&gt;         set { &lt;span class="kwrd"&gt;this&lt;/span&gt;.sut = &lt;span class="kwrd"&gt;value&lt;/span&gt;; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  28:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  29:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  30:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; IUserSession GetStubbedUserSession()&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  31:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  32:&lt;/span&gt;         IUserSession session = &lt;span class="kwrd"&gt;new&lt;/span&gt; UserSessionStub();&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  33:&lt;/span&gt;         User sampleUser = &lt;span class="kwrd"&gt;new&lt;/span&gt; User();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  34:&lt;/span&gt;         sampleUser.LoginName = &lt;span class="str"&gt;&amp;quot;test&amp;quot;&lt;/span&gt;;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  35:&lt;/span&gt;         session.CurrentUser = sampleUser;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  36:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  37:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; session;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  38:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  39:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  40:&lt;/span&gt;     [SetUp]&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  41:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetUp()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  42:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  43:&lt;/span&gt;         &lt;span class="kwrd"&gt;base&lt;/span&gt;.SetUp();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  44:&lt;/span&gt;         &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;this&lt;/span&gt;.sutCreator != &lt;span class="kwrd"&gt;null&lt;/span&gt;)&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  45:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  46:&lt;/span&gt;             &lt;span class="kwrd"&gt;this&lt;/span&gt;.Sut = &lt;span class="kwrd"&gt;this&lt;/span&gt;.sutCreator();&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  47:&lt;/span&gt;         }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  48:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  49:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  50:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; UserSessionStub : BaseUserSession&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  51:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  52:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  53:&lt;/span&gt; }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  54:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  55:&lt;/span&gt; &lt;span class="rem"&gt;// Nasza klasa testujaca&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  56:&lt;/span&gt; [TestFixture]&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  57:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; DefaultTelesalesCompanyInfoApplicationImportProcessingServiceTests : ServiceTestCase&amp;lt;DefaultTelesalesCompanyInfoApplicationImportProcessingService&amp;gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  58:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  59:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultTelesalesCompanyInfoApplicationImportProcessingServiceTests()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  60:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  61:&lt;/span&gt;         &lt;span class="kwrd"&gt;this&lt;/span&gt;.sutCreator = &lt;span class="kwrd"&gt;delegate&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; Mockery.PartialMock&amp;lt;DefaultTelesalesCompanyInfoApplicationImportProcessingService&amp;gt;(); };&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  62:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  63:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  64:&lt;/span&gt;     [Test]&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  65:&lt;/span&gt;     &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Process_GetApplicationsFromDatabaseForProcessingReturnsNull_ThrowsCriticalBusinessLogicException()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  66:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  67:&lt;/span&gt;         &lt;span class="kwrd"&gt;using&lt;/span&gt; (Mockery.Record())&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  68:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  69:&lt;/span&gt;             Expect&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  70:&lt;/span&gt;                 .Call(&lt;span class="kwrd"&gt;this&lt;/span&gt;.Sut.GetApplicationsFromDatabaseForProcessing())&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  71:&lt;/span&gt;                 .Return(&lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  72:&lt;/span&gt;         }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  73:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  74:&lt;/span&gt;         &lt;span class="kwrd"&gt;using&lt;/span&gt; (Mockery.Playback())&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  75:&lt;/span&gt;         {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  76:&lt;/span&gt;             Assert.Throws&amp;lt;CriticalBusinessLogicException&amp;gt;(&lt;span class="kwrd"&gt;delegate&lt;/span&gt; { &lt;span class="kwrd"&gt;this&lt;/span&gt;.Sut.Process(); });&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  77:&lt;/span&gt;         }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  78:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  79:&lt;/span&gt; ...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Niestety nie da sie zrobić w taki sposób “partial mocking” dla metod oznaczonych jako “internal”. Musiały by one być “public virtual”, a tego chciałbym uniknąć. Jednym ze sposobów jest ustawienie aby główny projekt “Service” zaufał bibliotece DynamicProxy2 z projektu Castle, która jest niepodpisana. Nie wygląda to zachęcająco. Ale możemy to zrobić pośrednio: “Service” ufa “Service.UnitTests” a ten ufa “DynamicProxy2”. Zatem do “Service.UnitTests” dodajemy:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; [assembly: System.Runtime.CompilerServices.InternalsVisibleTo(&lt;span class="str"&gt;&amp;quot;DynamicProxyGenAssembly2&amp;quot;&lt;/span&gt;)]&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;oraz tworzymy pośrednia klasę która dziedziczy po naszej klasie testowanej. Należy pamiętać ze musi ona nadpisywać metody które uczestniczą w procesie partial mocking:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; TrustedDefaultTelesalesCompanyInfoApplicationImportProcessingService : DefaultTelesalesCompanyInfoApplicationImportProcessingService&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     &lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; List&amp;lt;TelesalesCompanyInfoApplication&amp;gt; GetApplicationsFromDatabaseForProcessing()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;         &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.GetApplicationsFromDatabaseForProcessing();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;oraz zmieniamy sposób tworzenia instancji testowanej klasy:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="rem"&gt;// z&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultTelesalesCompanyInfoApplicationImportProcessingServiceTests()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     &lt;span class="kwrd"&gt;this&lt;/span&gt;.sutCreator = &lt;span class="kwrd"&gt;delegate&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; Mockery.PartialMock&amp;lt;DefaultTelesalesCompanyInfoApplicationImportProcessingService&amp;gt;(); };&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt; }&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt; &lt;span class="rem"&gt;// na&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   9:&lt;/span&gt;&amp;#160; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  10:&lt;/span&gt; &lt;span class="kwrd"&gt;public&lt;/span&gt; DefaultTelesalesCompanyInfoApplicationImportProcessingServiceTests()&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  11:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;  12:&lt;/span&gt;     &lt;span class="kwrd"&gt;this&lt;/span&gt;.sutCreator = &lt;span class="kwrd"&gt;delegate&lt;/span&gt; { &lt;span class="kwrd"&gt;return&lt;/span&gt; Mockery.PartialMock&amp;lt;TrustedDefaultTelesalesCompanyInfoApplicationImportProcessingService&amp;gt;(); };&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;  13:&lt;/span&gt; }&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=3935" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/TDD/default.aspx">TDD</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/RhinoMocks/default.aspx">RhinoMocks</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2009/06/30/bezpieczne-mockowanie-internal-methods.aspx</feedburner:origLink></item><item><title>Jak uruchomić Mono 2.2 VMware na VirtualPC 2007</title><link>http://feedproxy.google.com/~r/rodpl/~3/a0JlL1ey9Eg/jak-uruchomi-mono-2-2-vmware-na-virtualpc-2007.aspx</link><pubDate>Sun, 08 Feb 2009 15:51:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:2855</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/2855.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=2855</wfw:commentRss><description>&lt;p&gt;Pisząc aplikację .NET czasem chciałbym sprawdzić jak ona chodzi w środowisku Mono pod Linuxem. W tym celu można skorzystać z obrazu wirtualnej maszyny pod VMWare dostępnej &lt;a href="http://www.go-mono.com/mono-downloads/download.html"&gt;stąd&lt;/a&gt;. Wszystko pięknie ale ja mam już zainstalowane oprogramowanie MS Virtual PC 2007 SP1 i szczerze powiedziawszy nie chciałbym instalować dodatkowego oprogramowania VMWare Playera. Wiązałoby się to z instalacją dodatkowych driverów na moim i tak obciążonym systemie na notebooku. Jak sobie zatem poradzić ?&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Na początek należy przekonwertować VMWare disk image na VHD. Do tego wykorzystałem &lt;a href="http://www.winimage.com/"&gt;WinImage&lt;/a&gt;. Co prawda wersja shareware ale wyrobiłem się z konwersją w czasie krótszym niż 30 dni :). &lt;/li&gt;    &lt;li&gt;Teraz wystarczy stworzyć nowa maszynę wirtualna z systemem “Other” oraz podpiąć przekonwertowany dysk. &lt;/li&gt;    &lt;li&gt;W trakcie uruchomienia należy skorzystać z wpisu inicjującego &lt;strong&gt;noreplace-paravirt&lt;/strong&gt;.       &lt;br /&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/2854/original.aspx" /&gt; &lt;/li&gt;    &lt;li&gt;Teraz wystarczy dodać tę opcje na stałe do boot-a czyli,      &lt;ul&gt;       &lt;li&gt;Computer –&amp;gt; YaST &lt;/li&gt;        &lt;li&gt;hasło &lt;em&gt;“mono”&lt;/em&gt; &lt;/li&gt;        &lt;li&gt;System –&amp;gt; Boot Loader &lt;/li&gt;        &lt;li&gt;Edit i w polu “Optional Kernel Command Line Parameter” dopisać: noreplace-paravirt &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Instancje wirtualnych maszyn mogą być mało wydajne na notebookach z nowa generacja procesorów. Chodzi tutaj o dynamiczne obniżanie częstotliwości taktowania procesora. Aby temu zaradzić można wyłączyć poprzez np. wybranie w Viscie trybu High Performance lub ręczne ustawienie “Minimum processor state” na 100% w “Power procesor management”. Alternatywnym rozwiązaniem jest dodanie wpisu do pliku options.xml … jest to opisane tutaj&amp;#160; -&amp;gt; &lt;a href="http://blogs.msdn.com/virtual_pc_guy/archive/2007/03/27/last-resort-for-performance-issues-with-virtual-pc-on-laptops.aspx"&gt;Last resort for performance issues with Virtual PC on laptops&lt;/a&gt;.&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=2855" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Mono/default.aspx">Mono</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/Virtual+PC/default.aspx">Virtual PC</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2009/02/08/jak-uruchomi-mono-2-2-vmware-na-virtualpc-2007.aspx</feedburner:origLink></item><item><title>Intelisense dla jQuery korzystając z MonoRail</title><link>http://feedproxy.google.com/~r/rodpl/~3/wvzhMEnIaWI/intelisense-dla-jquery-korzystaj-c-z-monorail.aspx</link><pubDate>Tue, 27 Jan 2009 16:48:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:2799</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/2799.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=2799</wfw:commentRss><description>&lt;p&gt;Od jakiegoś czasu Microsoft udostępnił fix do Visual Studio 2008, dzięki któremu nie tylko mamy możliwość intelisense dla jQuery ale równiez dla jakichkolwiek bibliotek javascript. Po jego zainstalowaniu wystarczy dodać link do skryptu tak aby Visual Studio mógł go znaleźć. Co jednak zrobić w przypadku kiedy link do skryptu jest generowany w locie lub w danym momencie edytujemy “partial view”, czyli wycinek HTML-a ? Dodatkowo korzystamy z MonoRail-a ?&lt;/p&gt;  &lt;p&gt;Wystarczy zrobić prosty trick:&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; src=&lt;span class="str"&gt;&amp;quot;${siteRoot}/content/scripts/jquery.js&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; &amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; src=&lt;span class="str"&gt;&amp;quot;${siteRoot}/content/scripts/jquery.validate.js&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt; &amp;lt;% &lt;span class="kwrd"&gt;if&lt;/span&gt; (&lt;span class="kwrd"&gt;false&lt;/span&gt;): %&amp;gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt; &amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; src=&lt;span class="str"&gt;&amp;quot;../../content/scripts/jquery.js&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt; &amp;lt;script type=&lt;span class="str"&gt;&amp;quot;text/javascript&amp;quot;&lt;/span&gt; src=&lt;span class="str"&gt;&amp;quot;../../content/scripts/jquery.validate.js&amp;quot;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt; &amp;lt;% &lt;span class="kwrd"&gt;end&lt;/span&gt; %&amp;gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=2799" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MonoRail/default.aspx">MonoRail</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/jQuery/default.aspx">jQuery</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2009/01/27/intelisense-dla-jquery-korzystaj-c-z-monorail.aspx</feedburner:origLink></item><item><title>Ignorowanie testu w MbUnit 3.0.5</title><link>http://feedproxy.google.com/~r/rodpl/~3/4_fr2muVda4/ignorowanie-testu-w-mbunit-3-0-5.aspx</link><pubDate>Tue, 13 Jan 2009 19:01:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:2742</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/2742.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=2742</wfw:commentRss><description>&lt;p&gt;Aby zignorować test wystarczy dodać atrybut &lt;em&gt;[Ignore]&lt;/em&gt; do deklaracji metody. Co natomiast natomiast zrobić jeżeli decyzje o ignorowaniu wykonania testu chcielibyśmy podjąć dopiero w trakcie jego wykonania ? Zarówno w NUnit jak i MbUnit 2.0 istnieje metoda &lt;em&gt;Assert.Ignore()&lt;/em&gt;, która powoduje że test jest ignorowany w momencie jej wywołania. &lt;/p&gt;  &lt;p&gt;Niestety MbUnit od wersji 3.0 tej metody już nie ma. Obejściem tego problemu jest rzucenie odpowiedniego Exception. Oto przykład pomocniczej metody testowej, której zadaniem jest sprawdzanie poprawności mapowania długości pola w NHibernate. SQLite nie posiada w ogóle czegoś takiego jak określenie długości pola zatem dla tego typu bazy danych ten test nie miałby sensu. A oto i kod:&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   1:&lt;/span&gt; &lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; AssertPropertyLength(&lt;span class="kwrd"&gt;string&lt;/span&gt; propertyName, &lt;span class="kwrd"&gt;int&lt;/span&gt; length)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   2:&lt;/span&gt; {&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   3:&lt;/span&gt;     var driver = ((SessionFactoryImpl)&lt;span class="kwrd"&gt;this&lt;/span&gt;.Session.SessionFactory).ConnectionProvider.Driver;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   4:&lt;/span&gt;     &lt;span class="kwrd"&gt;if&lt;/span&gt; (driver.GetType().Equals(&lt;span class="kwrd"&gt;typeof&lt;/span&gt;(SQLite20Driver)))&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   5:&lt;/span&gt;     {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   6:&lt;/span&gt;         &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; SilentTestException(TestOutcome.Ignored, &lt;span class="str"&gt;&amp;quot;Test skipped for SQLite&amp;quot;&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="lnum"&gt;   7:&lt;/span&gt;     }&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="lnum"&gt;   8:&lt;/span&gt; ...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=2742" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/TDD/default.aspx">TDD</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MbUnit/default.aspx">MbUnit</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/NHibernate/default.aspx">NHibernate</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2009/01/13/ignorowanie-testu-w-mbunit-3-0-5.aspx</feedburner:origLink></item><item><title>Tak blisko, a za daleko</title><link>http://feedproxy.google.com/~r/rodpl/~3/17-NmZc3T4s/tak-blisko-a-za-daleko.aspx</link><pubDate>Fri, 12 Dec 2008 00:07:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:2608</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/2608.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=2608</wfw:commentRss><description>&lt;P&gt;W trakcie pracy nad kodem staram się jak najbardziej ograniczać moje wędrówki między kawiaturą a myszką. W tym celu oprócz &lt;A href="http://www.jetbrains.com/resharper/" target=_blank&gt;ReSharper&lt;/A&gt;-a korzystam z &lt;A href="http://www.viemu.com/" target=_blank&gt;ViEmu&lt;/A&gt;. Jak sama nazwa wskazuje jest to emulacja edytora Vi pod Visual Studio. Teraz mój gryzoń często leniuchuje przy klawiaturze grzejąc się w blasku monitora :). Mimo tego wciąż moje palce pokonują spore odległości. Sięgając po klawisz Esc oraz &lt;EM&gt;strzałki&lt;/EM&gt;.&lt;/P&gt;
&lt;P&gt;&lt;EM&gt;Esc&lt;/EM&gt; w Vi jest używany do wychodzenia z trybu “Insert”, czyli praktycznie non-stop. Alternatywnym rozwiazaniem jest zastosowanie &lt;EM&gt;Ctrl+[&lt;/EM&gt;. Jednak ReSharper też korzysta z tego skrótu. Jak dla mnie najlepszym rozwiązaniem byłoby skorzystanie z klawisza &lt;EM&gt;CapsLock&lt;/EM&gt; zamiast &lt;EM&gt;Esc.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;Mimo stosowania klawiszy &lt;EM&gt;H, J, K, L&lt;/EM&gt; do poruszania sie po kodzie, czasem zachodzi potrzeba korzystania ze strzałek. Ma to miejsce kiedy wyświetla się nam okienko z Intelisense. Tutaj można by zastosować &lt;EM&gt;Alt+N&lt;/EM&gt; do poruszania się w doł a &lt;EM&gt;Alt+P&lt;/EM&gt; w górę po opcjach intelisense. Tylko jak to zrobić ?&lt;/P&gt;
&lt;P&gt;Z pomocą przychodzi nam &lt;A href="http://www.autohotkey.com/" target=_blank&gt;AutoHotkey&lt;/A&gt;. Jest to rezydentny program, który potrafi klawiszom przypisywać różne makra. Makra te sa definiowane w postaci skryptu. W moim wypadku wygląda on tak&lt;/P&gt;
&lt;DIV class=csharpcode-wrapper id=codeSnippetWrapper&gt;
&lt;DIV class=csharpcode id=codeSnippet&gt;&lt;PRE class=alt&gt;#IfWinActive, ,Visual Studio&lt;BR&gt;    Capslock::Esc&lt;BR&gt;    Alt &amp;amp; p::Send {Up}&lt;BR&gt;    Alt &amp;amp; n::Send {Down}&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;
&lt;P&gt;Co ciekawe program ten potrafi konwertować swoje pliki skryptowe do plików exe. Zatem można na obcym komputerze odpalić tak skompilowany skrypt bez instalacji czegokolwiek, aby dalej cieszyć się naszą kombinacją klawiszy.&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Update:&lt;/STRONG&gt;&lt;/P&gt;
&lt;P&gt;Oto mała poprawka do popupów reshapera. Np. w momencie wyszukiwania jakiegos typu. Docelowy skrytpt powinien wygladać tak.&lt;/P&gt;
&lt;DIV class=csharpcode-wrapper id=codeSnippetWrapper&gt;
&lt;DIV class=csharpcode id=codeSnippet&gt;&lt;PRE class=alt&gt;if WinActive("ahk_class Visual Studio") or WinActive("ahk_class JetPopupMenuView")
{
	Capslock::Esc
	Alt &amp;amp; p:: Send {Up}
	Alt &amp;amp; n:: Send {Down}
}&lt;/PRE&gt;&lt;/DIV&gt;&lt;/DIV&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=2608" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/ReSharper/default.aspx">ReSharper</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/ViEmu/default.aspx">ViEmu</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/12/12/tak-blisko-a-za-daleko.aspx</feedburner:origLink></item><item><title>Remote backup dla SVN na GoogleCode</title><link>http://feedproxy.google.com/~r/rodpl/~3/M3ucXVc4xRM/remote-backup-dla-svn-na-googlecode.aspx</link><pubDate>Fri, 22 Aug 2008 00:37:54 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1780</guid><dc:creator>rod</dc:creator><slash:comments>2</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1780.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1780</wfw:commentRss><description>&lt;p&gt;Backupy dla SVN można wykonać za pomocą komendy &amp;quot;svnadmin dump&amp;quot;. Możliwe jest to jedynie wyłącznie kiedy mamy fizyczny dostęp do repozytorium. Co zrobić kiedy nasz projekt jest hostowany ? &lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Należy zrobić lokalny mirror. W tym celu napisałem mały skrypt WSH, kt&amp;#243;ry automatyzuje poszczeg&amp;#243;lne kroki. Można go pobrać stąd -&amp;gt; &lt;a href="http://www.42n.pl/files/svnmirror.zip"&gt;svnmirror.zip&lt;/a&gt; oraz uruchomić podając gdzie ma się znajdować lokalne repozytorium a gdzie zdalne. Przykład &lt;/li&gt; &lt;/ul&gt;  &lt;div class="console-wrapper"&gt;   &lt;div class="console"&gt;     &lt;pre class="alt"&gt;C:\SVN&amp;gt;svnmirror C:\SVN\RubyView.Mirror https://dabrowski.daniel@rubyview.googlecode.com/svn&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;Teraz już wystarczy wykonać dump naszego mirror-a czyli: &lt;/li&gt;
&lt;/ul&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;C:\SVN&amp;gt;svnadmin dump C:\SVN\RubyView.Mirror &amp;gt; RubyView.Mirror.20080821&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1780" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Subversion/default.aspx">Subversion</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/08/22/remote-backup-dla-svn-na-googlecode.aspx</feedburner:origLink></item><item><title>Dynamiczne referencje do bibliotek w Visual Studio</title><link>http://feedproxy.google.com/~r/rodpl/~3/tyZx-9MAgrE/dynamiczne-referencje-do-bibliotek-w-visual-studio.aspx</link><pubDate>Wed, 13 Aug 2008 21:37:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1718</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1718.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1718</wfw:commentRss><description>&lt;p&gt;Często, w trakcie korzystania z zewnętrznych bibliotek w naszym&amp;nbsp; projekcie, pojawia się pewien dylemat. Czy dołączone biblioteki, powinny być skompilowane jako "debug" czy jako "release" ?&amp;nbsp; Zamiast podejmować trudną decyzję zróbmy sobie proste rozwiązanie.&lt;/p&gt;  &lt;p&gt;W &lt;a href="http://zine.net.pl/blogs/rod/archive/2008/07/13/organizacja-projektu-i-automatyzacja-z-wykorzystaniem-msbuild-a-1-struktura.aspx"&gt;Automatyzacja projektu z MSBuild-em - 1. Struktura&lt;/a&gt; proponowałem przechowywanie "third-party libraries" w katalogu "lib". Teraz dodatkowo zróbmy tam podział na "debug" i "release". Przykład z bibliotekami z IronRuby, które wykorzystuje w aktualnym projekcie:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;lib&lt;/li&gt;    &lt;ul&gt;     &lt;li&gt;net&lt;/li&gt;      &lt;ul&gt;       &lt;li&gt;2.0&lt;/li&gt;        &lt;ul&gt;         &lt;li&gt;IronRuby&lt;/li&gt;          &lt;ul&gt;           &lt;li&gt;debug&lt;/li&gt;            &lt;li&gt;release&lt;/li&gt;         &lt;/ul&gt;       &lt;/ul&gt;     &lt;/ul&gt;   &lt;/ul&gt; &lt;/ul&gt;  &lt;p&gt;Struktura jest na tyle oczywista że chyba nie trzeba opisywać.&lt;/p&gt;  &lt;p&gt;Teraz w naszym pliku projektu ".csproj" wystarczy tak zmodyfikować referencje do bibiliotek:&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="IronRuby"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;..\..\..\lib\net\2.0\IronRuby\$(Configuration)\IronRuby.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="IronRuby.Libraries"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;..\..\..\lib\net\2.0\IronRuby\$(Configuration)\IronRuby.Libraries.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="Microsoft.Scripting"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;..\..\..\lib\net\2.0\IronRuby\$(Configuration)\Microsoft.Scripting.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="Microsoft.Scripting.Core"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;..\..\..\lib\net\2.0\IronRuby\$(Configuration)\Microsoft.Scripting.Core.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;  &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="System"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Data"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="System.Xml"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Jezeli nasz projekt jest kompilowany w trybie "Debug", wówczas kompilacja odbędzie się z wykorzystaniem innych bibliotek z podkatalogu "debug". Analogicznie z "Release".&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1718" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/08/13/dynamiczne-referencje-do-bibliotek-w-visual-studio.aspx</feedburner:origLink></item><item><title>Testowanie kompatybilnosci przegladarek dla Helpers w MonoRail</title><link>http://feedproxy.google.com/~r/rodpl/~3/u5v-ap4on7o/testowanie-kompatybilnosci-przegladarek-dla-helpers-w-monorail.aspx</link><pubDate>Thu, 31 Jul 2008 13:52:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1664</guid><dc:creator>rod</dc:creator><slash:comments>2</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1664.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1664</wfw:commentRss><description>&lt;p&gt;Helpers w MonoRail są często wykorzystywane do generowania kodu Html. Bywają sytuacje kiedy tworzony Html powinien wyglądać inaczej dla różnych przeglądarek. Czasem do wykrycia rodzaju oraz wersji przeglądarki stosuje się System.Web.HttpRequest.Browser, który zwraca klasę System.Web.HttpBrowserCapabilities. Niestety to rozwiązanie ma trzy zasadnicze wady:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;Trudno jest mockować klasę HttpBrowserCapabilities &lt;/li&gt;    &lt;li&gt;Rozwiązanie to opiera się na pliku browscap.ini. W momencie uruchamiania aplikacji&amp;nbsp; z serwera firmy hostingowej, nie mamy żadnej kontroli nad aktualizacja pliku browscap.ini. &lt;/li&gt;    &lt;li&gt;System.Web.HttpRequest różni się od&amp;nbsp; Castle.MonoRail.Framework.IRequest przede wszystkim tym, że IRequest nie ma property Browser :) i nie korzysta z HttpBrowserCapabilities :). Całe szczęście. &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Pozostaje nam stare dobre rozwiązanie a mianowicie własnoręczne rozpoznawanie "HTTP_USER_AGENT" w naszym Helperze. &lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;virtual&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsCompatibleBrowser()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;string&lt;/span&gt; agent = Context.Request.Params[&lt;span class="str"&gt;"HTTP_USER_AGENT"&lt;/span&gt;];&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;// IE&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;if&lt;/span&gt; (agent.IndexOf(&lt;span class="str"&gt;"MSIE"&lt;/span&gt;) &amp;gt;= 0 &amp;amp;&amp;amp; agent.IndexOf(&lt;span class="str"&gt;"Windows"&lt;/span&gt;) &amp;gt;= 0 &amp;amp;&amp;amp; agent.IndexOf(&lt;span class="str"&gt;"Opera"&lt;/span&gt;) &amp;lt; 0)&lt;/pre&gt;

    &lt;pre class="alt"&gt;    {&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        var match = Regex.Match(agent, &lt;span class="str"&gt;@"(?&amp;lt;=MSIE )[\d\.]+"&lt;/span&gt;);&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;return&lt;/span&gt; (match.Success &amp;amp;&amp;amp; &lt;span class="kwrd"&gt;float&lt;/span&gt;.Parse(match.Value, CultureInfo.InvariantCulture) &amp;gt;= 5.5);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    }&lt;/pre&gt;

    &lt;pre class="alt"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Lecz w jaki sposób to testować ? Najprostszym sposobem jest wykorzystanie istniejących we frameworku MonoRail klas typu stub.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;using&lt;/span&gt; Castle.MonoRail.Framework.Test;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;// SUT = System Under Test czyli mój helper&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; MyHelper _sut;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[SetUp]&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; SetUp()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;    _sut = &lt;span class="kwrd"&gt;new&lt;/span&gt; MyHelper();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    _sut.SetController(&lt;span class="kwrd"&gt;new&lt;/span&gt; HomeController(), &lt;span class="kwrd"&gt;new&lt;/span&gt; ControllerContext());&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    _sut.SetContext(&lt;span class="kwrd"&gt;new&lt;/span&gt; StubEngineContext(&lt;span class="kwrd"&gt;new&lt;/span&gt; StubRequest(), &lt;span class="kwrd"&gt;new&lt;/span&gt; StubResponse(), &lt;span class="kwrd"&gt;new&lt;/span&gt; UrlInfo(&lt;span class="str"&gt;"area"&lt;/span&gt;, &lt;span class="str"&gt;"home"&lt;/span&gt;, &lt;span class="str"&gt;"index"&lt;/span&gt;, &lt;span class="str"&gt;"/app"&lt;/span&gt;, &lt;span class="str"&gt;"sdm"&lt;/span&gt;)));&lt;/pre&gt;

    &lt;pre class="alt"&gt;    _sut.ServerUtility = &lt;span class="kwrd"&gt;new&lt;/span&gt; StubServerUtility();&lt;/pre&gt;

    &lt;pre class="alteven"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Przydadzą nam się linki do dwóch stron, które zawierają zbiór wszelakiej maści &lt;span class="str"&gt;"HTTP_USER_AGENT"&lt;/span&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href="http://www.useragentstring.com/pages/useragentstring.php"&gt;UserAgentStrings&lt;/a&gt; &lt;/li&gt;

  &lt;li&gt;&lt;a href="http://www.zytrax.com/tech/web/browser_ids.htm"&gt;Browser ID Strings&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dzięki nim łatwo możemy stworzyć następujące testy&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;// IE 5.5+ on Windows&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; WOW64; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; Media Center PC 5.0; .NET CLR 1.1.4322)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 1.1.4322; InfoPath.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; Dealio Deskball 3.0)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; NeosBrowser; .NET CLR 1.1.4322; .NET CLR 2.0.50727)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;// FireFox 1.5+&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (X11; U; Linux x86_64; sv-SE; rv:1.8.1.12) Gecko/20080207 Ubuntu/7.10 (gutsy) Firefox/2.0.0.12"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.4) Gecko/20060614 Fedora/1.5.0.4-1.2.fc5 Firefox/1.5.0.4 pango-text"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (X11; U; Darwin Power Macintosh; en-US; rv:1.8.0.12) Gecko/20070803 Firefox/1.5.0.12 Fink Community Edition"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.8) Gecko/20051201 Firefox/1.5"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsCompatibleBrowser_ThisBrowserShouldBeCompatible(&lt;span class="kwrd"&gt;string&lt;/span&gt; agent)&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    _sut.Context.Request.Params[&lt;span class="str"&gt;"HTTP_USER_AGENT"&lt;/span&gt;] = agent;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    Assert.That(_sut.IsCompatibleBrowser());&lt;/pre&gt;

    &lt;pre class="alteven"&gt;}&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;// IE &amp;lt; 5.5 on Windows&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 4.01; Windows NT 5.0)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT; .NET CLR 1.0.3705)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;// IE on Mac&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 5.23; Mac_PowerPC)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/4.0 (compatible; MSIE 5.5b1; Mac_PowerPC)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (MSIE 7.0; Macintosh; U; SunOS; X11; gu; SV1; InfoPath.2; .NET CLR 3.0.04506.30; .NET CLR 3.0.04506.648)"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;// FireFox &amp;lt; 1.5&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8b4) Gecko/20050908 Firefox/1.4"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.13) Gecko/20060410 Firefox/1.0.8"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alt"&gt;[TestCase(&lt;span class="str"&gt;@"Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.2b) Gecko/20020923 Phoenix/0.1"&lt;/span&gt;)]&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; IsCompatibleBrowser_ThisBrowserShouldNOTBeCompatible(&lt;span class="kwrd"&gt;string&lt;/span&gt; agent)&lt;/pre&gt;

    &lt;pre class="alt"&gt;{&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    _sut.Context.Request.Params[&lt;span class="str"&gt;"HTTP_USER_AGENT"&lt;/span&gt;] = agent;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    Assert.That(!_sut.IsCompatibleBrowser());&lt;/pre&gt;

    &lt;pre class="alteven"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Nadmienię tylko, że korzystam z wersji NUnit 2.5 Alpha-3 Release, stąd atrybut "TestCase", który jest odpowiednikiem np. "RowTest" w MbUnit.&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1664" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/TDD/default.aspx">TDD</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MonoRail/default.aspx">MonoRail</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/31/testowanie-kompatybilnosci-przegladarek-dla-helpers-w-monorail.aspx</feedburner:origLink></item><item><title>Automatyzacja projektu z MSBuild-em - 7. Inputs i Outputs, czyli fast &amp; furious</title><link>http://feedproxy.google.com/~r/rodpl/~3/Ya8HnOYwthY/automatyzacja-projektu-z-msbuild-em-7-inputs-i-outputs-czyli-fast-furious.aspx</link><pubDate>Wed, 30 Jul 2008 13:08:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1655</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1655.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1655</wfw:commentRss><description>&lt;p&gt;Podczas kompilacji często możemy dostrzec następujący komunikat.&lt;/p&gt;  &lt;div class="console-wrapper"&gt;   &lt;div class="console"&gt;     &lt;pre class="alt"&gt;CoreCompile:&lt;/pre&gt;

    &lt;pre class="alteven"&gt;Skipping target &amp;quot;CoreCompile&amp;quot; because all output files are up-to-date with respect to the input files.&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Jest to efekt funkcjonalnosci budowy przyrostowej - &amp;quot;incremental build&amp;quot;. Dzieki niej nasze skrypty mogą być o wiele wydajniejsze. Każdy target może mieć parametry Inputs i Outputs. Przed wykonaniem targetu MSBuild sprawdza timestamp plik&amp;#243;w w Inputs plikami w Outputs.&amp;#160; I jeżeli Inputs &amp;gt; Outputs, w&amp;#243;wczas przystępuje do wykonania zadania a jeżeli Inputs =&amp;lt; Outputs w&amp;#243;wczas &amp;quot;pomija&amp;quot; zadanie z uwzględnieniem &amp;quot;output inferral&amp;quot; ... o tym p&amp;#243;zniej.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="attr"&gt;Inputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(CSFile)&amp;quot;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="attr"&gt;Outputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;hello.exe&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Csc&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;Sources&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(CSFile)&amp;quot;&lt;/span&gt; &lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;OutputAssembly&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;hello.exe&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Powyższy przykład pokazuje, że kompilacja zostanie wykonana w momencie, kiedy data kt&amp;#243;regoś z plik&amp;#243;w &amp;quot;@(CSFile)&amp;quot; będzie większa niż docelowy plik, czyli &amp;quot;hello.exe&amp;quot;. &lt;/p&gt;

&lt;p&gt;Spr&amp;#243;bujmy zmienić nasz testowy target SayHi tak, aby się wykonywał przyrostowo por&amp;#243;wnująć pliki do skompilowania z plikami juz skompilowanymi.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SayHi&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Inputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(Compile)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Outputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(OutputPath)\$(TargetName).dll&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Project $(ProjectName) says 'HI' to everyone.&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Importance&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;High&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Beep&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Nie jest to do końca idealne rozwiązanie. Czasem np. zmiana zawartosci pliku Resource powinna r&amp;#243;wnież wymusić przyrostowe wykonanie. W powyższym przykładzie to się nie stanie gdyż sprawdzamy wyłącznie &amp;quot;@(Compile)&amp;quot;. Co zatem powinniśmy brać pod uwagę ? Wystarczy przyjżeć się taskowi &amp;quot;CoreCompile&amp;quot; z &amp;quot;Microsoft.CSharp.Targets&amp;quot;.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;CoreCompile&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="attr"&gt;Inputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildAllProjects);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;            @(Compile);                               &lt;/pre&gt;

    &lt;pre class="alt"&gt;            @(_CoreCompileResourceInputs);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;            $(ApplicationIcon);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            $(AssemblyOriginatorKeyFile);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;            @(ReferencePath);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            @(CompiledLicenseFile);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;            @(EmbeddedDocumentation); &lt;/pre&gt;

    &lt;pre class="alt"&gt;            $(Win32Resource);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;            $(Win32Manifest);&lt;/pre&gt;

    &lt;pre class="alt"&gt;            @(CustomAdditionalCompileInputs)&amp;quot;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="attr"&gt;Outputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(DocFileItem);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;             @(IntermediateAssembly);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;             @(_DebugSymbolsIntermediatePath);                 &lt;/pre&gt;

    &lt;pre class="alt"&gt;             $(NonExistentFile);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;             @(CustomAdditionalCompileOutputs)&amp;quot;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(CoreCompileDependsOn)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Zatem moglibyśmy skopiować parametry &amp;quot;Inputs&amp;quot; i &amp;quot;Outputs&amp;quot; z &amp;quot;CoreCompile&amp;quot; do &amp;quot;SayHi&amp;quot;. Jednak to nie wystarczy. W momencie gdy będziemy chcieli uruchomić &amp;quot;SayHi&amp;quot; po wykonaniu &amp;quot;CoreCompile&amp;quot;, w&amp;#243;wczas nasz target nigdy nie zostanie wykonany gdyż &amp;quot;Outputs&amp;quot; będa już &amp;quot;up-to-date&amp;quot;. Zr&amp;#243;bmy sobie zatem naszą własną zmienną - &amp;quot;IsCompileUpToDate&amp;quot;.&lt;/p&gt;

&lt;h3&gt;Output inferral&lt;/h3&gt;

&lt;p&gt;Mało kto o tym wie, ale istnieje pewna ukryta cecha w &amp;quot;incremental build&amp;quot;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Uwaga:&lt;/strong&gt; Bez względu na &amp;quot;Inputs&amp;quot; i &amp;quot;Outputs&amp;quot;, MSBuild zawsze skanuje target i zawsze wykonuje elementy odpowiedzialene za tworzenie lub zmianę Property i Item.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Cecha ta nazywa się &amp;quot;output inferral&amp;quot; i ma ona niwelować negatywny wplyw modyfikowanych zmiennych w zadaniach pominiętych, na realizację zadań jeszcze nie wykonanych. Zobaczymy to na przykładzie tworzenia naszej pomocniczej zmiennej.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SetIsCompileUpToDate&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;_InitializeIsCompileUpToDate;_CheckIsCompileUpToDate&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;_CheckIsCompileUpToDate&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;Inputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildAllProjects);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                @(Compile);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                @(_CoreCompileResourceInputs);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                $(ApplicationIcon);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                $(AssemblyOriginatorKeyFile);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                @(ReferencePath);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                @(CompiledLicenseFile);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                @(EmbeddedDocumentation);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                $(Win32Resource);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                $(Win32Manifest);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                @(CustomAdditionalCompileInputs)&amp;quot;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;Outputs&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(DocFileItem);&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                @(IntermediateAssembly);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                @(_DebugSymbolsIntermediatePath);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                $(NonExistentFile);&lt;/pre&gt;

    &lt;pre class="alt"&gt;                @(CustomAdditionalCompileOutputs)&amp;quot;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IsCompileUpToDate&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ValueSetByTask&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;_CheckIsCompileUpToDate $(IsCompileUpToDate)&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;_InitializeIsCompileUpToDate&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IsCompileUpToDate&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;ValueSetByTask&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;_InitializeIsCompileUpToDate $(IsCompileUpToDate)&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Początkowo inicjalizujemy naszą zmienną wartością &amp;quot;true&amp;quot;, a następnie w zależności od Inputs i Outputs zmieniamy jej wartość na &amp;quot;false&amp;quot;. Zgodnie z &amp;quot;output inferral&amp;quot;, pomimo iż target &amp;quot;_CheckIsCompileUpToDate&amp;quot; byłby teoretycznie pomijany to zmiennej IsCompileUpToDate i tak nadana by była wartość &amp;quot;false&amp;quot;. Od wersji MSBuild 3.5 mamy nowy typ &amp;quot;TaskParameter&amp;quot; a mianowicie &amp;quot;ValueSetByTask&amp;quot;, kt&amp;#243;ry zastosowałem powyżej. Dzieki niemu omijamy &amp;quot;output inferral&amp;quot; i wszsytko działa tak jak zamierzaliśmy.&lt;/p&gt;

&lt;p&gt;Teraz pytanie, w kt&amp;#243;rym momencie powinniśmy uruchomić &amp;quot;SetIsCompileUpToDate&amp;quot; ? Jak zauważylismy w jednym z poprzednich odcink&amp;#243;w, dodanie targetu do &amp;quot;CoreCompileDependsOn&amp;quot; nie jest najlepszym rozwiązaniem gdyż np. dodawanie referencji do projektu spod Visual Studio uruchamia target &amp;quot;CoreCompile&amp;quot;. Z drugiej strony musimy być pewni że nasze zmienne w Inputs i Outpus są wypełnione przez proces budowy. Na przykład&amp;#160; &amp;quot;_CoreCompileResourceInputs&amp;quot; dopiero powstaje w &amp;quot;_GenerateCompileInputs&amp;quot; w Microsoft.Common.targets. Przyjżyjmy się jak wygląda wog&amp;#243;le target &amp;quot;Compile&amp;quot;.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CompileDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;      ResolveReferences;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;      ResolveKeySource;&lt;/pre&gt;

    &lt;pre class="alt"&gt;      SetWin32ManifestProperties;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;      _GenerateCompileInputs;&lt;/pre&gt;

    &lt;pre class="alt"&gt;      BeforeCompile;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;      _TimeStampBeforeCompile;&lt;/pre&gt;

    &lt;pre class="alt"&gt;      CoreCompile;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;      _TimeStampAfterCompile;&lt;/pre&gt;

    &lt;pre class="alt"&gt;      AfterCompile&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CompileDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Compile&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(CompileDependsOn)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Teraz już widzimy ... najlepiej w &amp;quot;BeforeCompile&amp;quot;. Ten target możemy poprostu nadpisać w naszym Commons.Targets&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BeforeCompile&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SetIsCompileUpToDate&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Zatem zr&amp;#243;bmy już docelowy refaktoring zar&amp;#243;wno dla &amp;quot;SayHi&amp;quot; jak i &amp;quot;IncludeGeneratedAssemblyInfo&amp;quot;.&lt;/p&gt;

&lt;p&gt;Pamiętacie nasz trick z &amp;quot;Touch&amp;quot; przy generowaniu AssemblyInfo.cs ? Teraz możemy go pominąć, ale aby zachować kompatybilność, być może ktoś nie bedzie chciał korzystać z metody &amp;quot;SetIsCompileUpToDate&amp;quot;, zmodyfikujmy go tak ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Touch&lt;/span&gt; &lt;span class="attr"&gt;Files&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyInfoFile)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Time&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;2000-01-01&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(IsCompileUpToDate) == ''&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... natomiast Commons.Target będzie wyglądał tak ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Add additional depends to Build target --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        $(BuildDependsOn);&lt;/pre&gt;

    &lt;pre class="alt"&gt;        SayHi;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BuildDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;BeforeCompile&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SetIsCompileUpToDate&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CallTarget&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IncludeGeneratedAssemblyInfo&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(IsCompileUpToDate) == 'false'&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SayHi&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(IsCompileUpToDate) == 'false'&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Project $(ProjectName) says 'HI' to everyone. &amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Importance&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;High&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Beep&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Kod do dzisiejszego odcinka dostępny tutaj -&amp;gt; &lt;a href="http://rodsamples.googlecode.com/svn/MSBuildTutorial/tags/part007/"&gt;part007&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Na konieć nadmienię że istnieje bardzo ciekawe narzędzie, kt&amp;#243;re nazywa sie &lt;a href="http://www.codeplex.com/msbuildprofiler"&gt;MSBuild Profiller&lt;/a&gt;. Spos&amp;#243;b działania jest bardzo prosty. Opiera się on na własnym Loggerze do MSBuild i po zainstalowaniu uruchamia się go w następujący spos&amp;#243;b&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;MSBuild.exe mybuildfile.proj /t:mytarget /l:MSBuildProfileLogger,MSBuildProfiler,Version=1.0.1.0,Culture=neutral,PublicKeyToken=09544254e89d148c&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;.. i mamy w&amp;#243;wczas taki efekt&lt;/p&gt;
&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1656/original.aspx" /&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1655" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/30/automatyzacja-projektu-z-msbuild-em-7-inputs-i-outputs-czyli-fast-furious.aspx</feedburner:origLink></item><item><title>Automatyzacja projektu z MSBuild-em - 6. Numer wersji z SVN revision</title><link>http://feedproxy.google.com/~r/rodpl/~3/3ZREdRMfC7M/automatyzacja-projektu-z-msbuild-em-6-numer-wersji-z-svn-revision.aspx</link><pubDate>Fri, 25 Jul 2008 20:38:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1621</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1621.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1621</wfw:commentRss><description>&lt;p&gt;Tym razem zajmiemy się dynamiczną kompilacją, kt&amp;#243;ra wykona się r&amp;#243;wnież podczas budowy w Visual Studio. Naszym celem będzie stworzenie pliku &amp;quot;AssemblyInfo.cs&amp;quot; oraz dynamiczne włączenie go do kompilacji. Efektem tego, będzie brak AssemblyInfo w naszej strukturze plik&amp;#243;w widocznej w &amp;quot;Solution Explorer&amp;quot;. Nie będzie to kusiło żadnego z członk&amp;#243;w zespołu aby go modyfikować. Parametry do jego zawartości będą w centralnym miejscu. &lt;/p&gt;  &lt;p&gt;W tym odcinku pojawi się nowy plik - &amp;quot;tools\msbuild\rod.Commons\rod.Commons.Targets&amp;quot;. W nim znajdują się taski, kt&amp;#243;re będą opisane poniżej. Używam je we wszystkich swoich projektach, dlatego są wyodrębnione do oddzielnego pliku. W naszym wypadku, r&amp;#243;wnie dobrze jego zawartość można by umieścić w pliku Common.Targets. Ale zamiast tego umieścimy tam tylko Import.&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildExtensionsPath)\rod.Commons\rod.Commons.Targets&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RodCommonsTargetsIsLoaded) == ''&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Generowanie AssemblyInfo.cs&lt;/h3&gt;

&lt;p&gt;Następnym krokiem jest oczywiście &amp;quot;Exclude From Project&amp;quot; dla istniejących AssemblyInfo.cs. Ja dodatkowo oznaczam je jako ignore w SVN property. Pliki AssemblyInfo.cs będziemy generować za pomocą tasku &amp;quot;AssemblyInfo&amp;quot;. Parametry zapiszemy w Settings.proj.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- AssemblyInfo Properties --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyInfoFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Properties\AssemblyInfo.cs&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyInfoFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MySolution - $(AssemblyTitle)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyDescription&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Sample application.&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyDescription&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyCompany&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;rod&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyCompany&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyCopyright&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Copyright 2008 rod&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyCopyright&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyKeyFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(RootPath)\MySolution.snk&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyKeyFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyProduct&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;MySolution&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyProduct&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;1.0.0.0&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Dodatkowo możemy w każdym z projekt&amp;#243;w zmodyfikować poszczeg&amp;#243;lne properties. Nagł&amp;#243;wki naszych plik&amp;#243;w projektowych możemy zmienić w następujący spos&amp;#243;b:&lt;/p&gt;

&lt;p&gt;MyProject.csproj &lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(RootPath)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)\..\..\..\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Sample library&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyGuid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;F5830C28-699B-4789-AEA4-95AAB38A73CF&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyGuid&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;MyProject.Tests.csproj&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(RootPath)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)\..\..\..\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(AssemblyTitle) - Unit Tests for Sample library&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Za wygenerowanie AssemblyInfo.cs odpowiedzialny jest następujący target:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GenerateAssemblyInfo&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;CalculateAssemblyVersion&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyInfo&lt;/span&gt; &lt;span class="attr"&gt;CodeLanguage&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;CS&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;OutputFile&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyInfoFile)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;AssemblyTitle&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyTitle)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;AssemblyDescription&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyDescription)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;AssemblyCompany&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyCompany)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;AssemblyCopyright&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyCopyright)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;AssemblyProduct&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyProduct)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;AssemblyVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyVersion)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;AssemblyFileVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyVersion)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;AssemblyKeyFile&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyKeyFile)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;Guid&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyGuid)&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Target &amp;quot;CalculateAssemblyVersion&amp;quot;, od kt&amp;#243;rego jest uzależniony &amp;quot;GenerateAssemblyInfo&amp;quot;, będzie om&amp;#243;wiony p&amp;#243;źniej. W poprzednim odcinku dowiedzieliśmy się, że za zbi&amp;#243;r plik&amp;#243;w do kompilacji odpowiada ItemGroup &amp;quot;Compile&amp;quot;. Tym razem też go użyjemy:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IncludeGeneratedAssemblyInfo&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GenerateAssemblyInfo&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Exists('$(AssemblyInfoFile)')&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateItem&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyInfoFile)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Compile&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Include&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Touch&lt;/span&gt; &lt;span class="attr"&gt;Files&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyInfoFile)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Time&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;2000-01-01&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&amp;#160;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Wywołanie tasku Touch jest swego rodzaju trickiem. AssemblyInfo.cs bedzie generowany przy każdym wywołaniu Build-a. Jak wiemy, jeżeli pliki źr&amp;#243;dłowe nie zostały zmodyfikowane, w&amp;#243;wczas kompilacja podczas budowy jest pomijana. Gdybyśmy nie zastosowali powyższego tasku, w&amp;#243;wczas kompilacja odbywałaby się za każdym razem i podczas budowy solution w Visual Studio kompilowały by się wszystkie projekty, nawet te, kt&amp;#243;re nie były zmodyfikowane. Wywołamy powyższy target przed samą budową, wpisując w Common.Targets...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Add additional depends to Build target --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        IncludeGeneratedAssemblyInfo;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        $(BuildDependsOn)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BuildDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Dzięki temu plik AssemblyInfo.cs będzie się generował r&amp;#243;wnież podczas budowy Visual Studio ... i za pomocą NAnta nie dalibyśmy rady tego uzyskać lub byłoby to dosyć skomplikowane.&lt;/p&gt;

&lt;h3&gt;Tworzenie numeru wersji na podstawie wartości w pliku tekstowym oraz SVN revision.&lt;/h3&gt;

&lt;p&gt;W swoich projektach zazwyczaj stosuję następującą strategię wersjonowania 1.0.NumerIteracji.SVNRevision. Numer iteracji zapisuję w pliku w roocie projektu ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Helper Files --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;IterationNumberFile&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(IterationNumberFile)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(RootPath)\IterationNumber.txt&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;IterationNumberFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Ten plik może być generowany przez zewnętrzne narzędzie. Dobrym przykładem jest np. numer poprawnie przetestowanego builda przez narzędzie do Continuous Integration. Do pobrania numeru z pliku zastosujemy...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Gets the iteration number from file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GetIterationNumber&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Read the the iteration number file contents --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ReadLinesFromFile&lt;/span&gt; &lt;span class="attr"&gt;File&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(IterationNumberFile)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Lines&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IterationNumberFileContents&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ReadLinesFromFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Assign file contents to IterationNumber property --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;=&amp;quot;@(&lt;span class="attr"&gt;IterationNumberFileContents-&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;'%(Identity)')&amp;quot;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Value&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IterationNumber&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- If tehere is no IterationNumber, set zero --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(IterationNumber) == ''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Value&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;IterationNumber&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Z SVN revision jest trochę inaczej. Jeżeli dany projekt nie został zmodyfikowany będę nadal chciał kompilować go z SVN revision jego ostatniego commit-u. Ta informacja jest zapisana w &amp;quot;LastChangedRevision&amp;quot;. Jeżeli projekt został zmodyfikowany, zastosuje &amp;quot;Revision&amp;quot;, kt&amp;#243;re r&amp;#243;wna się najbliższemu numerowi, kt&amp;#243;ry zostanie nadany podczas następnego Commit. Jeżeli ktoś w międzyczasie zrobi własny revision, w&amp;#243;wczas ten numer nam wskaże na jego commit. Dobrą praktyką jest zatem zrobienie Commit potem Update a potem Build końcowy. &lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Get the revision number of the local working copy --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GetSvnRevision&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SvnVersion&lt;/span&gt; &lt;span class="attr"&gt;LocalPath&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildProjectDirectory)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;ContinueOnError&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Modifications&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SvnModified&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SvnVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SvnVersion&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;LocalPath&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildProjectDirectory)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;UseLastCommittedRevision&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;!$(SvnModified)&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;ContinueOnError&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Revision&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;SvnRevision&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SvnVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SvnRevision&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SvnRevision) == ''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;0&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SvnRevision&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Na końcu tasku zabezpieczamy property na wypadek, kiedy jeszcze nie mamy projektu pod kontrolą SVN-u. Ostatnim krokiem jest już złożenie wersji w całość.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;CalculateAssemblyVersion&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GetIterationNumber;GetSvnRevision&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt; &lt;span class="attr"&gt;Value&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(AssemblyVersion).$(IterationNumber).$(SvnRevision)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Value&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;PropertyName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AssemblyVersion&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateProperty&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Calculated Assembly Version: $(AssemblyVersion)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Importance&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;normal&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Należy pamiętać jednak aby zmienić w Settings.proj nasz AssemblyVersion na postać dwucyfrową np.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;1.0&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Kod do dzisiejszego odcinka znajdziecie tutaj -&amp;gt; &lt;a href="http://rodsamples.googlecode.com/svn/MSBuildTutorial/tags/part006"&gt;part006&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;Update 2008-07-30&lt;/h3&gt;

&lt;p&gt;Mała aktualizacja związana z podpisywaniem Assemblies. Już od wersji NET 2.0 assemblies powinno się podpisywać przy wykorzystaniu parametru do kompilatora a nie poprzez wpis w AssemblyInfo.cs. Kwestie bezpieczeństwa. Jeżeli zrobimy to wg starego sposobu, w&amp;#243;wczas podczas budowy pojawi się następujące ostrzeżenie.&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;warning CS1699: Use command line option '/keyfile' or appropriate project settings instead of 'AssemblyKeyFile'&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Zatem w Settings.proj dodajemy następujące linie:&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Signing Properties--&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SignAssembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SignAssembly&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyOriginatorKeyFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(RootPath)\MySolution.snk&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyOriginatorKeyFile&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... i oczywiście usuwamy property &amp;quot;AssemblyKeyFile&amp;quot;, kt&amp;#243;re zadeklarowaliśmy wcześniej w tym odcinku.&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1621" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/Subversion/default.aspx">Subversion</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/25/automatyzacja-projektu-z-msbuild-em-6-numer-wersji-z-svn-revision.aspx</feedburner:origLink></item><item><title>Automatyzacja projektu z MSBuild-em - 5. Makefile z Mono</title><link>http://feedproxy.google.com/~r/rodpl/~3/2P2tijIDhTI/automatyzacja-projektu-z-msbuild-em-5-makefile-z-mono.aspx</link><pubDate>Thu, 24 Jul 2008 20:14:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1615</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1615.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1615</wfw:commentRss><description>&lt;p&gt;W tym odcinku chciałbym przedstawić jak można dynamicznie budować kompilację, nie używając do tego w og&amp;#243;le Visual Studio. W następnym odcinku temat będzie podobny, ale już z uwzględnieniem Visual Studio.&lt;/p&gt;  &lt;p&gt;Za przykład posłuży nam projekt, kt&amp;#243;ry oryginalne był tworzony pod mono z wykorzystaniem plik&amp;#243;w Makefile. Mowa tu o FaRetSys aka eithne. Do budowy wykorzystamy źr&amp;#243;dła wersji &lt;a href="http://team.pld-linux.org/%7Ewolf/eithne/res/eithne-0.4.2.tar.bz2"&gt;0.4.2&lt;/a&gt;. Aby być niezależnym oraz nie modyfikować plik&amp;#243;w źr&amp;#243;dłowych w żaden spos&amp;#243;b, przyjąłem następującą strukturę:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;..      &lt;ul&gt;       &lt;li&gt;eithne - katalog, do kt&amp;#243;rego wrzucamy źr&amp;#243;dła eithne. Na ten katalog będzie wskazywać property $(SourcePath) &lt;/li&gt;        &lt;li&gt;eithne.msbuild - katalog z plikami, kt&amp;#243;re my będziemy tworzyć oraz dostarczać - $(RootPath)          &lt;ul&gt;           &lt;li&gt;build - zostanie utworzony dynamicznie i tu znajdzie się skompilowana aplikacja &lt;/li&gt;            &lt;li&gt;lib - katalog, do kt&amp;#243;rego wrzucamy potrzebne biblioteki - $(LibraryPath) &lt;/li&gt;            &lt;li&gt;tools - raczej oczywiste &lt;/li&gt;         &lt;/ul&gt;       &lt;/li&gt;     &lt;/ul&gt;   &lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;Projekt będziemy budować za pomocą &amp;quot;csc.exe&amp;quot; czyli .NET Framework a nie Mono. Do tego celu wykorzystamy oczywiście Microsoft.CSharp.targets. Jako pierwsze skompilujemy źr&amp;#243;dła IPlugin. Makefile do tych źr&amp;#243;deł wygląda następująco.&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;MCS = mcs&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;TARGET = ../IPlugin.dll&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;IPLUGIN = \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    BPP.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    CommSocket.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    Config.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    DialogMessage.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    DialogQuestion.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    GConfConfig.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    IBlock.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    ICommImage.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    ICommResult.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    IConfig.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    IFactory.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    IImage.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    IInfo.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    IInPlugin.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    IOutPlugin.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    IPlugin.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    IResult.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    IType.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    PluginException.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    Program.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    RegistryConfig.cs \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    ResultSorter.cs \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    Utility.cs&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;RESOURCES = \&lt;/pre&gt;

    &lt;pre class="alt"&gt;    DialogMessage.glade \&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    DialogQuestion.glade&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;RESFILES = $(addprefix resources/,$(RESOURCES))&lt;/pre&gt;

    &lt;pre class="alt"&gt;RESCMD = $(addprefix -resource:,$(RESFILES))&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;all: $(TARGET)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;$(TARGET): $(IPLUGIN) $(RESFILES)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    $(MCS) $(IPLUGIN) $(RESCMD) -out:$(TARGET) -target:library -r:Mono.Posix -unsafe -debug -pkg:gconf-sharp-2.0 -pkg:gtk-sharp-2.0 -pkg:glade-sharp-2.0&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;clean:&lt;/pre&gt;

    &lt;pre class="alt"&gt;    rm -f $(TARGET) $(TARGET).mdb&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Jak widać z tego pliku, musimy skompilować &amp;quot;library&amp;quot; z wyszczeg&amp;#243;lnionych plik&amp;#243;w .cs, załączyć pliki resources oraz stworzyć referencje do m.in. gtk-sharp itp. Za naszą budowę tej biblioteki będzie odpowiadał plik &amp;quot;IPlugin.proj&amp;quot;, kt&amp;#243;ry umieścimy w $(RootPath).&lt;/p&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;&lt;/h3&gt;

&lt;h3&gt;Źr&amp;#243;dła do kompilacji&lt;/h3&gt;

&lt;p&gt;Visual Studio zazwyczaj dodaje pliki do kompilacji pojedynczo. W naszym przypadku wszystkie pliki znajdują się w jednym miejscu więc bez obaw robimy następujący ItemGroup.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Compile&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\IPlugin\*.cs&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;EmbeddedResource&lt;/h3&gt;

&lt;p&gt;Biblioteka ma zawierać dwa pliki resource &amp;quot;DialogMessage.glade&amp;quot; oraz &amp;quot;DialogQuestion.glade&amp;quot;. C&amp;#243;ż prostszego ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;EmbeddedResource&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\IPlugin\resources\*.glade&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... i tutaj mamy pierwszą pułapkę. Kod programu odwołuje się do naszych resources w następujący spos&amp;#243;b.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;Glade.XML gxml = &lt;span class="kwrd"&gt;new&lt;/span&gt; Glade.XML(Assembly.GetExecutingAssembly()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                            , &lt;span class="str"&gt;&amp;quot;DialogMessage.glade&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;                            , &lt;span class="str"&gt;&amp;quot;DialogMessageWindow&amp;quot;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;                            , &lt;span class="kwrd"&gt;null&lt;/span&gt;);&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Aby taki kod m&amp;#243;gł zadziałać musimy dodać metatag LogicalName, czyli nasz kawałek definiujący resource w projekcie powinien wyglądać tak ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;EmbeddedResource&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\IPlugin\resources\DialogMessage.glade&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;LogicalName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;DialogMessage.glade&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;LogicalName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;EmbeddedResource&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Projekt IPlugin wymaga dw&amp;#243;ch plik&amp;#243;w jako resources ale w trakcie budowy Eithne.exe będziemy potrzebować ich prawie 50. Dodamy je zatem dynamicznie. Do tego potrzebujemy dodatkowy ItemGroup&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ResourcesToEmbed&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\IPlugin\resources\*.glade&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Teraz wygenerujemy EmbeddedResource z metatagiem LogicalName za pomocą następującego zadania, kt&amp;#243;re jako og&amp;#243;lnodostępne umieścimy je w Common.Targets&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GenerateEmbeddedResources&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateItem&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(ResourcesToEmbed)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;AdditionalMetadata&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;LogicalName=%(ResourcesToEmbed.FileName)%(ResourcesToEmbed.Extension)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;EmbeddedResource&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Include&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Referencje&lt;/h3&gt;

&lt;p&gt;Biblioteki potraktujmy jeszcze bardziej brutalnie :). Dodamy je wszystkie i zamiast tworzyć czegoś na styl ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Mono.Posix&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;False&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SpecificVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;  &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;..\..\lib\Mono.Posix.dll&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;HintPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... skorzystamy z zadania, kt&amp;#243;re umieszczamy w Common.Targets ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GenerateReferencesFromLibrary&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Libraries&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(LibraryPath)\*.dll&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CreateItem&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(Libraries.FileName)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;AdditionalMetadata&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;HintPath=%(Libraries.Identity)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Reference&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Include&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CreateItem&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;

    &lt;p&gt;Zadania &amp;quot;GenerateEmbeddedResources&amp;quot; oraz &amp;quot;GenerateReferencesFromLibrary&amp;quot; uruchamiany tuż przed budową czyli w pliku Common.Targets modyfikujemy property &amp;quot;BuildDependsOn&amp;quot; w taki spos&amp;#243;b&lt;/p&gt;

    &lt;div class="csharpcode-wrapper"&gt;
      &lt;div class="csharpcode"&gt;
        &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Add additional depends to Build target --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

        &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

        &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

        &lt;pre class="alteven"&gt;        GenerateReferencesFromLibrary;&lt;/pre&gt;

        &lt;pre class="alt"&gt;        GenerateEmbeddedResources;&lt;/pre&gt;

        &lt;pre class="alteven"&gt;        $(BuildDependsOn)&lt;/pre&gt;

        &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BuildDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

        &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;h3&gt;Pozostałe parametry kompilacji&lt;/h3&gt;


&lt;p&gt;Ostateczny wygląd IPlugin.proj jest następujący ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3.5&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DefaultTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(RootPath)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\Settings.proj&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Library&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;IPlugin&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System.Data&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System.Xml&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Compile&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\IPlugin\*.cs&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ResourcesToEmbed&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\IPlugin\resources\*.glade&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildToolsPath)\Microsoft.CSharp.targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\Common.Targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;OutputType definiuje nam czym mają być skompilowane assembly, w tym wypadku jako biblioteka dll, a AssemblyName jaka ma być jego nazwa. Pozostałe parametry kompilacji znajdują się w pliku Settings.proj, gdyż można powiedzieć, że są wsp&amp;#243;lne dla pozostałych projekt&amp;#243;w r&amp;#243;wnież.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Configuration&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Debug&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Platform&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Platform)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;AnyCPU&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Platform&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SchemaVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;2.0&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SchemaVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TargetFrameworkVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;v2.0&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TargetFrameworkVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;FileAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;512&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;FileAlignment&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AllowUnsafeBlocks&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AllowUnsafeBlocks&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DebugSymbols&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DebugSymbols&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DebugType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;full&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DebugType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Optimize&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;false&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Optimize&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\Debug\bin\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DefineConstants&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;DEBUG;TRACE&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DefineConstants&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ErrorReport&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;prompt&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ErrorReport&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;WarningLevel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;4&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;WarningLevel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BaseIntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\temp\Debug\obj\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BaseIntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;IntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\temp\Debug\obj\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;IntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;UseHostCompilerIfAvailable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;UseHostCompilerIfAvailable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)|$(Platform)' == 'Release|AnyCPU' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DebugType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;pdbonly&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DebugType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Optimize&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Optimize&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\Release\bin\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DefineConstants&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;TRACE&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DefineConstants&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ErrorReport&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;prompt&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ErrorReport&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;WarningLevel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;4&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;WarningLevel&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BaseIntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\temp\Release\obj\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BaseIntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;IntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\temp\Release\obj\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;IntermediateOutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;UseHostCompilerIfAvailable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;true&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;UseHostCompilerIfAvailable&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Zwr&amp;#243;ćcie uwagę na ustawienie true dla AllowUnsafeBlocks, kt&amp;#243;re jest wymagane w tym wypadku do kompilacji oraz na to że pliki automatycznie są wysyłane do odpowiedniego podkatalogu w katalogu &amp;quot;build&amp;quot; czyli $(BuildPath). &lt;/p&gt;

&lt;h3&gt;Circular reference&lt;/h3&gt;

&lt;p&gt;Jednak istnieje jedno zagrożenie. Plik Settings.proj jest zar&amp;#243;wno importowany na początku pliku IPlugin.proj jak i na początku Commons.Target. Oznacza to, że przypisywanie zmiennych w projektach odbywa się w następującej kolejności:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Settings.proj &lt;/li&gt;

  &lt;li&gt;IPlugin.Proj &lt;/li&gt;

  &lt;li&gt;Settings.proj &lt;/li&gt;

  &lt;li&gt;Common.Targets &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Jeżeli Setting.proj ustawia jakąś wartość zmiennej ABC, a potem IPlugin.proj zmienia tę wartość, to zanim dotrze ona do Common.Targets, z powrotem zostanie zamieniona na wartość z Settings.proj. Jest to w większości wypadk&amp;#243;w efekt niepożądany i nawet msbuild nas o tym informuje stosownym komunikatem&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;C:\Projects\eithne.msbuild&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;msbuild IPlugin.proj&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;

    &lt;pre class="alt"&gt;C:\Projects\eithne.msbuild\Common.Targets(9,10): warning MSB4011: There is a circular&lt;/pre&gt;

    &lt;pre class="alteven"&gt;reference involving the import of file &amp;quot;C:\Projects\eithne.msbuild\Settings.proj&amp;quot;. &lt;/pre&gt;

    &lt;pre class="alt"&gt;This file may have been imported more than once, or you may have attempted to import&lt;/pre&gt;

    &lt;pre class="alteven"&gt;the main project file. All except the first instance of this file will be ignored.&lt;/pre&gt;

    &lt;pre class="alt"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Aby się przed tym uchronić należy nadać warunek przed kolejnym importem najlepiej oparty o jakąś zmienną, kt&amp;#243;ra jest zdefiniowana tylko w pliku Settings.proj i kt&amp;#243;ra nie będziemy zazwyczaj modyfikować przy użyciu linii poleceń. Zatem import w pliku Common.Target powinien wyglądać tak...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Settings.proj&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(ToolsPath) == ''&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Budowa pliku Exe&lt;/h3&gt;

&lt;p&gt;Budowa gdk-cairo.dll wygląda tak samo jak IPlugin.proj. Służy od tego plik Gdk-Cairo.proj.&lt;/p&gt;

&lt;p&gt;Za plik exe odpowiadać będzie Eithne.proj. W stosunku do pozostałych plik&amp;#243;w proj r&amp;#243;żni się typem budowanego assembly ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;WinExe&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Eithne&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... większej ilości resources ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ResourcesToEmbed&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\resources\*.glade&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ResourcesToEmbed&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\resources\pixmaps\*.png&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... wykluczenia pliku gdk-cairo.cs z kompilacji ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Compile&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\*.cs&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Exclude&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(SourcePath)\gdk-cairo.cs&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... oraz ustawienia zależności pomiędzy pozostałymi projektami czyli ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProjectReference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\IPlugin.proj&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ProjectReference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProjectReference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\Gdk-Cairo.proj&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ProjectReference&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Teraz kompilując projekt Eithne.proj, pozostałe dwa projekty r&amp;#243;wnież zostaną zbudowane.&lt;/p&gt;

&lt;h3&gt;Kompilacja hurtowa plugin&amp;#243;w&lt;/h3&gt;

&lt;p&gt;Źr&amp;#243;dła plugin&amp;#243;w znajdują się w katalogu Plugins, kt&amp;#243;ry jest wskazywany przez zmienną $(PluginsSourcePath). Jest ich 28 i oznacza to 28 plik&amp;#243;w Makefile. Czy r&amp;#243;wnież oznacza to że musimy robić 28 plik&amp;#243;w .proj ? Niekoniecznie. Wszystkie te pluginy tak naprawdę r&amp;#243;żnią się nazwą zatem możemy zrobić projekt w stylu szablonu. Nazwijmy go PluginTemplate.proj. Oto on ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3.5&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DefaultTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(RootPath)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\Settings.proj&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProjectName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(PluginName)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ProjectName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Library&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputType&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AssemblyName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(PluginName)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;AssemblyName&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\temp\Debug\bin\Plugins\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DeployPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\Debug\bin\Plugins&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DeployPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(Configuration)|$(Platform)' == 'Release|AnyCPU' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\temp\Release\bin\Plugins\&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;OutputPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DeployPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(BuildPath)\Release\bin\Plugins&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DeployPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System.Data&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Reference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;System.Xml&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProjectReference&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\IPlugin.proj&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Compile&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(PluginsSourcePath)\$(PluginName)\*.cs&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ResourcesToEmbed&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(PluginsSourcePath)\$(PluginName)\resources\*.*&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildToolsPath)\Microsoft.CSharp.targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\Common.Targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AfterBuild&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildFiles&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(TargetDir)\$(TargetName).*&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;BuildFiles&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Copy&lt;/span&gt; &lt;span class="attr"&gt;SourceFiles&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;@(BuildFiles)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DestinationFolder&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(DeployPath)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;ContinueOnError&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;true&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;    &lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Jak widać, najistotniejszy jest parametr $(PluginName). Dzięki niemu możemy budować plugin w następujący spos&amp;#243;b.&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;C:\Projects\eithne.msbuild&amp;gt; msbuild PluginTemplate.proj /p:PluginName=Best&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Jedyną r&amp;#243;żnicą w por&amp;#243;wnaniu od poprzednich projekt&amp;#243;w jest prymitywny deployment.&amp;#160; OutputPath musi wskazywać na jakąś tymczasową lokalizację a potem gotowe assemblies muszą być kopiowane do nowej lokalizacji. Jeżeli tego nie zrobimy zadziała w&amp;#243;wczas target &amp;quot;IncrementalClean&amp;quot;, kt&amp;#243;ry nam wyczyści z &amp;quot;OutputPath&amp;quot; pliki z poprzednio budowanego plugina. Dzieję się tak gdyż tak naprawdę projekt o jednej nazwie PluginTemplate.proj buduje assemblies za każdym razem o innych nazwach więc traktuje poprzednio budowane pliki jako obce. Ale ten prosty deployment umieszczony w &amp;quot;AfterBuild&amp;quot; chroni nas przed tym. &lt;/p&gt;

&lt;p&gt;Dzieki takiemu rozwiazaniu, dołożenie przez programistę nowego pluginu nie powoduje zmiany plik&amp;#243;w proj. Wystarczy, że umieści go w nowym podkatalogu. Mamy coś w stylu Convention over Configuration.&lt;/p&gt;

&lt;p&gt;Teraz już pozostaje zbudować jednym poleceniem wszystkie pluginy. Zrobimy to przy wykorzystaniu nowego pliku Plugins.proj, kt&amp;#243;ry wygląda tak...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1.0&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;utf-8&amp;quot;&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;3.5&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;DefaultTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;http://schemas.microsoft.com/developer/msbuild/2003&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot; '$(RootPath)' == '' &amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(RootPath)\Settings.proj&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PluginsToBuild&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(PluginsSourcePath)\**&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Exclude&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(PluginsSourcePath)\**\resources\*;$(PluginsSourcePath)\*&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PluginsToBuild&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Import 3rd party targets --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;#160;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt;  &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GetPluginNames&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;PluginTemplate.proj&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Build&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Properties&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;PluginName=%(PluginNames.Identity)&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;GetPluginNames&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RegexReplace&lt;/span&gt; &lt;span class="attr"&gt;Input&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;%(PluginsToBuild.RecursiveDir)&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Expression&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;\\&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Replacement&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;Count&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;1&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;            &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt; &lt;span class="kwrd"&gt;=&amp;quot;PluginNames&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Output&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RegexReplace&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;W zadaniu &amp;quot;GetPluginNames&amp;quot; tworzymy listę nazw podkatalog&amp;#243;w, kt&amp;#243;rą p&amp;#243;źniej wykorzystujemy do uruchomienia tasku MSBuild&amp;#160; budującego projekt PluginTemplate.proj tyle razy ile jest podkatalog&amp;#243;w.&lt;/p&gt;

&lt;h3&gt;Podsumowanie&lt;/h3&gt;

&lt;p&gt;Gotowe rozwiązanie można pobrać stąd -&amp;gt; &lt;a href="http://rod.neostrada.pl/blog/eithne.msbuild.zip"&gt;eithne.msbuild.zip&lt;/a&gt;. Nie zawiera ono bibliotek wymaganych do kompilacji i uruchomienia, typu mono, gdk itp. Dla chętnych biblioteki są w oddzielnym pliku &lt;a href="http://rod.neostrada.pl/blog/eithne.msbuild.lib.zip"&gt;eithne.msbuild.lib.zip&lt;/a&gt; lub można dostarczyć je samemu kopiując do katalogu &amp;quot;lib&amp;quot;.&lt;/p&gt;

&lt;p&gt;Jak widać do naszej budowy potrzebujemy mniej własnych plik&amp;#243;w .proj aniżeli plik&amp;#243;w Makefile w oryginale. Aby rozkoszować się aplikacją zbudowaną na Windowsach bez użycia Mono wystarczy ...&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;C:\Projects\eithne.msbuild&amp;gt; msbuild Eithne.proj&lt;/pre&gt;

    &lt;pre class="alteven"&gt;C:\Projects\eithne.msbuild&amp;gt; msbuild Plugins.proj&lt;/pre&gt;

    &lt;pre class="alt"&gt;C:\Projects\eithne.msbuild&amp;gt; build\Debug\bin\Eithne.exe&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1615" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/Makefile/default.aspx">Makefile</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/Mono/default.aspx">Mono</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/24/automatyzacja-projektu-z-msbuild-em-5-makefile-z-mono.aspx</feedburner:origLink></item><item><title>Resize Form czyli WinForms-y okiem laika</title><link>http://feedproxy.google.com/~r/rodpl/~3/3V9ZDqe3_og/resize-form-czyli-winforms-y-okiem-laika.aspx</link><pubDate>Mon, 21 Jul 2008 21:12:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1594</guid><dc:creator>rod</dc:creator><slash:comments>5</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1594.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1594</wfw:commentRss><description>&lt;p&gt;W WinFormsach programuje zupełnie sporadycznie. Wole warstwy domenowe, serwisowe, bazodanowe i prezentacyjne (w modelach MVP). Widoki toleruje tylko pod MonoRail i ASP.NET. Ale WinForms ? .... e to nie dla mnie. Niestety życie bywa brutalne.&amp;nbsp; W moim aktualnym projekcie integruje system finansowo księgowy z danymi dostarczanymi z działu aktuarialnego. Procesem przetwarzania danych kieruje aplikacja WinForms-owa. Prosty wygląd w postaci zakładek, gdzie dwie zakładki posiadają kontrolki na wprowadzenie parametrów. Natomiast jedna posiada textbox z zawartością logu, a jeszcze inna ReportViewer z Microsoft Reporting. &lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:1c945c1b-c28b-4152-94eb-c414561cacc8" style="margin:0px;padding:0px;display:inline;float:none;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1590/original.aspx" alt="" style="width:415px;height:398px;"&gt;&lt;/div&gt;  &lt;p&gt;Poprzedni programista, który projektował UI, nie uwzględnił tego aby Form był w pełni resizable a wraz z nim textbox z zawartością logu oraz ReportViewer. Mimo, że program potrafi wykonywać skomplikowane przeliczenia księgowe wg. zawiłych reguł biznesowych, łącznie z importem do systemu to brak ładnego powiększania okienka może spowodować że projekt zostanie odrzucony. Dla klienta ważniejsze jest to co widzi aniżeli to co siedzi w środku. To normalne. Lecz niestety zadanie zrobienia resizable form spadło na mnie. No to zaczynamy. &lt;a href="http://www.google.com"&gt;www.google.com&lt;/a&gt; ... "form c# resize child controls" ... press "search" ... i w sumie nic ciekawego nie znalazłem. No dobra filozofia jest przecież banalna. Jak powiększę okno o powiedzmy 100 px to pozostałe kontrolki też należy powiększyć o te 100 px. Piece of cake. Hmm, ale jak to zrobić i się nie narobić i żeby na przyszłość można było w łatwy sposób dokładać następne kontrolki, które mają reagować tak samo na powiększenie okna. &lt;/p&gt;  &lt;p&gt;Na początek należy przechować jaka jest różnica w wysokości i szerokości pomiędzy kontrolkami a oknem. Początkowo do przechowania WidthDifference i HeightDifference zrobiłem własną strukturę, ale szybko okazało się ze już jest taka struktura - Size, wiec postanowiłem ją wykorzystać. Końcowe rozwiązanie mojego problemu jest następujące. &lt;/p&gt;  &lt;p&gt;Deklarujemy pole ...&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; IDictionary&amp;lt;Control, Size&amp;gt; _sizeDifferences = &lt;span class="kwrd"&gt;new&lt;/span&gt; Dictionary&amp;lt;Control, Size&amp;gt;();&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... podczas ładowania okna zapamiętujemy różnice taką metodą ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; RememberInitialSizeDifferences()&lt;/pre&gt;

    &lt;pre class="alteven"&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;    _sizeDifferences.Add(MainTabControl, this.Size - MainTabControl.Size);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    _sizeDifferences.Add(CurrentLogTextBox, this.Size - CurrentLogTextBox.Size);&lt;/pre&gt;

    &lt;pre class="alt"&gt;    _sizeDifferences.Add(ImportSummaryReportViewer, this.Size - ImportSummaryReportViewer.Size);&lt;/pre&gt;

    &lt;pre class="alteven"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;... dodajemy metodę do eventu Resize dla obiektu Form z taką zawartością ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; MainWindows_Resize(&lt;span class="kwrd"&gt;object&lt;/span&gt; sender, EventArgs e)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;{&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;foreach&lt;/span&gt; (var pair &lt;span class="kwrd"&gt;in&lt;/span&gt; _sizeDifferences)&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        pair.Key.Size = this.Size - pair.Value;&lt;/pre&gt;

    &lt;pre class="alt"&gt;}&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Szybko, prosto i przyjemnie. Można się jeszcze pokusić o bardziej uniwersalne rozwiązanie i aby jakism fajnym atrybutem dekorować te kontrolki, które mają się powiększać wraz z oknem o tę sama ilośc pikseli co samo okno. Ale ... WinFormsy to nie moja działka.&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1594" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/WinForms/default.aspx">WinForms</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/21/resize-form-czyli-winforms-y-okiem-laika.aspx</feedburner:origLink></item><item><title>Automatyzacja projektu z MSBuild-em - 4a. TDD, prawie jak TestDriven.NET</title><link>http://feedproxy.google.com/~r/rodpl/~3/ECLdB0xD8eE/automatyzacja-projektu-z-msbuild-em-4a-tdd-prawie-jak-testdriven-net.aspx</link><pubDate>Thu, 17 Jul 2008 12:51:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1559</guid><dc:creator>rod</dc:creator><slash:comments>0</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1559.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1559</wfw:commentRss><description>&lt;p&gt;Wcześniej już wspominałem, jestem strasznie leniwy. Nie lubię pokonywać setek kilometrów myszką, nie lubię pisać dwa razy tego samego, nie lubię często naciskać Alt+Tab ... i wpadłem na taki pomysł.&lt;/p&gt;  &lt;p&gt;   &lt;/p&gt;&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:e8a9c5bf-6229-48c9-a2ce-0c3cd664900a" style="margin:0px;padding:0px;display:inline;float:none;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1555/original.aspx" alt="" style="width:396px;height:391px;"&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt;  &lt;p&gt;   &lt;/p&gt;&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:076a4249-b86f-46e6-96af-9b205073074f" style="margin:0px;padding:0px;display:inline;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1557/original.aspx" alt="" style="width:396px;height:391px;"&gt;&lt;/div&gt; &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Teraz wystarczy zamapować klawisze, np...&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:1bf5ee3e-5689-42ce-8cc4-4027d04ea3e1" style="margin:0px;padding:0px;display:inline;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1558/original.aspx" alt="" style="width:403px;height:250px;"&gt;&lt;/div&gt;  &lt;p&gt;... i prawie jak TestDriven.NET :)&lt;/p&gt;  &lt;p&gt;A teraz mała opowiastka ... Ostatnio, w trakcie rozmowy rekrutacyjnej w ramach poszukiwania pracy, spytałem osobę, która&amp;nbsp; przeprowadzała ze mną wywiad, czy w swoich projektach wykorzystują TDD. Okazało się, że chcieliby, ale tak nie do końca bo mają testy własne napisane we frameworku X, który znają, a dostali jeszcze w spadku poprzednia wersję, którą miała napisane testy we frameworku Y i niby teraz trzeba by przepisać te testy a nie ma czasu etc etc ?!?!?&lt;/p&gt;  &lt;p&gt;Ja wychodzę z założenia że lepsze unit testy jakiekolwiek, niż żadne. Framework się nie liczy. Oczywiście nie należy dopuszczać, aby każdy członek zespołu pisał przy wykorzystaniu innego framework-u. Gdy dostajemy testy "w spadku" wykonane w innym narzędziu to zamiast je przepisywać, lepiej je uruchamiać razem.&lt;/p&gt;  &lt;p&gt;Dlatego w którymś z dalszych odcinków będę chciał się zmierzyć z uruchamianiem testów pod kilka platform za jednym przyciśnięciem klawisza. Ciekawe czy TestDriven.NET to potrafi ? Przyznam się że nie wiem.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Update:&lt;/b&gt; Na pierwszym obrazku, czyli "Test Current Solution" jest błąd. Czy znajdzie się osoba, która uważnie przeczytała poprzedni odcinek i będzie potrafiła go poprawić ?&lt;br&gt;&lt;/p&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1559" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/TDD/default.aspx">TDD</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/Visual+Studio/default.aspx">Visual Studio</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/17/automatyzacja-projektu-z-msbuild-em-4a-tdd-prawie-jak-testdriven-net.aspx</feedburner:origLink></item><item><title>Automatyzacja projektu z MSBuild-em - 4. TDD</title><link>http://feedproxy.google.com/~r/rodpl/~3/HisLweplQT4/automatyzacja-projektu-z-msbuild-em-4-tdd.aspx</link><pubDate>Wed, 16 Jul 2008 23:04:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1546</guid><dc:creator>rod</dc:creator><slash:comments>4</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1546.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1546</wfw:commentRss><description>&lt;p&gt;W tym odcinku zajmiemy się testowaniem.&lt;/p&gt;  &lt;h3&gt;Rozdzielna budowa&lt;/h3&gt;  &lt;p&gt;Na początek warto stworzyć dwa pomocnicze targety: "BuildApp" oraz "BuildTest". Pierwszy z nich będzie oczywiście budował projekty składające się na aplikację, a drugi testy. Do tego potrzebujemy listy projektów z rozbiciem na dwa typy. To zrobi dla nas target "GetProjectsFromSolution", który umieszczamy w Default.proj&lt;/p&gt;  &lt;div class="csharpcode-wrapper"&gt;   &lt;div class="csharpcode"&gt;     &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="GetProjectsFromSolution"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Get all the projects associated with the solution --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;GetSolutionProjects&lt;/span&gt; &lt;span class="attr"&gt;Solution&lt;/span&gt;&lt;span class="kwrd"&gt;="$(SolutionPath)"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="Output"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="SolutionProjects"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;GetSolutionProjects&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Filter out solution folders and non .csproj items --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt; &lt;span class="attr"&gt;Input&lt;/span&gt;&lt;span class="kwrd"&gt;="@(SolutionProjects)"&lt;/span&gt; &lt;span class="attr"&gt;Expression&lt;/span&gt;&lt;span class="kwrd"&gt;=".[\.]csproj$"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="Output"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="Projects"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Resolve test projects --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt; &lt;span class="attr"&gt;Input&lt;/span&gt;&lt;span class="kwrd"&gt;="@(Projects)"&lt;/span&gt; &lt;span class="attr"&gt;Expression&lt;/span&gt;&lt;span class="kwrd"&gt;="$(TestDetectionExpression)[\.]csproj$"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="Output"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="TestProjects"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Resolve the libraries code projects --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;AppProjects&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="@(Projects)"&lt;/span&gt; &lt;span class="attr"&gt;Exclude&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestProjects)"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;="$(NEW_LINE)Resolved the following solution projects:"&lt;/span&gt; &lt;span class="attr"&gt;Importance&lt;/span&gt;&lt;span class="kwrd"&gt;="high"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;="&lt;span class="attr"&gt;AppProjects:&lt;/span&gt;$(&lt;span class="attr"&gt;NEW_LINE&lt;/span&gt;)$(&lt;span class="attr"&gt;TAB&lt;/span&gt;)@(App&lt;span class="attr"&gt;Projects-&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;'%(RelativeDir)%(FileName)%(Extension)', '$(NEW_LINE)$(TAB)')" Importance="high"&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;="&lt;span class="attr"&gt;TestProjects:&lt;/span&gt;$(&lt;span class="attr"&gt;NEW_LINE&lt;/span&gt;)$(&lt;span class="attr"&gt;TAB&lt;/span&gt;)@(&lt;span class="attr"&gt;TestProjects-&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;'%(RelativeDir)%(FileName)%(Extension)', '$(NEW_LINE)$(TAB)')" Importance="high"&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Pomocnicze property, które później też wykorzystamy znajduje się w Settings.proj&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TestDetectionExpression&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;.[\.](Test[s]{0,1})&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TestDetectionExpression&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Jak łatwo się domyśleć jego wykonanie będzie skutkować takim wynikiem&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;C:\...\trunk&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kwrd"&gt;&lt;/span&gt;msbuild Default.proj /t:GetProjectsFromSolution&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;

    &lt;pre class="alt"&gt;Resolved the following solution projects:&lt;/pre&gt;

    &lt;pre class="alteven"&gt;AppProjects:&lt;/pre&gt;

    &lt;pre class="alt"&gt;      C:\...\trunk\src\app\MyProject\MyProject.csproj&lt;/pre&gt;

    &lt;pre class="alteven"&gt;TestProjects:&lt;/pre&gt;

    &lt;pre class="alt"&gt;      C:\...\trunk\src\test\MyProject.Tests\MyProject.Tests.csproj&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Parę słów wyjaśnienia. Zwróćcie uwagę, że lista projektów jest pobierana z solution, z property "SolutionPath". Jeżeli nasza aplikacja składa sie z wielu projektów, może się okazać, że warto zrobić dodatkowe pliki .sln grupujące projekty w zależności np. od warstwy - MySolution.Services.sln. Teraz, aby zbudować kod z tej okrojonej grupy wystarczy ...&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;pre class="console"&gt;C:\...\trunk&amp;gt; msbuild Default.proj /t:BuildApp /p:SolutionPath=.\MySolution.Services.sln&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Jak widać do rozdzielenia różnych rodzajów projektów wykorzystujemy expression regexp-a. Należy również zwrócić uwagę na "ItemGroup". Od wersji MSBuild 3.5 można używać "ItemGroup" jak i "PropertyGroup" wewnątrz znaczników "Target". W poprzedniej wersji&amp;nbsp; należało wykorzystywać "CreateItem" i "CreateProperty". Dodatkowo możemy teraz usuwać wartości z ItemGroup np. &lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;!&lt;/span&gt;—Remove *.licx from the EmbeddedResource list - -&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;EmbeddedResource&lt;/span&gt; &lt;span class="attr"&gt;Remove&lt;/span&gt;&lt;span class="kwrd"&gt;="*.licx"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Aby zwiększyć czytelność dodałem pomocnicze properties takie jak $(NEW_LINE) i $(TAB). Są one zadeklarowane w pliku Settings.proj w następujący sposób...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;&amp;lt;!-- ASCII Constants --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;NEW_LINE&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;%0D%0A&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;NEW_LINE&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;TAB&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;%09&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;TAB&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;DOUBLE_QUOTES&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;%22&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;DOUBLE_QUOTES&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SPACE&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;%20&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SPACE&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Teraz pozostaje nam zbudować brakujące zadania "BuildApp" i "BuildTest" oraz zrefaktorować target "BuildAll", który powstał w poprzednim odcinku.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildAll"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildApp;BuildTest"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildApp"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="GetProjectsFromSolution"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;="@(AppProjects)"&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;             &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="TargetOutputs"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="AppAssemblies"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Add all assemblies to all build assemblies --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildAssemblies&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="@(AppAssemblies)"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildTest"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="GetProjectsFromSolution"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestProjects)"&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;             &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="TargetOutputs"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="TestAssemblies"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Add all assemblies to all build assemblies --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;BuildAssemblies&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestAssemblies)"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Wynikiem zadań są properties "AppAssemblies", "TestAssemblies" oraz "BuildAssemblies", które zawierają odpowiednio pliki wynikowe aplikacji, testów oraz wszystkie pliki, które powstały w trakcie tego przebiegu budowy.&lt;/p&gt;

&lt;h3&gt;Uruchomienie testów&lt;/h3&gt;

&lt;p&gt;Do testów wykorzystałem NUnit v2.5 alpha. Znajduje się on w tools\nunit. Napisałem prostą klasę testująca, która zwraca jeden poprawny i jeden niepoprawny rezultat. Naszym celem jest teraz umożliwienie uruchomienia testu dla pojedynczego projektu jak i zbiorowo czyli ...&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre class="alt"&gt;C:\...\trunk&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; msbuild src\test\MyProject.Tests\MyProject.Tests.csproj /t:Test&lt;/pre&gt;

    &lt;pre class="alteven"&gt;C:\...\trunk&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; msbuild Default.proj /t:TestAll&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Zaczynamy od definicji ścieżki do NUnit w pliku Settings.proj&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;NUnitPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(ToolsPath)\nunit&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;NUnitPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Następnie tworzymy target "Test" w Common.Targets&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="Test"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Assemblies&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="$(TargetDir)\$(TargetName).dll"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt; &lt;span class="attr"&gt;Input&lt;/span&gt;&lt;span class="kwrd"&gt;="@(Assemblies)"&lt;/span&gt; &lt;span class="attr"&gt;Expression&lt;/span&gt;&lt;span class="kwrd"&gt;="&lt;/span&gt;&lt;span class="kwrd"&gt;$(TestDetectionExpression)&lt;/span&gt;&lt;span class="kwrd"&gt;[\.]dll$"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="Output"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="TestAssemblies"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;NUnit&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '@(TestAssemblies)' != '' "&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;ToolPath&lt;/span&gt;&lt;span class="kwrd"&gt;="$(NUnitPath)"&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;Assemblies&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestAssemblies)"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Tutaj zastosowałem małą sztuczkę w celu wyodrębnienia testów należących do faktycznie kompilowanego projektu. Może zdarzyć się sytuacja, że jeden test zależy od drugiego testu i oba assemblies o końcówce *.Test.dll razem znajda się w $(TargetDir), a nam zależy aby testować tylko jedno, aktualnie zbudowane assembly. Jeżeli nie ma plików testowych, wówczas NUnit nie jest uruchamiany.&lt;/p&gt;

&lt;p&gt;"TestAll" w Default.proj możemy zaprojektować na dwa sposoby&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="TestAll"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="GetProjectsFromSolution"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestProjects)"&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;="Test"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Czyli wywołanie zadania "Test" dla każdego projektu testowego, co skutkuje również jego budową lub ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="TestAll"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildTest"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;NUnit&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '@(TestAssemblies)' != '' "&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;ToolPath&lt;/span&gt;&lt;span class="kwrd"&gt;="$(NUnitPath)"&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;Assemblies&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestAssemblies)"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Pierwsze rozwiązanie wydaje się być bardziej eleganckie, zwłaszcza że drugie rozwiązanie wygląda podobnie jak w Commons.Target, wiec jak coś się zmieni w sposobie uruchamiania testu np. generowanie raportu, wówczas mamy wyraźne złamanie DRY principle i musimy poprawić kod w dwóch miejscach. Ale ... Jeżeli mamy więcej projektów testowych to przy pierwszym rozwiązaniu wykonanie będzie następujące: &lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Build ProjectOne &lt;/li&gt;

  &lt;li&gt;Test ProjectOne &lt;/li&gt;

  &lt;li&gt;Build ProjectTwo &lt;/li&gt;

  &lt;li&gt;Test ProjectTwo &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;W drugim rozwiązaniu:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Build ProjectOne &lt;/li&gt;

  &lt;li&gt;Build ProjectTwo &lt;/li&gt;

  &lt;li&gt;Test ProjectOne &lt;/li&gt;

  &lt;li&gt;Test ProjectTwo &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Osobiście wole kiedy najpierw zbudują mi się wszystkie testy i jak to przebiegnie pomyślnie wówczas je przetestuje. Jednak żeby nikt nam nie zarzucał "Don't Repeat Yourself" zrobimy mały refaktoring i dodamy do pliku "Settings.proj"...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="InternalNUnit"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;NUnit&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '@(TestAssemblies)' != '' "&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="attr"&gt;ToolPath&lt;/span&gt;&lt;span class="kwrd"&gt;="$(NUnitPath)"&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="attr"&gt;Assemblies&lt;/span&gt;&lt;span class="kwrd"&gt;="@(TestAssemblies)"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Refaktoring Default.proj&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="TestAll"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildTest"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CallTarget&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;="InternalNUnit"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Refaktoring Common.Targets&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="Test"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build;GetTestAssemblies"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CallTarget&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;="InternalNUnit"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="GetTestAssemblies"&lt;/span&gt; &lt;span class="attr"&gt;DependsOnTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Assemblies&lt;/span&gt; &lt;span class="attr"&gt;Include&lt;/span&gt;&lt;span class="kwrd"&gt;="$(TargetDir)$(TargetName)*.dll"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ItemGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt; &lt;span class="attr"&gt;Input&lt;/span&gt;&lt;span class="kwrd"&gt;="@(Assemblies)"&lt;/span&gt; &lt;span class="attr"&gt;Expression&lt;/span&gt;&lt;span class="kwrd"&gt;="$(TestDetectionExpression)[\.]dll$"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Output&lt;/span&gt; &lt;span class="attr"&gt;TaskParameter&lt;/span&gt;&lt;span class="kwrd"&gt;="Output"&lt;/span&gt; &lt;span class="attr"&gt;ItemName&lt;/span&gt;&lt;span class="kwrd"&gt;="TestAssemblies"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RegexMatch&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Uwaga: &lt;/strong&gt;Target "Test" umyślnie rozbiłem na dwa targety. MSBuild ma takie ograniczenie, że jeżeli manipulujemy jakimś Item lub Property to zmiana ta będzie widoczna dla innych targetów dopiero po zakończeniu aktualnego. Zatem manipulacja Property a potem wywołanie CallTarget nie powiodłaby się. Na to trzeba uważać.&lt;/p&gt;

&lt;p&gt;Kod do dzisiejszego odcinka znajdziecie tutaj -&amp;gt; &lt;a href="http://rodsamples.googlecode.com/svn/MSBuildTutorial/tags/part004"&gt;Part004&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;W następnym odcinku zobaczymy jak zrobić Assembly.cs, którego nikt nie będzie widział w projekcie, czyli dynamiczne dokładanie plików.&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1546" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/NUnit/default.aspx">NUnit</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/TDD/default.aspx">TDD</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/17/automatyzacja-projektu-z-msbuild-em-4-tdd.aspx</feedburner:origLink></item><item><title>Automatyzacja projektu z MSBuild-em - 3. Początki</title><link>http://feedproxy.google.com/~r/rodpl/~3/LqcEvAxRmfA/organizacja-projektu-i-automatyzacja-z-wykorzystaniem-msbuild-a-3-podstawy.aspx</link><pubDate>Tue, 15 Jul 2008 18:06:00 GMT</pubDate><guid isPermaLink="false">0de27b5c-4a0c-4e7a-8e19-9d082c99f8a3:1512</guid><dc:creator>rod</dc:creator><slash:comments>4</slash:comments><comments>http://zine.net.pl/blogs/rod/comments/1512.aspx</comments><wfw:commentRss>http://zine.net.pl/blogs/rod/commentrss.aspx?PostID=1512</wfw:commentRss><description>&lt;p&gt;W ramach dalszych odcinków będę budował od podstaw pliki do MSBuild na przykładzie prostego projektu w .NET 3.5 tak aby każdy mógł "poczuć" działające rozwiązanie. Poszczególne etapy rozwiązania znajdują się w &lt;a href="https://rodsamples.googlecode.com/svn/MSBuildTutorial/tags"&gt;repozytorium SVN&lt;/a&gt; w podkatalogach o numeracji odpowiadającej poszczególnym odcinkom.&lt;/p&gt;  &lt;p&gt;Zanim przystąpimy do pracy warto zapatrzeć się w dwa proste narzędzia:&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;&lt;a href="http://msbuildtasks.tigris.org/"&gt;MSBuild Community Tasks Project&lt;/a&gt; - Biblioteka rozszerzająca funkcjonalność MSBuild. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://www.codeplex.com/msbdbg"&gt;Visual Debugger for MSBuild Projects&lt;/a&gt; - Jak sama nazwa wskazuje debugger do plików MSBuild, co prawda średnio stabilny, ale potrafi czasem pomóc. &lt;/li&gt;    &lt;li&gt;&lt;a href="http://code.msdn.microsoft.com/PowerCommands"&gt;PowerCommands for Visual Studio 2008&lt;/a&gt; - Dodatek do Visual Studio, który m.in. ułatwia edycję plików csproj z poziomu naszego IDE dodając opcję "Edit Project File" spod prawego klawisza w "Solution Explorer" . Bez tego też nam się to uda, ale należy wówczas&amp;nbsp; zrobić "Unload Project" a potem "Edit Prtoject File". &lt;/li&gt; &lt;/ul&gt;  &lt;h3&gt;Pliki podstawowe &lt;/h3&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Będziemy tworzyć automatyzację do bardzo prostej aplikacji, która ma strukturę katalogów taką jak opisywałem w pierwszej części. Plik "MySolution.sln" zawiera odniesienie do dwóch plików projektowych "MyProject.csproj" oraz "MyProject.Tests.csproj".&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:ebff8108-76c3-44e0-a12e-ba2f68349ceb" style="margin:0px;padding:0px;display:inline;float:none;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1499/original.aspx" alt="" style="width:237px;height:209px;"&gt;&lt;/div&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Z linii poleceń możemy skompilować nasze rozwiązanie w całości lub poszczególne projekty wykonując następujące polecenia:&lt;/p&gt;  &lt;div class="console-wrapper"&gt;   &lt;div class="console"&gt;     &lt;pre&gt;C:\...\trunk&amp;gt; msbuild MySolution.sln
C:\...\trunk&amp;gt; msbuild src\app\MyProject\MyProject.csproj
C:\...\trunk&amp;gt; msbuild src\test\MyProject.Tests\MyProject.Tests.csproj&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;W tej chwili nie mamy&amp;nbsp; żadnego punktu centralnego gdzie moglibyśmy zarządzać wspólnymi parametrami. Pliki .csproj nie mają żadnego wspólnego punktu stycznego z którego mogłyby czerpać informację. Dodatkowo plik MySolution.sln nie jest plikiem, który możemy edytować. Aktualnie jest następujący workflow pomiędzy plikami w trakcie budowy.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:ef0d8443-fb68-4a60-be9b-d917f2912479" style="margin:0px;padding:0px;display:inline;float:none;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1502/original.aspx" alt="" style="width:380px;height:140px;"&gt;&lt;/div&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Aby zapewnić lepszą elastyczność i centralizacje parametrów doprowadźmy do takiego powiązania plików ...&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:2cc64b27-cf87-4680-9924-b9a2ee26fc82" style="margin:0px;padding:0px;display:inline;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1510/original.aspx" alt="" style="width:501px;height:233px;"&gt;&lt;/div&gt;

&lt;p&gt;To powiązanie jest łudząco podobne to układu w projekcie NHibernate. &lt;/p&gt;

&lt;p&gt;Plik Settings.proj będzie plikiem zawierającym wspólne parametry, które będą wykorzystywane zarówno przez Default.proj jak i Common.Targets.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;&amp;lt;!--&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    ==================================================&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;        Settings file for VS and external build files&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    ==================================================&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;--&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/developer/msbuild/2003"&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;="3.5"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '$(RootPath)' == '' "&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Project folders --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ToolsPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(RootPath)\tools&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ToolsPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Project files --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;SolutionPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;$(RootPath)\&lt;/span&gt;MySolution.sln&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;SolutionPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Property "RootPath" ma zawsze wskazywać na główny katalog naszego projektu i poprzez niego będziemy się zawsze odwoływać do wszystkich ścieżek. W ten sam sposób tworzymy "zmienne" ze ścieżkami pomocniczymi do katalogów np. "ToolsPath" lub plików jak "SolutionPath".&lt;/p&gt;

&lt;p&gt;Plik Default.proj będzie zawierał parametry oraz akcje wykonywane przez inne procesy niż Visual Studio np. przez Continuous Integration lub poprzez ręczne uruchomienie. Na początku będzie wyglądał bardzo prosto ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt; ?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;&amp;lt;!--&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    ==================================================&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;        Default file for external builds&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    ==================================================&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;--&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;DefaultTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildAll"&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/developer/msbuild/2003"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- This file must be imported first --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;="Settings.proj"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&amp;nbsp;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="BuildAll"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuild&lt;/span&gt; &lt;span class="attr"&gt;Projects&lt;/span&gt;&lt;span class="kwrd"&gt;="$(SolutionPath)"&lt;/span&gt; &lt;span class="attr"&gt;Targets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build"&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Należy mieć na uwadze, że plik "Settings.proj" ma być importowany jak najwcześniej. Domyślnym celem jest "BuildAll", który nie robi nic innego tylko w prosty sposób buduje solution. Teraz juz wystarczy ...&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;div class="console"&gt;
    &lt;pre&gt;C:\...\trunk&amp;gt; msbuild Default.proj&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Każdy plik .csproj powinien być powiązany z plikiem Common.Targets, który na razie będzie wyglądał tak ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;&amp;lt;!--&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    ==================================================&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;        Common file for VS and external build files&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    ==================================================&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;--&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/developer/msbuild/2003"&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;="3.5"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- This file must be imported first --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;="Settings.proj"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;="Exists('$(RootPath)\Common.User.Targets')"&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;="$(RootPath)\Common.User.Targets"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Plik Common.User.Targets to plik opcjonalny, który może zawierać parametry lub akcje specyficzne dla użytkownika. Dlatego daje ten plik do ignorowania przez svn, gdyż każdy programista w zespole może chcieć umieścić w nim różne zadania, niezależne od reszty zespołu.&lt;/p&gt;

&lt;p&gt;Teraz można przystąpić do edycji plików .csproj. Na początku pliku należy poprawnie zdeklarować property RootPath ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="html"&gt;xml&lt;/span&gt; &lt;span class="attr"&gt;version&lt;/span&gt;&lt;span class="kwrd"&gt;="1.0"&lt;/span&gt; &lt;span class="attr"&gt;encoding&lt;/span&gt;&lt;span class="kwrd"&gt;="utf-8"&lt;/span&gt;?&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt; &lt;span class="attr"&gt;ToolsVersion&lt;/span&gt;&lt;span class="kwrd"&gt;="3.5"&lt;/span&gt; &lt;span class="attr"&gt;DefaultTargets&lt;/span&gt;&lt;span class="kwrd"&gt;="Build"&lt;/span&gt; &lt;span class="attr"&gt;xmlns&lt;/span&gt;&lt;span class="kwrd"&gt;="http://schemas.microsoft.com/developer/msbuild/2003"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- Root Path definition relative for actual build file --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '$(RootPath)' == '' "&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(MSBuildProjectDirectory)\..\..\..&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;RootPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Configuration&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '$(Configuration)' == '' "&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;Debug&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Configuration&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Platform&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;=" '$(Platform)' == '' "&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;AnyCPU&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Platform&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;ProductVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;9.0.21022&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;ProductVersion&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;$(MSBuildProjectDirectory) wskazuje na katalog w którym aktualnie znajduje sie uruchamiany skrypt MSBuild. Następnie na końcu pliku projektu dodajemy nasz Common.Targets do importu. Czyli ...&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;...&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;="$(MSBuildToolsPath)\Microsoft.CSharp.targets"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;="$(RootPath)\Common.Targets"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="rem"&gt;&amp;lt;!-- To modify your build process, add your task inside one of the targets below and uncomment it. &lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;        Other similar extension points exist, see Microsoft.Common.targets.&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;        &amp;lt;Target Name="BeforeBuild"&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    &amp;lt;/Target&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;    &amp;lt;Target Name="AfterBuild"&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="rem"&gt;    &amp;lt;/Target&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;    --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Uwaga: &lt;/strong&gt;Wartości odnoszące się do ścieżek nie zawsze na końcu zwracają "\".&amp;nbsp; Warto o tym pamiętać. &lt;/p&gt;

&lt;p&gt;Jeżeli&amp;nbsp; nie popełniliśmy żadnego błędu to po załadowaniu naszego solution do Visual Studio powinniśmy zobaczyć tylko komunikaty ostrzegawcze o modyfikacjach plików .csproj.&lt;/p&gt;

&lt;div class="wlWriterSmartContent" id="scid:6960CE03-38FC-44df-87D4-FA4540212B06:29dc1f2a-0015-48e7-bf55-fa16035f76bb" style="margin:0px;padding:0px;display:inline;"&gt;&lt;img src="http://zine.net.pl/photos/posts_pictures/images/1511/original.aspx" alt="" style="width:551px;height:389px;"&gt;&lt;/div&gt;

&lt;p&gt;Należy wybrać "Load project normally". Jeżeli będzie jakiś błąd w ścieżkach wówczas Visual Studio poinformuje nas o błędzie i pozostawi błędny projekt w stanie "Unload". Należy poprawić błąd i zrobić "Reload Project". Uczulam przed modyfikacja plików, które dodaliśmy w momencie, kiedy mamy otwarty projekt w Visual Studio. Czasem te pliki są cacheowane i wywołanie "Build" spod VS może nie uwzględnić zmian. W trakcie tworzenia własnych ulepszeń proponuje testować po prostu z linii poleceń.&lt;/p&gt;

&lt;h3&gt;Współdzielone pliki Targets&lt;/h3&gt;

&lt;p&gt;Przydałoby się zaimplementować jakieś proste zadanie wykorzystujące MSBuild Community Tasks. Zapewne już zainstalowaliśmy te rozszerzenia do MSbuild-a, ale czy pozostali programiści w zespole też to zrobili ? Aby uniknąć przykrych niespodzianek warto skopiować zawartosc katalogu "C:\Program Files\MSbuild" do naszego "tools\msbuild". Należy również zmienić zawartość property "MSBuildExtensionsPath" oraz zaimportować rozszerzenia. Robimy to dodając do pliku "Settings.proj" wpis ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;...&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;&amp;lt;!-- 3rd Party Program Paths --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;MSBuildExtensionsPath&lt;/span&gt; &lt;span class="attr"&gt;Condition&lt;/span&gt;&lt;span class="kwrd"&gt;="Exists('$(ToolsPath)\msbuild')"&lt;/span&gt; &lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;$(ToolsPath)\msbuild&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;MSBuildExtensionsPath&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;A do Common.Targets dodajemy linie importu...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;...&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Import&lt;/span&gt; &lt;span class="attr"&gt;Project&lt;/span&gt;&lt;span class="kwrd"&gt;="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h3&gt;Pierwsze wspólne zadanie do kompilacji&lt;/h3&gt;

&lt;p&gt;Teraz mamy już poprawnie powiązane nasze pliki. Spróbujmy zatem stworzyć jakieś wspólne zadanie np. dźwięk i tekst na ekranie po kompilacji. Zacznijmy od utworzenia następującego zadania w pliku Common.Targets.&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;...&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt; &lt;span class="attr"&gt;Name&lt;/span&gt;&lt;span class="kwrd"&gt;="SayHi"&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Message&lt;/span&gt; &lt;span class="attr"&gt;Text&lt;/span&gt;&lt;span class="kwrd"&gt;="Project $(ProjectName) says 'HI' to everyone."&lt;/span&gt; &lt;span class="attr"&gt;Importance&lt;/span&gt;&lt;span class="kwrd"&gt;="High"&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;Beep&lt;/span&gt;&lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;Target&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Teraz należy doprowadzić do wywołania zadania przed kompilacją każdego z projektów. Za kompilacje projektów C# odpowiada "$(MSBuildToolsPath)\Microsoft.CSharp.targets" i tam można znaleźć odpowiedź w jaki sposób oraz w jakiej kolejności są wykonywane czynności podczas budowy projektu. Dzięki temu możemy bardzo łatwo wcisnąć nasze zadanie pomiędzy zadaniami kompilacji ...&lt;/p&gt;

&lt;div class="csharpcode-wrapper"&gt;
  &lt;div class="csharpcode"&gt;
    &lt;pre class="alt"&gt;...&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="rem"&gt;&amp;lt;!-- Add additional depends to Build target --&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;&lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;    &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;CoreCompileDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;        SayHi;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;        $(CoreCompileDependsOn)&lt;/pre&gt;

    &lt;pre class="alt"&gt;    &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;CoreCompileDependsOn&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alteven"&gt;&lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;PropertyGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;&lt;/pre&gt;

    &lt;pre class="alt"&gt;...&lt;/pre&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Oczywiście wpis ten dokonujemy w pliku Common.Targets. Dla tych, którym nie chce się przeglądać pliku "Microsoft.CSharp.targets" polecam stronę &lt;a href="http://blogs.msdn.com/msbuild/archive/2006/02/10/528822.aspx"&gt;How To: Add Custom Process at Specific Points During Build (Method #2)&lt;/a&gt;. Teraz&amp;nbsp; kompilując nasz projekt z lini poleceń powinniśmy doświadczyć czegoś takiego ...&lt;/p&gt;

&lt;div class="console-wrapper"&gt;
  &lt;pre class="console"&gt;C:\...\trunk&amp;gt; msbuild Default.proj
...
  Finished processing 0 edmx files
SayHi:
  Project MyProject says 'HI' to everyone.
CopyFilesToOutputDirectory:
  Copying file from "obj\Debug\MyProject.dll" to "bin\Debug\MyProject.dll".
...

  Finished processing 0 edmx files
SayHi:
  Project MyProject.Tests says 'HI' to everyone.
CopyFilesToOutputDirectory:
  Copying file from "obj\Debug\MyProject.Tests.dll" to "bin\Debug\MyProject.Tests.dll".
...&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;... oraz usłyszeć dwa razy "beep". Nawet jak zrobimy Build&amp;nbsp; z Visual Studio wówczas również usłyszymy "beep". :)&lt;/p&gt;&lt;p&gt;&lt;b&gt;Updated: &lt;/b&gt;Okazuje się że teraz "beep" nawet usłyszymy kiedy będziemy chcieli dodać nową&amp;nbsp; lub usunąć istniejącą referencje do projektu :). Polecam przetestować. &lt;br&gt;&lt;/p&gt;

&lt;p&gt;Pełny projekt do tej części dostępny jest przez Svn-a -&amp;gt; &lt;a href="http://rodsamples.googlecode.com/svn/MSBuildTutorial/tags/part003"&gt;Part003&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Można powiedzieć, że tekst dzisiejszy zamyka w sumie częśc wprowadzającą. Od następnego odcinka zajmiemy się bardziej przydatnymi rzeczami w codzinnej pracy programisty. Wiec mam nadzieje że zaawansowani czytelnicy również znajdą pożyteczne dla nich informacje :). Zapraszam niebawem ...&lt;/p&gt;&lt;img src="http://zine.net.pl/aggbug.aspx?PostID=1512" width="1" height="1"&gt;</description><category domain="http://zine.net.pl/blogs/rod/archive/tags/Narz_1901_dzia/default.aspx">Narzędzia</category><category domain="http://zine.net.pl/blogs/rod/archive/tags/MSBuild/default.aspx">MSBuild</category><feedburner:origLink>http://zine.net.pl/blogs/rod/archive/2008/07/15/organizacja-projektu-i-automatyzacja-z-wykorzystaniem-msbuild-a-3-podstawy.aspx</feedburner:origLink></item></channel></rss>
