Rock Solid Knowledge Blogs" 07/01/2013 17:11:00 http://www.rocksolidknowledge.com An aggregation of all the Rock Solid Knowledge Blogs tag:blogger.com,1999:blog-30604582.post-889172719437463006 http://andyclymer.blogspot.com/2013/01/windows-8-keyboard-short-cuts.html Windows 8 keyboard short cuts <p>New year, new OS.&#160; I made the jump to Windows 8 over the xmas period.&#160; Still getting used to it, spend most of my time in desktop mode, like the fact that the task bar is extended across multiple monitors.&#160; Being a keyboard junkie I found the following list of keyboard shortcuts really useful.&#160; New years resolution is to practice them…</p> <p>Win : switch between the Start screen and the last-running Windows 8 app <br />Win + C : displays the Charms: the Settings, Devices, Share and Search options <br />Win + D : launches the desktop <br />Win + E : launches Explorer <br />Win + F : opens the File Search pane <br />Win + H : opens the Share pane <br />Win + I : opens Settings <br />Win + K : opens the Devices pane <br />Win + L : locks your PC <br />Win + M : minimises the current Explorer or Internet Explorer window (works in the full-screen IE, too) <br />Win + O : toggles device orientation lock on and off <br />Win + P : switch your display to a second display or projector <br />Win + Q : open the App Search pane <br />Win + R : opens the Run box <br />Win + U : open the Ease of Access Centre <br />Win + V : cycle through toasts (notifications) <br />Win + W : search your system settings (type POWER for links to all power-related options, say) <br />Win + X : displays a text menu of useful Windows tools and applets <br />Win + Z : displays the right-click context menu when in a full-screen app <br />Win + + : launch Magnifier and zoom in <br />Win + - : zoom out <br />Win + , : Aero peek at the desktop <br />Win + Enter : launch Narrator <br />Win + PgUp : move the current screen to the left-hand monitor <br />Win + PgDn : move the current screen to the right-hand monitor <br />Win + PrtSc : capture the current screen and save it to your Pictures folder <br />Win + Tab : switch between running apps</p> tag:blogger.com,1999:blog-30604582.post-4158781599638484364 http://andyclymer.blogspot.com/2012/11/devweek-2013.html DevWeek 2013 <p>Schedule for <a href="http://www.devweek.com/" target="_blank">DevWeek 2013</a> is now out RSK will be presenting a range of materials from distributed systems, C# 5 threading , debugging, HTML 5 , and some of the future stuff such as Roslyn.&#160; Dr Rockman will be present in the exhibition area to answer any of your technical questions.</p> <p>&#160;</p> <p>Look forward to seeing you there</p> <p>&#160;</p> <p><img src="https://encrypted-tbn1.gstatic.com/images?q=tbn:ANd9GcQrWjVbWI4ZZiovK8xvEsQbeGr0Ig7A09sMEhFCaCGY-pehBBWp0A" width="93" height="157" /></p> tag:blogger.com,1999:blog-30604582.post-465577640106546266 http://andyclymer.blogspot.com/2012/08/first-install-of-cisco-based-cat.html First install of Cisco based CAT <p>The furniture is currently being installed for our first Cisco Video Advantage based <a href="http://www.face2faceassist.com/" target="_blank">CAT</a> solution for Harrow Council.&#160; Rich and myself will be installing the software on Tuesday.&#160; </p> <p>&#160;</p> <p><a href="http://lh5.ggpht.com/-_OfmpRC7-nc/UCT785hJbZI/AAAAAAAACUY/dbTxQtL72rg/s1600-h/photo%25255B4%25255D.jpg"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="photo" border="0" alt="photo" src="http://lh4.ggpht.com/-AL2trAgN94M/UCT79zHIMWI/AAAAAAAACUg/vCEYHpINpEk/photo_thumb%25255B1%25255D.jpg?imgmax=800" width="333" height="249" /></a></p> <p>Harrow are currently rolling this out to three libraries initially, allowing residents to access housing services from a convenient local location.</p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,50861acd-6bd1-4283-9fdc-7a611a440829.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,50861acd-6bd1-4283-9fdc-7a611a440829.aspx Certificate Validation and Setting up Service Bus 1.0 Beta for Windows Server <p> Microsoft recently announced the beta of Service Bus 1.0 for Windows Server. This is the on-premise version of the Azure Service Bus that so many have been asking for. There is a good walkthrough of the new beta in the MSDN documentation <a href="http://msdn.microsoft.com/library/jj193022(Azure.10).aspx">here</a> including how to install it. </p> <p> So why this blog post? Well if you install the beta on a Windows Server 2008 R2 box and you actually develop on another machine then there’s a couple of things not mentioned in the documentation that you need to do (having previously spent long hour glaring at certificate errors allowed me to resolve things pretty quickly) </p> <p> First a little background into why there is an issue. Certificate validation has a number of steps to it for a certificate to be considered valid: </p> <ol> <li> The issuer of the cert must be trusted. In fact the issuer of the issuer must also be trusted. In fact the issuer of the issuer of the issuer must be trusted. In fact … well you get the picture. In other words, when a certificate is validated all certificates in the chain of issuers must be trusted back to a trusted root CA (normally bodies like Verisign or your corporate certificate server). You will find these in your certificate store in the “Trusted Root Certificate Authorities” section. This mechanism is known as <strong>chain trust</strong>.</li> <li> The certificate must be in date (between the valid from and valid to dates)</li> <li> The usage of the certificate must be correct for the supported purposes of the cert (server authentication, client authentication, code signing, etc)</li> <li> For a server authentication cert (often known as an SSL cert) the subject of the cert must be the same as the server DNS name</li> <li> The certificate must not be revoked (if a cert is compromised the issuer can revoke the cert and publishes this in a revocation list) according to the issuers revocation list</li> </ol> <p> For 1. there is an alternative called <strong>Peer Trust</strong> where the presented certificate must be in the clients Trusted People section of their certificate store </p> <p> There may be other forms of validation but these are the ones that typically fail </p> <p> So the issue is that the installer of Service Bus (SB), if you just run through the default install, generates a Certificate Authority cert and puts it into the target machine’s Trusted CA store – it obviously doesn’t put it in the client’s Trusted CA store because it knows nothing about that. It also generates a server authentication cert with the machine name you are installing on. This causes two issues: no cert issued by the CA will be trusted and so an SSL failure will happen the first time you try to talk to SB, the generated SSL cert will have problems generally validating due to, for example, no revocation list </p> <p> The first of these issues can be fixed by exporting the generated CA cert and importing it into the Trusted CA Store ion the dev machine </p> <p> <a href="http://www.dotnetconsult.co.uk/weblog2/content/binary/Windows-Live-Writer/Setting-up-Ser.0-Beta-for-Windows-Server_D6B6/CA_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="CA" border="0" alt="CA" src="http://www.dotnetconsult.co.uk/weblog2/content/binary/Windows-Live-Writer/Setting-up-Ser.0-Beta-for-Windows-Server_D6B6/CA_thumb.png" width="573" height="89"></a> </p> <p> The second can be fixed by exporting the SSL cert and importing it into the trusted people store on the dev machine </p> <p> <a href="http://www.dotnetconsult.co.uk/weblog2/content/binary/Windows-Live-Writer/Setting-up-Ser.0-Beta-for-Windows-Server_D6B6/SSL_2.png"><img style="background-image: none; border-bottom: 0px; border-left: 0px; padding-left: 0px; padding-right: 0px; display: inline; border-top: 0px; border-right: 0px; padding-top: 0px" title="SSL" border="0" alt="SSL" src="http://www.dotnetconsult.co.uk/weblog2/content/binary/Windows-Live-Writer/Setting-up-Ser.0-Beta-for-Windows-Server_D6B6/SSL_thumb.png" width="576" height="71"></a> </p> <p> With these in place the Getting Started / Brokered Messaging / QueuesOnPrem sample should work fine </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=50861acd-6bd1-4283-9fdc-7a611a440829" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,89baa03d-47ee-4c9e-8705-c04f2df5518d.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,89baa03d-47ee-4c9e-8705-c04f2df5518d.aspx Demos from TechEd EMEA <p> The demos from DEV 326 – my talk on WCF 4.5 at TechEd EMEA are available <a href="http://rocksolidknowledge.blob.core.windows.net/demos/DEV326%20-%20Demos.zip">here</a>. The session was also recorded and the video is now on Channel9 <a href="http://channel9.msdn.com/Events/TechEd/Europe/2012/DEV326">here</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=89baa03d-47ee-4c9e-8705-c04f2df5518d" /> tag:blogger.com,1999:blog-30604582.post-2931246832058060928 http://andyclymer.blogspot.com/2012/04/how-much-packaging.html How much packaging <p>Richard and myself receive a batch of Microsoft Windows Embedded licence keys.&#160; Having only ordered four we were a bit amused by the size of the box they came in .</p> <p><a href="http://www.youtube.com/watch?v=M47ZbefpQbY&amp;feature=plcp">http://www.youtube.com/watch?v=M47ZbefpQbY&amp;feature=plcp</a></p> tag:blogger.com,1999:blog-30604582.post-1990127888255869408 http://andyclymer.blogspot.com/2012/04/pet-usb-keys.html Pet USB Keys A friend of mine has designed some dog USB keys. I'm sure they will be a hit with dog lovers and kids alike<br /><br />You can buy them online<br /><br />http://www.petstar-tech.com/<br />"Designed in Farnham assembled in China"<br /> tag:blogger.com,1999:blog-30604582.post-3352712449694687183 http://andyclymer.blogspot.com/2012/04/double-check-locking.html Double check locking <p>At my recent Async talk at DevWeek I built an Asynchronous queue that enables the consumers to take advantage of async and await keywords available in C# 5.&#160; You can download the code <a href="http://rocksolidknowledge.blob.core.windows.net/demos/DevWeek2012/Async.zip" target="_blank">here</a>, the final step in that implementation was to make use of double check locking.&#160; A delegate came up to me afterwards and said my code wasn’t thread safe, in that I could end up with a partially completed object.&#160; This was due to the fact that the CPU can re-order write operations to optimise memory bus, and that is true of some processors.&#160; In that the reference to the object could be flushed out to main memory before the data associated with the object constructor.&#160; This certainly was the case in .NET 1.1 with certain chip sets not true for your classic x86 and x64 but the Itanium I-A64 family of processor.&#160; The work around was to make the pointer to the constructed object volatile forcing the compiler to place the appropriate memory barrier instructions.</p> <p>However in .NET 2.0 the CLR team enforced a more strong memory model since they didn’t like the idea of managed code behaving so differently on the final target hardware.&#160; Here is a <a href="http://msdn.microsoft.com/en-gb/magazine/cc163715.aspx#S11" target="_blank">link</a> to the write up from MSDN mag by Vance Morrison the compiler architect of the .NET runtime explaining why you don’t need to use volatile from .NET 2.0 onwards.</p> tag:blogger.com,1999:blog-30604582.post-2888415008430107091 http://andyclymer.blogspot.com/2012/04/devweek-2012-demos.html DevWeek 2012 Demos <p>Just to say my demos from DevWeek 2012 are now available for download <a href="http://www.rocksolidknowledge.com/Conferences.mvc" target="_blank">here</a></p> tag:blogger.com,1999:blog-30604582.post-8052980758977531005 http://andyclymer.blogspot.com/2012/04/devweek-2012.html Devweek 2012 Had a great conference as ever. Thanks to everyone who attended the RSK talks. I literally left the conference and went on holiday. Will be back tomorrow so will upload the demos to the website on Tuesday 3rd<br /><br />If you want a refresher on the asynchronous talk we have screencasts on the site that cover some of the aspects<br /><br /> tag:blogger.com,1999:blog-30604582.post-211249091280365412 http://andyclymer.blogspot.com/2012/03/days-of-events.html Days of events <p>In addition to my responsibilities at RSK I also teach for <a href="www.develop.com/uk" target="_blank">developmentor</a>, and this summer we are trying something new.&#160; We are running days of events, so you don’t have to give up a whole week from the office to attend a training course during August we are running a day of .NET threading featuring C# 5 and Visual Studio 11.&#160; So at the end of the day you will be up to speed on threading for .NET 4 and have a good insight to how things will be different in C#5 when it ships.</p> <p>In addition to the days of threading we are running a day of design patterns, so if you still find yourself using the same techniques to solve problems, feel your OO skills are getting rusty then come along for a day, and immerse yourself in OO and design patterns.</p> <p>For more details <a href="https://na1.salesforce.com/sfc/p/30000000oK33kY76Nrm96Tf5K1BY8QLbj7BTR8w=" target="_blank">click here</a></p> tag:blogger.com,1999:blog-30604582.post-6327888151614719996 http://andyclymer.blogspot.com/2012/03/asyncawait-mechanics.html Async/await mechanics <p>Just completed two <a href="http://www.rocksolidknowledge.com/screencasts" target="_blank">screen casts</a> describing the mechanics of how async and await work using Visual Studio 11 Beta, along with how you can create your own types to await on rather than always using tasks.</p> tag:blogger.com,1999:blog-30604582.post-8619815669824256673 http://andyclymer.blogspot.com/2012/01/developmentor-has-moved.html Developmentor has moved <p><b>In addition to working hard at RSK myself and Richard are also instructors for Developmtor.&#160; Both of us author and teach a range of courses for them.&#160; This year has seen Developmentor move from Hammersmith to central London, for all of you who are based in and around London they are offering an evening of tech and nibbles to show case the new location.&#160; Details below, hopefully see some of you there. </b></p> <p><b>Come and see us! On Monday 6th February 2012, 5-7pm </b>to cement the move to our new London City location in Moorgate, we invite you to our house warming, entertainment provided by <a href="http://www.develop.com/technicalstaff#Richard Blewett">Richard Blewett</a> and <a href="http://www.develop.com/technicalstaff#Andrew Clymer">Andy Clymer</a>who will be revealing the magic behind the new and exciting C#5 Async and AWait keywords. To register your interest for this free event, please email us <a href="mailto:salesuk@develop.com">salesuk@develop.com </a>or call 01242 525108 .</p> tag:blogger.com,1999:blog-30604582.post-4677896670895261384 http://andyclymer.blogspot.com/2012/01/code-smarter-with-design-patterns.html Code smarter with Design Patterns <p>Just finished updating the Code Smarter with Design Patterns for <a href="http://www.develop.com">Developmentor</a>.&#160; </p> <p>The course traditionally has focused on GoF design patterns, in this release I have added MVC and Repository pattern, to round off the offering.</p> <p>Both these patterns build upon the GoF patterns discussed earlier in the course, and show how the basic GoF patterns are often compounded to produce elegant solutions.</p> <p>Other enhancements include addition of Prototype and Builder patterns, and a general upgrade to the latest features offered by the .NET framework.</p> <p> <br />To learn more click <a href="http://www.develop.com/training-course/net-design-patterns">here</a></p> tag:blogger.com,1999:blog-30604582.post-6712137806207404786 http://andyclymer.blogspot.com/2011/11/devweek-2012.html Devweek 2012 <p>RSK guys will be speaking at <a href="http://www.devweek.com/">DevWeek</a> this year, and as usual we will be talking about a large range of cutting edge topics, including</p> <p>Our fluffy cuddly colouring in guy Dave Wheeler will be doing a huge number of sessions on Windows 8 Metro including the Keynote to get you all fired up, but don’t think they will be all soft, one session includes a COM primer for all those youngsters who didn’t take their COM apprentiship.</p> <p>Rich will be covering topics from Whats New in WCF 4.5, and the ever cool Reactive Framework, and a deep dive into the GC, something all developers should have intimate knowledge of.</p> <p>Andy will be covering the new async functionality of C#5, highlighting how you now write both ui and server side code to consume and enable the use of these new wonderful keywords, and doing a whole day of threading as a pre con on Monday</p> <p>Kevin will be presenting a day of building MVC applications, along with a session on unit testing.&#160; </p> <p>During the breaks Dr Rock Man will also be there to try and solve your specific technical problems or just happy to hear you rant about the code base you have just inherited. </p> <p>In total we will be presenting a total 19 sessions, plus pre and post conference sessions.&#160; Hopefully see you <a href="http://www.devweek.com/">there</a> with what should be a fun pact week..</p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a5b8a66a-b880-46eb-b656-e33ce7d78c9b.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a5b8a66a-b880-46eb-b656-e33ce7d78c9b.aspx Demos from Basta 2011 <p> Thanks to everyone for attending my sessions on the Reactive Framework and Garbage Collection at <a href="http://basta.net/">Basta 2011</a>, you can download the demos here: </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/Basta2011Rx.zip">Reactive Framework</a> </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/Basta2011GC.zip">Garbage Collection</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=a5b8a66a-b880-46eb-b656-e33ce7d78c9b" /> tag:blogger.com,1999:blog-30604582.post-8177027063012623816 http://andyclymer.blogspot.com/2011/08/customer-access-terminal-v2.html Customer Access Terminal V2 <p>Rich and myself are just about to install the next version of our Customer Access Terminal solution at one of our existing customers.&#160; So it seems a convenient time to mention we now have a web site that provides a detailed overview of all the features in V2.</p> <p><a href="http://www.face2faceAssist.com">Face 2 Face Asssit</a></p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,d69307a4-76c2-4a38-b317-1c15fb189acc.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,d69307a4-76c2-4a38-b317-1c15fb189acc.aspx Self Hosted Web API / Nuget Gotcha <p> Just a heads up that when self hosting the new WCF Web API. By default if you try to add the Web API references via Nuget you will get a failure (E_FAIL returned from a COM component). </p> <p> This is due to the likely project types (Console, Windows Service, WPF) defaulting to the client profile rather than the full framework. If you change the project to the full framework the Nuget packages install correctly </p> <p> Yet again bitten by the Client Profile </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=d69307a4-76c2-4a38-b317-1c15fb189acc" /> tag:blogger.com,1999:blog-30604582.post-1939546588617569200 http://andyclymer.blogspot.com/2011/03/cat-terminal-on-film.html CAT Terminal on film <p>The council that recently purchased our CAT kiosk made a short movie for their local tv station, if you are interested in seeing the CAT in action</p> <p><a href="http://www.cheshirewest.tv/categories/my-services/film/newsdesk-march-2011/">Click here</a></p> <p>The CAT piece is 1 minute 29 seconds into the movie.</p> tag:blogger.com,1999:blog-30604582.post-1282591364438059092 http://andyclymer.blogspot.com/2011/03/cat-terminal.html CAT Terminal <p>Following up from my recent post on our CAT kiosk deployment.</p> <p><a href="http://www.chesterfirst.co.uk/news/100188/new-videolink-for-tarporley-library.aspx" target="_blank">Here is a link to the councils own article</a></p> tag:blogger.com,1999:blog-30604582.post-5647507558645289713 http://andyclymer.blogspot.com/2011/03/customer-access-terminal-cat.html Customer Access Terminal (CAT) <p>Yesterday was a big day for Rich and myself we successfully deployed our CAT software to our first customer in conjunction with our video conferencing partner First Connections.&#160; The software allows members of the public to interact with their local council almost as if they are with them in person.&#160; Allowing members of the public to access services from rural locations.</p> <p>The kiosk utilises two screens, one being a touch screen.&#160; The touch screen is used to visit specific council web sites, or to start a video call with a member from one of the council help desk team.&#160; Once in a video call the council representative can help complete specific council forms including taking passport style photos with the built in HD camera and customers signatures using a high resolution LCD signature pad.</p> <p>All built using .NET 4 and Windows Embedded.</p> <p><a href="http://lh6.ggpht.com/_OxnULoaN7CE/TXt-LqvQv3I/AAAAAAAAA1c/LETbvdPCvU4/s1600-h/IMG_1322%5B2%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IMG_1322" border="0" alt="IMG_1322" src="http://lh6.ggpht.com/_OxnULoaN7CE/TXt-L1EDOoI/AAAAAAAAA1g/fwPP_0pp-7M/IMG_1322_thumb.jpg?imgmax=800" width="244" height="183" /></a> </p> <p><a href="http://lh3.ggpht.com/_OxnULoaN7CE/TXt-MwWI9vI/AAAAAAAAA1k/FaVCvGoP274/s1600-h/IMG_1327%5B2%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IMG_1327" border="0" alt="IMG_1327" src="http://lh3.ggpht.com/_OxnULoaN7CE/TXt-NUUKQJI/AAAAAAAAA1o/mfvOCtMSrHs/IMG_1327_thumb.jpg?imgmax=800" width="244" height="183" /></a> <a href="http://lh6.ggpht.com/_OxnULoaN7CE/TXt-NsVs4oI/AAAAAAAAA1s/eYq8sZgQcoo/s1600-h/IMG_1325%5B2%5D.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IMG_1325" border="0" alt="IMG_1325" src="http://lh4.ggpht.com/_OxnULoaN7CE/TXt-OH8UciI/AAAAAAAAA1w/HbwFWpIqZTY/IMG_1325_thumb.jpg?imgmax=800" width="244" height="183" /></a></p> tag:blogger.com,1999:blog-30604582.post-8917742020928807291 http://andyclymer.blogspot.com/2011/03/concurrent-data-structures-screen-cast.html Concurrent Data Structures screen cast <p>Must be screen cast Thursday, another screen cast posted to RSK on Concurrent Data Structures in .NET 4</p> <p><a href="http://www.rocksolidknowledge.com/screencasts" target="_blank">RSK screen casts</a></p> tag:blogger.com,1999:blog-30604582.post-501220225366007920 http://andyclymer.blogspot.com/2011/03/async-and-await-screencast.html async and await screencast <p>Just uploaded a new screencast on async and await keywords due to be introduced in C# 5.</p> <p><a href="http://www.rocksolidknowledge.com/screencasts.mvc" target="_blank">Rock Solid Knowledge Screencasts</a></p> tag:blogger.com,1999:blog-30604582.post-8253427283517620314 http://andyclymer.blogspot.com/2011/02/tpl-dataflow.html TPL Dataflow <p>One parallel pattern that required some work with base .NET 4 was parallel pipe lines.&#160; The CTP release of the Parallel Dataflow extensions, makes this trivial now.&#160; I’m intending to do a screencast really soon to show this action, but in the mean time try it out for yourself you can <a href="http://msdn.microsoft.com/en-us/devlabs/gg585582">download it from here</a></p> tag:blogger.com,1999:blog-30604582.post-8816041966901303271 http://andyclymer.blogspot.com/2011/02/coding-challengean-alternative-to.html Coding Challenge,an alternative to regular class room training <h3>&#160;</h3> <p>What do most engineers want to do, “Build Things”. Regular training classes are good at introducing new technology, but what if you want to take it further; to stretch and motivate your senior developers. This was the requirement that our major investment bank client presented to Rock Solid Knowledge the co-developed solution was to produce a Coding Challenge…</p> <h4>The Training Day One</h4> <p>The first day was spent with a deep dive into Silverlight; all teams had prior knowledge of WPF. The focus of the day was to effectively demonstrate the differences and similarities of the two technologies, giving the teams the ability to deliver a high quality Silverlight solution to match the code challenge requirements document.</p> <h4>The Challenge Day Two</h4> <p>The three person teams, of senior developers, spent the next 24 hours straight building a working product to the supplied specification. Not only did this test their ability to apply the new technology but demonstrated who ships and who doesn’t. Failing to organise is clearly highlighted when you only have a short period of time to deliver.</p> <h4>The Assessment Day Three</h4> <p>After working nearly flat out for 24 hours the teams submitted their solutions to be assessed by Rock Solid Knowledge. Initial marks were given, with each team then given a technical grilling on their solution to provide feedback on what was good and bad.</p> <h4>The Winner</h4> <p>The winning team all received iPads, a satisfactory reward for all their hard efforts and our client introduced a new technology in a vibrant and compelling way.</p> <p>If this has wetted your appetite a more detailed write up can be downloaded from <a href="http://rocksolidknowledge.blob.core.windows.net/downloads/Full+Coding+Challenge.pdf">here</a> or if you would just simply like to know how we could bring this experience to your company contact us by clicking <a href="http://www.rocksolidknowledge.com/ContactUs.mvc/">here</a></p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,1efac821-2b89-47bb-9d27-48f0d6347914.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,1efac821-2b89-47bb-9d27-48f0d6347914.aspx WCF Instances and Threading <p> I have just found myself answering essentially the same question 4 times on the MSDN WCF Forum about how instances, threading and throttling interact in WCF. So to save myself some typing I will walk through the relationships here and then I can reference this post in questions. </p> <p> <strong>Instancing<br> </strong>WCF has 3 built in instancing models: PerCall, PerSession and Single. They are set on the InstanceContextMode on the ServiceBehavior attribute on the service implementation. They relate to how many instances of the service implementation class get used when requests come in, and work as follows: </p> <ul> <li> Single – one instance of the implementation class is used for all requests <li> PerCall – every request gets its own instance of the implementation class <li> PerSession – this is the slightly odd one as it means every session gets its own instance. In practical terms it means that for <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,af6e6325-2e30-42e3-acb9-57e1363fa51e.aspx">Session</a> supporting bindings: NetTcpBinding, WSHttpBinding, NetNamedPipeBinding, etc, every proxy gets an instance of the service. For bindings that do not support session: BasicHttpBinding, WebHttpBinding, we get the same effect as PerCall. To add to the confusion, this setting is the default</li> </ul> <p> <strong>Concurrency<br> </strong>By default WCF assumes you do not understand multithreading. Therefore, it only allows one thread at a time into an instance of the service implementation class unless you tell it otherwise. You can control this behavior using the ConcurrencyMode on the ServiceBehavior; it has 3 values: </p> <ul> <li> Single – this is the default and only one thread can get into an instance at a time <li> Multiple – any thread can enter an instance at any time <li> Reentrant – only makes a difference in <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b891610a-6b78-4b54-b9a6-4ec81c82b7c0.aspx">duplex</a> services but means that an inbound request can be received from the component you are currently making a request to (sounds a bit vague but in duplex the role of service and client are somewhat arbitrary)</li> </ul> <p> <strong>Interaction<br> </strong>Now these two concepts are different but have some level of interaction. </p> <p> If you set InstanceContextMode to Single and ConcurrencyMode to Single then your service will process exactly one request at a time. If you set InstanceContextMode to Single and ConcurrencyMode to Multiple then your service processes many requests but you are responsible for ensuring your code is threadsafe. </p> <p> If you set InstanceContextMode to PerCall then ConcurrencyMode Single and Multiple behave the same as each request gets its own instance </p> <p> For PerSession ConcurrencyMode Multiple is only required if you want to support a client sending multiple requests through the same proxy from multiple threads concurrently </p> <p> <strong>Threading<br> </strong>Unless you turn on ASP.NET Compatibility, WCF calls are processed on IO threads in the system threadpool. There is no thread affinity so any of these threads could process a request. The number of threads being used will grow until the throughput of the service matches the number of concurrent requests (assuming the server machine has the resources to match the number of concurrent requests). Although the number of IO threads is capped at 1000 by default, if you hit this many then unless you are running on some big iron hardware you probably have problems in your architecture. </p> <p> <strong>Throttling<br> </strong>Throttling is there to ensure your service is not swamped in terms of resources. There are three throttles in place: </p> <ul> <li> MaxConcurrentCalls – the number of concurrent calls that can be made – under .NET 4 defaults to 16 x number of cores <li> MaxConcurrentSessions – the number of concurrent sessions that can be in in flight – under .NET 4 defaults to 100 x number of cores <li> MaxConcurrentObjects – the number of service implementation objects that are in use – defaults to the sum of MaxConcurrentCalls + MaxConcurrentSessions</li> </ul> <p> In reality, depending on whether you are using sessions or not, the session or call throttle will affect your service the most. The object one will only affect your service if you set it lower than the others or you do something unsual and handle the mapping of requests to objects yourself using a custom IInstanceContextProvider </p> <p> You can control the throttle values using the serviceThrottling service behavior which you set in the config file or in code </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=1efac821-2b89-47bb-9d27-48f0d6347914" /> tag:blogger.com,1999:blog-30604582.post-744306029416948424 http://andyclymer.blogspot.com/2011/02/no-more-free-reflector.html No more free Reflector <p>Red Gate have announced that from the next release in March no more free versions of Reflector.</p> <p><a href="http://www.red-gate.com/products/dotnet-development/reflector/announcement">http://www.red-gate.com/products/dotnet-development/reflector/announcement</a></p> tag:blogger.com,1999:blog-30604582.post-5977291092075806086 http://andyclymer.blogspot.com/2011/01/devweek-2011.html Devweek 2011 <p>Just in case you are not aware <a href="http://www.devweek.com" target="_blank">Dev Week 2011</a> is fast approaching, this is without doubt the best independent .NET technical&#160; conference in the UK.&#160; I’m delighted to say that Rock Solid Knowledge will be attending again this year delivering a variety of sessions from Parallel programming to Workflow to fluffy UI.&#160; A full list of our sessions can be found <a href="http://www.rocksolidknowledge.com/conferences.mvc" target="_blank">here</a></p> <p><img alt="image" src="http://lh6.ggpht.com/_OxnULoaN7CE/S2qq5oV1XfI/AAAAAAAAAqY/9m97LN_2DU0/image_thumb.png?imgmax=800" /></p> <p>In addition to the traditional lecture sessions we will be running our drop in clinic where our consultants will help you solve your design and development issues.&#160; The whole team will be there so whether its WPF, Silverlight, .NET 4.0, WCF , Design Patterns, Multithreading, Web Development or anything else, we’ll be on hand to lend a sympathetic ear and hopefully solve your problems. </p> http://blogs.mantiso.com/blog/kevin/2010/06/26/formelement-is-null-in-ASP-Net-MVC-Validation http://blogs.mantiso.com/blog/kevin/2010/06/26/formelement-is-null-in-ASP-Net-MVC-Validation formelement is null in ASP.Net MVC Validation I'm buidling a really simple MVC application as a demo and I've been getting a Javascript "formelement is null" error. A quick google throws up a bunch of 'make sure you add the correct .js files" but I had all those <pre class="brush: html"> <script src="../../Scripts/MicrosoftAjax.debug.js" type="text/javascript"></script> <script src="../../Scripts/MicrosoftMvcAjax.debug.js" type="text/javascript"></script> <script src="../../Scripts/MicrosoftMvcValidation.debug.js" type="text/javascript"></script> </pre> Turns out that I had added a Master page using a template and thet template contains a <pre class="brush: html"> <form runat="server"> </pre> element. This screwa up the validation. Removing that tag fixes the problem http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0cf7f2c1-78f5-43d6-820d-849d5cd5fee0.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0cf7f2c1-78f5-43d6-820d-849d5cd5fee0.aspx Software Architect Conference 2010 <p> <a href="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/SoftwareArchitectConference2010_98EF/Speaker_SA2010_120x120_4.jpg"><img style="border-right-width: 0px; margin: 0px 15px 0px 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="Speaker_SA2010_120x120" border="0" alt="Speaker_SA2010_120x120" align="left" src="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/SoftwareArchitectConference2010_98EF/Speaker_SA2010_120x120_thumb_1.jpg" width="124" height="124"></a> </p> <p> I’m speaking at Software Architect 2010 in October. I’m going to be delivering two sessions on Windows Workflow Foundation 4.0: the first explains the basic architecture and looks at using workflow as a Visual Scripting environment to empower business users. The second looks at building big systems with workflow concentrating on the WCF integration features. </p> <p> In addition to that I’ll be delivering two all-day workshops with <a href="http://andyclymer.blogspot.com/">Andy Clymer</a>: Building Applications the .NET 4.0 Way and Moving to the Parallel Mindset with .NET 4.0. The first of these will take a number of new features of .NET 4.0 and show how they can be combined to create compelling applications. The second will look at the Parallel Framework Extensions (PFx) introduced in .NET 4.0 examining both the rich functionality of the library, how it can be best leveraged avoiding common parallel pitfalls and finally looking at patterns that aid parallelisation of your code </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=0cf7f2c1-78f5-43d6-820d-849d5cd5fee0" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,adb974bc-7595-4e06-827b-12f7c09208ae.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,adb974bc-7595-4e06-827b-12f7c09208ae.aspx Unity, Multiple Constructors and Configuration <p> I’ve been working with the <a href="http://unity.codeplex.com/wikipage?title=Unity2">Unity IoC container</a> from Microsoft Patterns and Practices recently. Its mostly straightforward as IoC containers go but one thing had me puzzled for a while as its not really documented or blogged as far as I can see; so I decided to blog it so hopefully others looking will stumble across this article </p> <p> Lets start off with a simple example: I have two interfaces: <font face="Consolas">IService</font> and <font face="Consolas">IRepository</font> that live in the Interfaces class library </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IService</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">void</span> DoWork();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> }</pre> <!--CRLF--> </div> </div> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">interface</span> IRepository</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">string</span> GetStuff();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> }</pre> <!--CRLF--> </div> </div> I also have two implementations in the Services class library: <font face="Consolas">MyRepository</font>&nbsp; <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MyRepository : IRepository</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">string</span> GetStuff()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">return</span> <span style="color: #006080">"TADA!!"</span>;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> }</pre> <!--CRLF--> </div> </div> <p> </p> <p> </p> <p> </p> <p> and <font face="Consolas">MyService</font> </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MyService : IService</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">private</span> IRepository repository;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> MyService(IRepository repository)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #0000ff">this</span>.repository = repository;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> DoWork()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> Console.WriteLine(repository.GetStuff());</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> }</pre> <!--CRLF--> </div> </div> <p> </p> <p> Notice that <font face="Consolas">MyService</font> needs an <font face="Consolas">IRepository</font> to do its work. Now the idea here is I’m going to wire this together via dependency injection and the Unity IoC container. So I have my application </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">class</span> Program</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> UnityContainer container = <span style="color: #0000ff">new</span> UnityContainer();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection(<span style="color: #006080">"unity"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> section.Configure(container);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> IService svc = container.Resolve&lt;IService&gt;();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> svc.DoWork();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> }</pre> <!--CRLF--> </div> </div> <p> </p> <p> Notice as we’re using IoC that there are no hard coded dependencies – everything is wired up via the container. However, there must be some information about how the interfaces map to concrete types and this is in the config file </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">configuration</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">configSections</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">section</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="unity"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">configSections</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">unity</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAliases</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #008000">&lt;!-- Lifetime Managers --&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="singleton"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Microsoft.Practices.Unity.ContainerControlledLifetimeManager"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> <span style="color: #008000">&lt;!-- Interfaces --&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="IService"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Interfaces.IService,Interfaces"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="IRepository"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Interfaces.IRepository,Interfaces"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> <span style="color: #008000">&lt;!-- Implementations --&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="service"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Services.MyService, Services"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">typeAlias</span> <span style="color: #ff0000">alias</span><span style="color: #0000ff">="repository"</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="Services.MyRepository, Services"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">typeAliases</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">containers</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">container</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">types</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">type</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="IService"</span> <span style="color: #ff0000">mapTo</span><span style="color: #0000ff">="service"</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">lifetime</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="singleton"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">type</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">type</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="IRepository"</span> <span style="color: #ff0000">mapTo</span><span style="color: #0000ff">="repository"</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">lifetime</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="singleton"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">type</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">types</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">container</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">containers</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">unity</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">configuration</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> </div> </div> <p> </p> <p> Now all of this works fine and is simple Unity stuff. We use constructor injection to get the repository implementation into the service constructor. However, I’ve decided the service needs a timeout that I will generally configure in the config file. However to make Unit Testing simple I’ll add another constructor to <font face="Consolas">MyService</font> so I can pass a specific timeout </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> MyService : IService</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">private</span> IRepository repository;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> TimeSpan timeout;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #0000ff">public</span> MyService(IRepository repository, TimeSpan timeout)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">this</span>.timeout = timeout;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> <span style="color: #0000ff">public</span> MyService(IRepository repository)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> <span style="color: #0000ff">this</span>.repository = repository;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> timeout = GetTimeoutFromConfig();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> <span style="color: #0000ff">private</span> TimeSpan GetTimeoutFromConfig()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">default</span>(TimeSpan);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> DoWork()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> Console.WriteLine(repository.GetStuff());</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> }</pre> <!--CRLF--> </div> </div> <p> </p> <p> Now I try to run the application and I get a pretty ugly error </p> <font size="2" face="Consolas"><font size="2" face="Consolas"> <p> Unhandled Exception: Microsoft.Practices.Unity.ResolutionFailedException: Resolution of the dependency failed, <br> type = "Interfaces.IService", name = "(none)".<br> Exception occurred while: while resolving.<br> Exception is: InvalidOperationException - The type Int32 cannot be constructed.<br> You must configure the container to supply this value. </font></font>> <p> <font face="Consolas"><font face="Consolas"><font size="2" face="Trebuchet MS">Now that’s weird – I have no types that take an <font face="Consolas">Int32</font>! This is caused by Unity’s default behavior where it will try to resolve on the constructor with the most parameters (on the basis that this one will have the most dependencies that can be injected). It tried to resolve the <font face="Consolas">TimeSpan</font> and so looks at the <font face="Consolas">TimeSpan</font> and tries to resolve its constructor which can take an <font face="Consolas">Int32</font>. I actually want to tell it to use a different constructor and I can do this in two ways: annotate the constructor I want to use with the <font face="Consolas">[InjectionConstructor]</font> attribute</font></font></font> </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> [InjectionConstructor]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> MyService(IRepository repository)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">this</span>.repository = repository;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> timeout = GetTimeoutFromConfig();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> }</pre> <!--CRLF--> </div> </div> <font size="2" face="Consolas"><font size="2" face="Consolas"></font></font> <p> But personally I don’t like this. It forces the services assembly to take a dependency on Unity and the service has knowledge about how its being constructed. What I really want to do is specify this in config. This isn’t very well documented from what I can see but what you do it specify the constructor and how to resolve the parameters against the type mapping in the config – i.e. </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">type</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="IService"</span> <span style="color: #ff0000">mapTo</span><span style="color: #0000ff">="service"</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">lifetime</span> <span style="color: #ff0000">type</span><span style="color: #0000ff">="singleton"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">constructor</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">param</span> <span style="color: #ff0000">name</span><span style="color: #0000ff">="repository"</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">dependency</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">param</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">constructor</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">type</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> </div> </div> <p> </p> As well as specifying dependencies you can also give explicit values by using <font face="Consolas">&lt;value/&gt;</font> instead of <font face="Consolas">&lt;dependency/&gt;</font>. This model I think is a lot cleaner than the attribute approach.<img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=adb974bc-7595-4e06-827b-12f7c09208ae" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0542f45a-40cc-4b2c-9bc4-b4b2740b2af4.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0542f45a-40cc-4b2c-9bc4-b4b2740b2af4.aspx Windows AppFabric Hits the Streets <p> Announced today at TechEd – Windows AppFabric is now available </p> <p> <a href="http://blogs.msdn.com/b/endpoint/archive/2010/06/07/windows-server-appfabric-now-generally-available.aspx">http://blogs.msdn.com/b/endpoint/archive/2010/06/07/windows-server-appfabric-now-generally-available.aspx</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=0542f45a-40cc-4b2c-9bc4-b4b2740b2af4" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,c12e0817-7c4b-4d6b-abce-a2afeeb258ce.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,c12e0817-7c4b-4d6b-abce-a2afeeb258ce.aspx Visual Studio 2010 Power Tools <p> The <a href="http://visualstudiogallery.msdn.microsoft.com/en-us/d0d33361-18e2-46c0-8ff2-4adea1e34fef">Visual Studio 2010 Power Tools</a> have just been released. There’s all sorts of goodness in here: new flexible tab handling in the VS shell (vertical tab groups, tabs grouped by project, dropping of rarely used tabs, etc); a new searchable Add Reference dialog; new editor enhancements to make navigation easier and much more </p> <p> I’ve been playing with it for the last couple of hours and its very neat. Of course I don’t use <a href="http://www.jetbrains.com/resharper/">Resharper</a> or <a href="http://www.devexpress.com/Products/Visual_Studio_Add-in/Coding_Assistance/">CodeRush</a> (I use too many machines I don’t control to become dependent on them) so some of these features may be available in those tools. But for me the power tools are a welcome addition to the IDE </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=c12e0817-7c4b-4d6b-abce-a2afeeb258ce" /> tag:blogger.com,1999:blog-30604582.post-8646374059620055218 http://andyclymer.blogspot.com/2010/06/software-architecture-2010.html Software Architecture 2010 <p>Myself and other Rock Solid Knowledge guys have had various talks accepted for Software Architecture conference this October in London.</p> <p>Rich and myself will be spending a day talking about how to use various bits of .NET 4 technology to build a MVC, WF and&#160; Entity Framework based application.&#160; The aim to build the app live, so you really get to see how this tech actually ticks.</p> <p>Through out the week I’ll be doing stuff on Patterns, and Parallel programming.</p> <p>Finishing the week with another day with Rich talking about parallel programming, all using the latest bits of .NET 4.</p> <p>Hopefully see you there…</p> <p><a href="http://www.software-architect.co.uk" target="_blank"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="Speaker_SA2010_360x50" border="0" alt="Speaker_SA2010_360x50" src="http://lh4.ggpht.com/_OxnULoaN7CE/TAjpKB3vy5I/AAAAAAAAAqk/PpkqV3u2Hqo/Speaker_SA2010_360x50%5B4%5D.jpg?imgmax=800" width="244" height="37" /></a></p> tag:blogger.com,1999:blog-30604582.post-2913322138003962057 http://andyclymer.blogspot.com/2010/04/devweek-2011.html Devweek 2011 <p>Just heard that Dev Week in London is going to run 14th to 18th March 2011.&#160;&#160; Rock Solid Knowledge will be submitting a variety of talks…If you have some ideas let us know and we will do our best to accommodate.</p> <p>And yep I’m sure Dr Rock Man will be back for the drop in consultations.</p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,332e063e-732b-45b7-a04b-2051785e0877.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,332e063e-732b-45b7-a04b-2051785e0877.aspx Rock Solid Knowledge Screencasts now Available via iTunes <p> Rock Solid Knowledge on iTunes is live! We’ve taken the feed to our free screencasts and they are now available through iTunes via the following link </p> <p> <a href="http://itunes.apple.com/gb/podcast/rock-solid-knowledge-screencasts/id365244375">http://itunes.apple.com/gb/podcast/rock-solid-knowledge-screencasts/id365244375</a> </p> <p> Now you can watch them on the move </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=332e063e-732b-45b7-a04b-2051785e0877" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ab2a4f9a-b925-4903-8792-fb0a3bc3386c.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ab2a4f9a-b925-4903-8792-fb0a3bc3386c.aspx Demos from DevWeek 2010 <p> Thanks to everyone who attended my sessions at DevWeek 2010. I’ve now uploaded the demos which you can find at the following locations </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/DevWeek2010DayOf4.0.zip">A Day of .NET 4.0 Demos</a> </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/DevWeek2010WF4.zip">Windows Workflow Foundation 4.0 Demos</a> </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/DevWeek2010WFServices.zip">Creating WCF Services using WF4 Demos</a> </p> <p> I’ll be around for the rest of the conference so drop by for a chat at our <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,93eeba3c-1dda-4f49-980d-03485fe9572e.aspx">developer clinic</a> in the exhibition area </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=ab2a4f9a-b925-4903-8792-fb0a3bc3386c" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,cd224eac-11f1-495e-a0f5-6b7678e2f35e.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,cd224eac-11f1-495e-a0f5-6b7678e2f35e.aspx Using advanced filters for custom routing logic in the Routing Service <p> In <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,7e558c12-f091-4c02-99c6-90eeca251641.aspx">my last post</a> I pointed to a screencast I had recorded that showed how to create a custom message filter to plug your own logic into the WCF 4.0 Routing Service. However, the simple custom filter is only the start – you can actually take control of part of the routing table which allows you to make global decisions about which filters match a particular request. On that basis I have created another screencast that shows how to build one of these more complex custom filters. in this case I use the example of a round robin load balancer where you can use a file on the file system to indicate whether a specific endpoint should be considered part of the load balancing algorithm </p> <p> You can find this last in the series of screencasts on the routing service, along with all the others here, on the <a href="http://rocksolidknowledge.com/">Rock Solid Knowledge</a> site </p> <p> <a href="http://rocksolidknowledge.com/ScreenCasts.mvc">http://rocksolidknowledge.com/ScreenCasts.mvc</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=cd224eac-11f1-495e-a0f5-6b7678e2f35e" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,7e558c12-f091-4c02-99c6-90eeca251641.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,7e558c12-f091-4c02-99c6-90eeca251641.aspx Using Custom Message Filters with the Routing Service <p> I’ve just uploaded a new screencast on the the <a href="http://www.rocksolidknowledge.com/">Rock Solid Knowledge site</a>. This one shows you how to plug your own routing logic into the new Routing Service that is part of WCF 4.0. It uses a custom message filter that can be used to supplement the existing set of filters such as matching on XPath and Action. </p> <p> You can find the screencast (along with the previous ones in the series) here </p> <p> <a href="http://www.rocksolidknowledge.com/ScreenCasts.mvc"><u><font color="#0066cc">http://www.rocksolidknowledge.com/ScreenCasts.mvc</font></u></a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=7e558c12-f091-4c02-99c6-90eeca251641" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,8a42e2b0-18e9-4730-add9-b2bbf8911bf5.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,8a42e2b0-18e9-4730-add9-b2bbf8911bf5.aspx Data Dependent Routing with the Routing Service <p> Continuing my screencast series on the Routing Service in WCF 4.0, I have just uploaded one on Data Dependent Routing </p> <p> You can get to the latest screencast (and all of the others) here <a href="http://rocksolidknowledge.com/ScreenCasts.mvc"><u><font color="#0066cc">http://rocksolidknowledge.com/ScreenCasts.mvc</font></u></a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=8a42e2b0-18e9-4730-add9-b2bbf8911bf5" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,aa6a1657-4815-4f33-b05f-ddea272abb86.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,aa6a1657-4815-4f33-b05f-ddea272abb86.aspx Failover and Multicast with the Routing Service <p> I have just published my second screencast on one of the new features of WCF 4.0 – the Routing Service. This screencast focuses on enabling multicast and failover with the Routing Service </p> <p> You can get to the screencast from here <a href="http://rocksolidknowledge.com/ScreenCasts.mvc"><u><font color="#0066cc">http://rocksolidknowledge.com/ScreenCasts.mvc</font></u></a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=aa6a1657-4815-4f33-b05f-ddea272abb86" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ac4f4eaf-2b2d-475a-98b4-1bffb59b8e7b.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ac4f4eaf-2b2d-475a-98b4-1bffb59b8e7b.aspx Demos from BASTA! <p> Thanks to everyone who attended my two sessions at <a href="http://it-republik.de/dotnet/basta10spring/">BASTA!</a> – another thoroughly enjoyable conference. I’ve uploaded the demos </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/downloads/BASTAWF4.zip">What’s new in Workflow 4.0</a> – this includes the application with the rehosted designer </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/downloads/BASTAWFServices.zip">Building WCF services with Workflow 4.0</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=ac4f4eaf-2b2d-475a-98b4-1bffb59b8e7b" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,acafcfb9-2d8a-46d3-8a02-b4414e203cf8.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,acafcfb9-2d8a-46d3-8a02-b4414e203cf8.aspx Creating Rich Composite Activities <p> I my <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,c3394709-1aaf-486a-8d1f-51050ce94ecc.aspx">last post</a> I showed that creating a custom composite activity (one that can have one or more children) requires deriving from <font face="Courier New">NativeActivity</font>. The <font face="Courier New">Retry</font> activity that I showed was fairly simple and in particular didn’t try to share data with its child. There appears to be a <a href="http://en.wikipedia.org/wiki/Catch-22_(logic)">catch-22</a> in this situation when it comes to overriding <font face="Courier New">CacheMetadata</font>: if I add a <font face="Courier New">Variable</font> to the metadata (<font face="Courier New">AddVariable</font>) then it can be used exclusively by its children – i.e. the activity itself can’t manipulate the state; if I add a variable as implementation data to the metadata (<font face="Courier New">AddImplementationVariable</font>) then the children cant see it as its seen as purely used for this activities implementation. How then do we create data that can be both manipulated by the activity and accessed by the parent? </p> <p> The secret to achieving this is a feature called <font face="Courier New">ActivityAction</font> - <a href="http://blogs.msdn.com/mwinkle/">Matt Winkler</a> talks about it <a href="http://blogs.msdn.com/mwinkle/archive/2009/12/24/swiss-cheese-and-wf4-or-an-introduction-to-activityaction.aspx">here</a>. The idea is that I can bind an activity to one or more parent defined pieces of data then schedule the activity where it will have access to the data. Its probably best to show this with an example so I have written a <font face="Courier New">ForEachFile</font> activity that you give a directory and then it passes its child the file name of each file in the directory in turn. I’ll show the code in its entirety and then walk through each piece in turn </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> [ContentProperty(<span style="color: #006080">"Body"</span>)]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> [Designer(<span style="color: #0000ff">typeof</span>(ForEachFileDesigner))]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> ForEachFile : NativeActivity, IActivityTemplateFactory</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> InArgument&lt;<span style="color: #0000ff">string</span>&gt; Directory { get; set; }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> [Browsable(<span style="color: #0000ff">false</span>)]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">public</span> ActivityAction&lt;<span style="color: #0000ff">string</span>&gt; Body { get; set; }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #0000ff">private</span> Variable&lt;IEnumerator&lt;FileInfo&gt;&gt; files = <span style="color: #0000ff">new</span> Variable&lt;IEnumerator&lt;FileInfo&gt;&gt;(<span style="color: #006080">"files"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> CacheMetadata(NativeActivityMetadata metadata)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> metadata.AddDelegate(Body);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> RuntimeArgument arg = <span style="color: #0000ff">new</span> RuntimeArgument(<span style="color: #006080">"Directory"</span>, <span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">string</span>), ArgumentDirection.In);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> metadata.AddArgument(arg);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> metadata.AddImplementationVariable(files);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> Execute(NativeActivityContext context)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> DirectoryInfo dir = <span style="color: #0000ff">new</span> DirectoryInfo(Directory.Get(context));</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> IEnumerable&lt;FileInfo&gt; fileEnum = dir.GetFiles();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> IEnumerator&lt;FileInfo&gt; fileList = fileEnum.GetEnumerator();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> files.Set(context, fileList);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> <span style="color: #0000ff">bool</span> more = fileList.MoveNext();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> <span style="color: #0000ff">if</span> (more)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> context.ScheduleAction&lt;<span style="color: #0000ff">string</span>&gt;(Body, fileList.Current.FullName, OnBodyComplete);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum34"> 34:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum35"> 35:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum36"> 36:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum37"> 37:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnBodyComplete( NativeActivityContext context, ActivityInstance completedInstance)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum38"> 38:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum39"> 39:</span> IEnumerator&lt;FileInfo&gt; fileList = files.Get(context);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum40"> 40:</span> <span style="color: #0000ff">bool</span> more = fileList.MoveNext();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum41"> 41:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum42"> 42:</span> <span style="color: #0000ff">if</span> (more)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum43"> 43:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum44"> 44:</span> context.ScheduleAction&lt;<span style="color: #0000ff">string</span>&gt;(Body, fileList.Current.FullName, OnBodyComplete);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum45"> 45:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum46"> 46:</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum47"> 47:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum48"> 48:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum49"> 49:</span> <span style="color: #cc6633">#region</span> IActivityTemplateFactory Members</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum50"> 50:</span> <span style="color: #0000ff">public</span> Activity Create(DependencyObject target)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum51"> 51:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum52"> 52:</span> var fef = <span style="color: #0000ff">new</span> ForEachFile();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum53"> 53:</span> var aa = <span style="color: #0000ff">new</span> ActivityAction&lt;<span style="color: #0000ff">string</span>&gt;();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum54"> 54:</span> var da = <span style="color: #0000ff">new</span> DelegateInArgument&lt;<span style="color: #0000ff">string</span>&gt;();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum55"> 55:</span> da.Name = <span style="color: #006080">"item"</span>;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum56"> 56:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum57"> 57:</span> fef.Body = aa;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum58"> 58:</span> aa.Argument = da;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum59"> 59:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum60"> 60:</span> <span style="color: #0000ff">return</span> fef;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum61"> 61:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum62"> 62:</span> <span style="color: #cc6633">#endregion</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum63"> 63:</span> }</pre> <!--CRLF--> </div> </div> <p> </p> <p> Ok lets start with the core functionality then we’ll look at each of the pieces that help make this fully usable. As you can see the class derives from <font face="Courier New">NativeActivity</font> and overrides <font face="Courier New">CacheMetadata</font> and <font face="Courier New">Execute</font> – we’ll look at their implementations in a minute. There are three member variables in the class: the <font face="Courier New">InArgument&lt;string&gt;</font> for the directory; an implementation variable to hold the iterator as we move through the files in the directory; the all important <font face="Courier New">ActivityAction&lt;string&gt;</font> which we will use to pass the current file name to the child activity. </p> <p> Lets look at <font face="Courier New">CacheMetadata</font> more closely. Because we want to do interesting things with some of the state the default implementation won’t work so we override it. As we don’t call the base class version we need to specify how we use all of the state. We add the <font face="Courier New">ActivityAction</font> as a delegate, we bind the <font face="Courier New">Directory</font> argument to a <font face="Courier New">RuntimeArgument</font> and specify the iterator as an implementation variable – we don’t want the child activity to have access to that directly. </p> <p> Next lets look at <font face="Courier New">Execute</font>. The first couple of lines are nothing unusual – we get the directory and get hold of the list of files. Now we have to store the retrieved iterator in the implementation variable, <font face="Courier New">fileList</font>. We move to the first file in the iteration, if it returns <font face="Courier New">false</font> the list was empty so as long as <font face="Courier New">MoveNext</font> returned <font face="Courier New">true</font> we want to schedule the child activity passing the current file. To do this we use the <font face="Courier New">ScheduleAction&lt;T&gt;</font> member on the context. However, because we’re going to process each one sequentially, we also need to know when the child is finished so we pass a completion callback, <font face="Courier New">OnBodyComplete</font>. </p> <p> Now in <font face="Courier New">OnBodyComplete</font> we simply get the iterator, move to the next item in the iteration and as long as we’re not finished iterating re-schedule the child again passing the new item in the iteration. </p> <p> That really is the “functional” part of the activity – everything else is there to support the designer. So why does the designer need help? Well lets look at what we would have to do to build this activity correctly if we were going to execute it from main </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> Activity workflow = <span style="color: #0000ff">new</span> ForEachFile</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> Body = <span style="color: #0000ff">new</span> ActivityAction&lt;<span style="color: #0000ff">string</span>&gt;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> Argument = <span style="color: #0000ff">new</span> DelegateInArgument&lt;<span style="color: #0000ff">string</span>&gt;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> Name = <span style="color: #006080">"item"</span>,</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> },</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> Handler = <span style="color: #0000ff">new</span> WriteLine</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> Text = <span style="color: #0000ff">new</span> VisualBasicValue&lt;<span style="color: #0000ff">string</span>&gt;(<span style="color: #006080">"item"</span>)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> },</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> Directory = <span style="color: #006080">@"c:\windows"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> };</pre> <!--CRLF--> </div> </div> <p> </p> <p> As you can see, its not a matter of simply creating the <font face="Courier New">ForEachFile</font>, we have to build the internal structure too – something needs to create that structure for the designer - this is the point of <font face="Courier New">IActivityTemplateFactory</font>. When you drag an activity on to the design surface normally it just creates the XAML for that activity. However, before it does that it does a speculative cast for <font face="Courier New">IActivityTemplateFactory</font> and if the activity supports that it calls the interface’s <font face="Courier New">Create</font> method instead and serializes the resulting activity to XAML. </p> <p> So going back to the <font face="Courier New">ForEachFile</font> activity, you can see it implements <font face="Courier New">IActivityTemplateFactory</font> and therefore, as far as the designer is concerned, this is the interesting functionality – lets take a look at the <font face="Courier New">Create</font> method.We create the <font face="Courier New">ForEachFile</font> and wire an <font face="Courier New">ActivityAction&lt;string&gt;</font> to its <font face="Courier New">Body</font> property. <font face="Courier New">ActivityAction&lt;string</font>&gt; needs a slot to store the data to be presented to the child activity. This is modelled by<font face="Courier New"> DelegateArgument&lt;string&gt;</font> and this gets wired to the <font face="Courier New">Argument</font> member of the <font face="Courier New">ActvityAction</font>. We also name the argument as we want a default name for the state so the child activity can use it. Notice, however, we don’t specify the child activity itself (it would be a pretty useless composite if we hard coded this). The child will be placed on the <font face="Courier New">Handler</font> property of the <font face="Courier New">ActivityAction</font> but that will be done in the <font face="Courier New">ActivityDesigner</font> using data binding. </p> <p> Before we look at the designer lets highlight a couple of “polishing” features of the code: the class declared a <font face="Courier New">ContentProperty</font> via an attribute – that just makes the XAML parsing cleaner as the child doesn’t need to be specified using <a href="http://msdn.microsoft.com/en-us/library/ms788723.aspx#PESyntax">property element syntax</a>; the <font face="Courier New">Body</font> is set to non-browsable – we don’t want the activities user to try to set this value in the property grid. </p> <p> OK on to the designer. If you read my previous article there are a couple of new things here. Lets look at the markup – again there is no special code in the code behind file, everything is achieved using data binding </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sap:ActivityDesigner</span> <span style="color: #ff0000">x:Class</span><span style="color: #0000ff">="ActivityLib.ForEachFileDesigner"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #ff0000">xmlns</span><span style="color: #0000ff">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #ff0000">xmlns:x</span><span style="color: #0000ff">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #ff0000">xmlns:s</span><span style="color: #0000ff">="clr-namespace:System;assembly=mscorlib"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #ff0000">xmlns:conv</span><span style="color: #0000ff">="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #ff0000">xmlns:sap</span><span style="color: #0000ff">="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #ff0000">xmlns:sapv</span><span style="color: #0000ff">="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #ff0000">xmlns:me</span><span style="color: #0000ff">="clr-namespace:ActivityLib"</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sap:ActivityDesigner.Resources</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">conv:ArgumentToExpressionConverter</span> <span style="color: #ff0000">x:Key</span><span style="color: #0000ff">="expressionConverter"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">sap:ActivityDesigner.Resources</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">Grid</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">Grid.RowDefinitions</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">RowDefinition</span> <span style="color: #ff0000">Height</span><span style="color: #0000ff">="Auto"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">RowDefinition</span> <span style="color: #ff0000">Height</span><span style="color: #0000ff">="*"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Grid.RowDefinitions</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">StackPanel</span> <span style="color: #ff0000">Orientation</span><span style="color: #0000ff">="Horizontal"</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="2"</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">TextBlock</span> <span style="color: #ff0000">Text</span><span style="color: #0000ff">="For each file "</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">TextBox</span> <span style="color: #ff0000">Text</span><span style="color: #0000ff">="{Binding ModelItem.Body.Argument.Name}"</span> <span style="color: #ff0000">MinWidth</span><span style="color: #0000ff">="50"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">TextBlock</span> <span style="color: #ff0000">Text</span><span style="color: #0000ff">=" in "</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sapv:ExpressionTextBox</span> <span style="color: #ff0000">Expression</span><span style="color: #0000ff">="{Binding Path=ModelItem.Directory, Converter={StaticResource expressionConverter}}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> <span style="color: #ff0000">ExpressionType</span><span style="color: #0000ff">="s:String"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> <span style="color: #ff0000">OwnerActivity</span><span style="color: #0000ff">="{Binding ModelItem}"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">StackPanel</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sap:WorkflowItemPresenter</span> <span style="color: #ff0000">Item</span><span style="color: #0000ff">="{Binding ModelItem.Body.Handler}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> <span style="color: #ff0000">HintText</span><span style="color: #0000ff">="Drop activity"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Row</span><span style="color: #0000ff">="1"</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="6"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Grid</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">sap:ActivityDesigner</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> </div> </div> <p> Here’s what this looks like in the designer </p> <p> <a href="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/CreatingRichCompositeActivities_C385/ForEachFile_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="ForEachFile" border="0" alt="ForEachFile" src="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/CreatingRichCompositeActivities_C385/ForEachFile_thumb.png" width="244" height="84"></a> </p> <p> So the TextBox at line 21 displays the argument name that our IActivityTemplateFactory implementation set up. The ExpressionTextBox is bound to the directory name but allows VB.NET expressions to be used. The WorkflowItemPresenter is bound to the Handler property of the Body ActivityAction, This designer is then associated with the activity using the [Designer] attribute. </p> <p> So as you can see, ActivityAction and IActivityTemplateFactory work together to allow us to build rich composite activities with design time support </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=acafcfb9-2d8a-46d3-8a02-b4414e203cf8" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,c3394709-1aaf-486a-8d1f-51050ce94ecc.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,c3394709-1aaf-486a-8d1f-51050ce94ecc.aspx NativeActivity &ndash; A Tricky Beast <p> I’m writing <a href="http://www.develop.com/course/windows-workflow-foundation-csharp-4">Essential Windows Workflow Foundation 4.0</a> with <a href="http://msmvps.com/blogs/theproblemsolver/default.aspx">Maurice</a> for <a href="http://www.develop.com">DevelopMentor</a>. One of the things that I think is less than obvious is the behavior of NativeActivity. </p> <p> What is NativeActivity I hear you ask? Well there are a number of models for building custom activities in WF4. Most “business” type custom activities will be built using a declarative model in XAML by assembling building blocks graphically. However, what if you are missing a building block? At this point you have to fall back to writing code and there are three options for your base class when writing an activity in code: </p> <p> <strong><font size="2">CodeActivity</font></strong> <br> You use CodeActivity when you have a simple synchronous activity. All work happens in Execute and it has no child activities </p> <p> <strong>AsyncCodeActivity</strong> <br> This is new to WF4. Here you have the ability to implement the async pattern (BeginExecute / EndExecute) to perform short lived async operations where you do not want the workflow persisted (e.g. an async WebRequest) </p> <p> NativeActivity<br> This gives you full access to the power of the workflow execution engine. However, in the words of <a href="http://en.wikipedia.org/wiki/Uncle_Ben">Spiderman’s Uncle</a>, “with great power comes great responsibility”. NativeActivity can be a bit tricky so that is what this article is about </p> <p> I’m going to walk through the code for a Retry activity – where a child activity can be rerun a number of times upon failure. The activity has two InArguments: <font face="Courier New">MaxRetries</font> and <font face="Courier New">RetryDelay</font>. <font face="Courier New">MaxRetries</font> says how many times you will retry the child before giving up. <font face="Courier New">RetryDelay</font> says how long to wait between retries. We could use a <font face="Courier New">Thread.Sleep</font> to do the delay but this would not be good for the workflow engine: we block a thread it could use and there is no way for the engine to persist the workflow – what if we wanted to retry in 2 days? So instead, as part of our implementation, we’ll use a <font face="Courier New">Delay</font> activity. </p> <p> Now to explain the code we have to take a slight diversion and talk about the relationship between Activity, ActivityInstance and ExecutionContext. I talked about is a while back <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,5a7759a2-c6c3-41f6-af58-ba4f82becc9a.aspx">here</a> when the PDC CTP first came out (that’s what the reference to some base class called WorkflowElement is about) but to expand a little: The Activity is really just a template containing the code to execute for the activity. The ActivityInstance is the actual thing that is executing. It holds the state for this instance of the activity template. Now we need a way to bind the template code to the currently running instance of the activity and this is the role of the ExecutionContext. If you are using a CodeActivity base class then most of this is hidden from you except that you have to access arguments by passing in the ExecutionContext. However, with NativeActivity you have to get more directly involved with this model. </p> <p> Now how does the workflow engine know what data you need to store in the ActivityInstance? Well it turns out you need to tell it. NativeActivity has a virtual method called CacheMetadata (<a href="http://blogs.msdn.com/tilovell/archive/2010/02/06/nativeactivity-cachemetadata-for-fun-and-profit.aspx">this post</a> talks about it to some degree). The point being that the activity has to register all of the “stuff” that it wants to use during its execution. Now the base class implementation will do some fairly reasonable default actions but it cannot know, for example, that part of your functionality is there purely for implementation details and should not be public. Therefore, you will often override this when you create a NativeActivity </p> <p> So without more ado – here’s the code for the Retry activity. I’ll then walk through it </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> [Designer(<span style="color: #0000ff">typeof</span>(ForEachFileDesigner))]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Retry : NativeActivity</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #0000ff">public</span> InArgument&lt;<span style="color: #0000ff">int</span>&gt; MaxRetries { get; set; }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #0000ff">public</span> InArgument&lt;TimeSpan&gt; RetryDelay { get; set; }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #0000ff">private</span> Delay Delay = <span style="color: #0000ff">new</span> Delay();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #0000ff">public</span> Activity Body { get; set; }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> Variable&lt;<span style="color: #0000ff">int</span>&gt; CurrentRetry = <span style="color: #0000ff">new</span> Variable&lt;<span style="color: #0000ff">int</span>&gt;(<span style="color: #006080">"CurrentRetry"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> CacheMetadata(NativeActivityMetadata metadata)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> metadata.AddChild(Body);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> metadata.AddImplementationVariable(CurrentRetry);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> RuntimeArgument arg = <span style="color: #0000ff">new</span> RuntimeArgument(<span style="color: #006080">"MaxRetries"</span>, <span style="color: #0000ff">typeof</span>(<span style="color: #0000ff">int</span>), ArgumentDirection.In);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> metadata.Bind(MaxRetries, arg);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> metadata.AddArgument(arg);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> Delay.Duration = RetryDelay;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> metadata.AddImplementationChild(Delay);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> <span style="color: #0000ff">protected</span> <span style="color: #0000ff">override</span> <span style="color: #0000ff">void</span> Execute(NativeActivityContext context)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> CurrentRetry.Set(context, 0);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span> context.ScheduleActivity(Body, OnFaulted);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnFaulted(NativeActivityFaultContext faultContext, Exception propagatedException, ActivityInstance propagatedFrom)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum34"> 34:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum35"> 35:</span> <span style="color: #0000ff">int</span> current = CurrentRetry.Get(faultContext);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum36"> 36:</span> <span style="color: #0000ff">int</span> max = MaxRetries.Get(faultContext);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum37"> 37:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum38"> 38:</span> <span style="color: #0000ff">if</span> (current &lt; max)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum39"> 39:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum40"> 40:</span> faultContext.CancelChild(propagatedFrom);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum41"> 41:</span> faultContext.HandleFault();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum42"> 42:</span> faultContext.ScheduleActivity(Delay, OnDelayComplete);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum43"> 43:</span> CurrentRetry.Set(faultContext, current + 1);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum44"> 44:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum45"> 45:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum46"> 46:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum47"> 47:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">void</span> OnDelayComplete(NativeActivityContext context, ActivityInstance completedInstance)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum48"> 48:</span> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum49"> 49:</span> context.ScheduleActivity(Body, OnFaulted);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum50"> 50:</span> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum51"> 51:</span> }</pre> <!--CRLF--> </div> </div> <p> </p> <p> So lets look at the code: first the class derives from NativeActivity (we’ll come to the designer later). This means I want to do fancy things like have child activities or perform long running asynchronous work. Next we see the two InArguments that are passed to the Retry. The Delay is an implementation detail of how we will pause between retry attempts and the Body property is where the activity we are going to retry lives. Finally we have a Variable, CurrentRetry, where we store how many retry attempts we have made. That is the data in the class but remember we need to tell the workflow engine about what we need to store and why – this is the point of CacheMetadata (I read this method name as “here is the metadata for the cache” rather than “I am going to cache some metadata”) </p> <p> In CacheMetadata the first thing we do is specify that the Body is our child activity. Next we tell the engine that we want to be able to get hold of the CurrentRetry but that its only there for our implementation – we’re not expecting the child activity to try to make use of it. The next 3 lines (17-19) seem a little strange but essentially we’re saying that the MaxRetries argument needs to be accessed over the whole lifetime of the ActivityInstance so we need a slot for that. We next configure out Delay activity passing the RetryDelay as its duration (this is how long we want to wait between retries). Finally we add the Delay, not as a normal child, but as an implementation detail. </p> <p> OK, Execute is pretty simple – we initialize the CurrentRetry and then schedule the Body. But, because we want to retry on failure, we also pass in a fault handler (OnFaulted) </p> <p> OnFaulted does the main work. It fires if the child fails. So it checks to see if we have exceeded the retry count and if not retries the Body activity. However, it doesn’t do this directly, first it tells the context that it has handled the error – it also, strangely has to cancel the current child (which is odd as its already faulted) – Maurice talks about this oddity <a href="http://msmvps.com/blogs/theproblemsolver/archive/2010/02/09/error-handling-in-a-nativeactivity.aspx">here</a>. Next it schedules the Delay as we have to wait for the retry delay and wires up a completion handler (OnDelayComplete) so we know when the delay is finished. Finally it updates the CurrentRetry. </p> <p> OnDelayComplete simply reschedules the Body activity, remembering to pass the fault handler again in case the activity fails again. </p> <p> Oh one thing I said I’d come back to – the designer. I have written a designer to go with this (designers in WF4 are WPF based). The XAML for this is here: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum1"> 1:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sap:ActivityDesigner</span> <span style="color: #ff0000">x:Class</span><span style="color: #0000ff">="WordActivities.ForEachFileDesigner"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum2"> 2:</span> <span style="color: #ff0000">xmlns</span><span style="color: #0000ff">="http://schemas.microsoft.com/winfx/2006/xaml/presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum3"> 3:</span> <span style="color: #ff0000">xmlns:s</span><span style="color: #0000ff">="clr-namespace:System;assembly=mscorlib"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum4"> 4:</span> <span style="color: #ff0000">xmlns:x</span><span style="color: #0000ff">="http://schemas.microsoft.com/winfx/2006/xaml"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum5"> 5:</span> <span style="color: #ff0000">xmlns:sap</span><span style="color: #0000ff">="clr-namespace:System.Activities.Presentation;assembly=System.Activities.Presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum6"> 6:</span> <span style="color: #ff0000">xmlns:sapv</span><span style="color: #0000ff">="clr-namespace:System.Activities.Presentation.View;assembly=System.Activities.Presentation"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum7"> 7:</span> <span style="color: #ff0000">xmlns:conv</span><span style="color: #0000ff">="clr-namespace:System.Activities.Presentation.Converters;assembly=System.Activities.Presentation"</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum8"> 8:</span> <span style="color: #ff0000">mc:Ignorable</span><span style="color: #0000ff">="d"</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum9"> 9:</span> <span style="color: #ff0000">xmlns:d</span><span style="color: #0000ff">="http://schemas.microsoft.com/expression/blend/2008"</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum10"> 10:</span> <span style="color: #ff0000">xmlns:mc</span><span style="color: #0000ff">="http://schemas.openxmlformats.org/markup-compatibility/2006"</span> <span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum11"> 11:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sap:ActivityDesigner.Resources</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum12"> 12:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">conv:ArgumentToExpressionConverter</span> <span style="color: #ff0000">x:Key</span><span style="color: #0000ff">="expressionConverter"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum13"> 13:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">sap:ActivityDesigner.Resources</span><span style="color: #0000ff">&gt;</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum14"> 14:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">Grid</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum15"> 15:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">Grid.RowDefinitions</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum16"> 16:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">RowDefinition</span> <span style="color: #ff0000">Height</span><span style="color: #0000ff">="Auto"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum17"> 17:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">RowDefinition</span> <span style="color: #ff0000">Height</span><span style="color: #0000ff">="Auto"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum18"> 18:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">RowDefinition</span> <span style="color: #ff0000">Height</span><span style="color: #0000ff">="*"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum19"> 19:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Grid.RowDefinitions</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum20"> 20:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">Grid.ColumnDefinitions</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum21"> 21:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">ColumnDefinition</span> <span style="color: #ff0000">Width</span><span style="color: #0000ff">="Auto"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum22"> 22:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">ColumnDefinition</span> <span style="color: #ff0000">Width</span><span style="color: #0000ff">="*"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum23"> 23:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Grid.ColumnDefinitions</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum24"> 24:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum25"> 25:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">TextBlock</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Row</span><span style="color: #0000ff">="0"</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Column</span><span style="color: #0000ff">="0"</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="2"</span><span style="color: #0000ff">&gt;</span>Max. Retries:<span style="color: #0000ff">&lt;/</span><span style="color: #800000">TextBlock</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum26"> 26:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sapv:ExpressionTextBox</span> <span style="color: #ff0000">Expression</span><span style="color: #0000ff">="{Binding Path=ModelItem.MaxRetries, Converter={StaticResource expressionConverter}}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum27"> 27:</span> <span style="color: #ff0000">ExpressionType</span><span style="color: #0000ff">="s:Int32"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum28"> 28:</span> <span style="color: #ff0000">OwnerActivity</span><span style="color: #0000ff">="{Binding ModelItem}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum29"> 29:</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Row</span><span style="color: #0000ff">="0"</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Column</span><span style="color: #0000ff">="1"</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="2"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum30"> 30:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum31"> 31:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">TextBlock</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Row</span><span style="color: #0000ff">="1"</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Column</span><span style="color: #0000ff">="0"</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="2"</span><span style="color: #0000ff">&gt;</span>Retry Delay:<span style="color: #0000ff">&lt;/</span><span style="color: #800000">TextBlock</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum32"> 32:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sapv:ExpressionTextBox</span> <span style="color: #ff0000">Expression</span><span style="color: #0000ff">="{Binding Path=ModelItem.RetryDelay, Converter={StaticResource expressionConverter}}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum33"> 33:</span> <span style="color: #ff0000">ExpressionType</span><span style="color: #0000ff">="s:TimeSpan"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum34"> 34:</span> <span style="color: #ff0000">OwnerActivity</span><span style="color: #0000ff">="{Binding ModelItem}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum35"> 35:</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Row</span><span style="color: #0000ff">="1"</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Column</span><span style="color: #0000ff">="1"</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="2"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum36"> 36:</span> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum37"> 37:</span> <span style="color: #0000ff">&lt;</span><span style="color: #800000">sap:WorkflowItemPresenter</span> <span style="color: #ff0000">Item</span><span style="color: #0000ff">="{Binding ModelItem.Body}"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum38"> 38:</span> <span style="color: #ff0000">HintText</span><span style="color: #0000ff">="Drop Activity"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum39"> 39:</span> <span style="color: #ff0000">Margin</span><span style="color: #0000ff">="6"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum40"> 40:</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Row</span><span style="color: #0000ff">="2"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum41"> 41:</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">Column</span><span style="color: #0000ff">="0"</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum42"> 42:</span> <span style="color: #ff0000">Grid</span>.<span style="color: #ff0000">ColumnSpan</span><span style="color: #0000ff">="2"</span><span style="color: #0000ff">/&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum43"> 43:</span>&nbsp; </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum44"> 44:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">Grid</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #606060" id="lnum45"> 45:</span> <span style="color: #0000ff">&lt;/</span><span style="color: #800000">sap:ActivityDesigner</span><span style="color: #0000ff">&gt;</span></pre> <!--CRLF--> </div> </div> <p> There is no special code behind, everything is done via databinding. </p> <p> So as you can see, there are a lot of pieces that need to be put into place for something that seems fairly simple. The critical issue is getting the implementation of CacheMetadata correct – once you have identified all of the pieces of data you need stored the rest falls out nicely. </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=c3394709-1aaf-486a-8d1f-51050ce94ecc" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b9c1ff65-8823-4a5e-ae07-7531c258a5ac.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b9c1ff65-8823-4a5e-ae07-7531c258a5ac.aspx EF4 Self Tracking Entities &ndash; the new DataSet? <p> A while back I wrote <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0a7cd196-c36b-4afa-ab02-5e4e6829c42d.aspx">a blog post about DataSets</a> and why you shouldn’t use them on service boundaries. The fundamental issues are: </p> <ol> <li> No non-.NET client has any idea what the data looks like you are sending them</li> <li> Hidden, non essential data is being passes up and down the wire</li> <li> Your client gets coupled to the shape of your data (usually a product of the Data Access Layer)</li> </ol> <p> So when I saw that Entity Framework 4.0 supports Self Tracking Entities (STEs) I was interested to see how they would work – after all, automated change tracking is one of the reasons people wanted to use DataSets in service contracts. The idea is that as you manipulate the state the object itself tracks the changes to properties and whether it has been created new or marked for deletion. It does this by implementing an interface called <font face="Courier New">IObjectWithchangeTracker</font> which is then used by the <font face="Courier New">ObjectContext</font> to work out what needs to be done in terms of persistence. There is an extension method on the <font face="Courier New">ObjectContext</font> called <font face="Courier New">ApplyChanges</font> which does the heavy lifting. </p> <p> The Entity Framework team has released a <a href="http://msdn.microsoft.com/en-us/library/bb126445.aspx">T4 Template</a> to generate these STEs from an EDMX file and the nice thing is that the generated entities themselves have no dependency on the Entity Framework. Only the generated context class has this dependency and, so the story goes, the client needs to know nothing about Entity Framework, only the service does. The client, and the entities, remain ignorant of the persistence model. For this reason STEs have been touted as a powerful tool in n-tier based architectures </p> <p> All of this seems almost too good to be true … and unfortunately it is. </p> <p> To understand what the issue is with STEs we have to remember what two of the main goals of Service based systems are: </p> <ol> <li> Support heterogeneous systems – the service ecosystem is not bound to one technology</li> <li> Decoupling – to ensure changes in a service do not cascade to consumers of the service for technical reasons (there may obviously be business reasons why we might want a change in a service to effect the consumers such as changes in law or legislation) </li> </ol> <p> So to understand the problem with STEs we need to look at the generated code.Here’s the model I’m using: </p> <p> <a href="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/EF4SelfTrackingEntitiesthenewDataSet_B3E9/edmx_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="edmx" border="0" alt="edmx" src="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/EF4SelfTrackingEntitiesthenewDataSet_B3E9/edmx_thumb.png" width="244" height="135"></a> </p> <p> Now lets look at the T4 Template generated code for, say, the <font face="Courier New">OrderLine</font> </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">[DataContract(IsReference = <span style="color: #0000ff">true</span>)]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">[KnownType(<span style="color: #0000ff">typeof</span>(Order))]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">public</span> <span style="color: #0000ff">partial</span> <span style="color: #0000ff">class</span> OrderLine: IObjectWithChangeTracker, INotifyPropertyChanged</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #cc6633">#region</span> Primitive Properties</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> [DataMember]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">int</span> id</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> get { <span style="color: #0000ff">return</span> _id; }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> set</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (_id != <span style="color: #0000ff">value</span>)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> ChangeTracker.RecordOriginalValue(<span style="color: #006080">"id"</span>, _id);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> _id = <span style="color: #0000ff">value</span>;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> OnPropertyChanged(<span style="color: #006080">"id"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">private</span> <span style="color: #0000ff">int</span> _id;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #008000">// more details elided for clarity</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> A few things to notice: firstly this is a <font face="Courier New">DataContract</font> and therefore is designed to be used on WCF contracts – that is its intent; secondly a bit of work takes place inside the generated property setters. The property setters check to see if the data is actually changed, then it records the old value and raises calls <font face="Courier New">OnPropertyChanged</font> to raise the <font face="Courier New">PropertyChanged</font> event (defined on <font face="Courier New">INotifyPropertyChanged</font>). Lets have a look inside <font face="Courier New">OnPropertyChanged</font>: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">protected</span> <span style="color: #0000ff">virtual</span> <span style="color: #0000ff">void</span> OnPropertyChanged(String propertyName)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (ChangeTracker.State != ObjectState.Added && ChangeTracker.State != ObjectState.Deleted)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> ChangeTracker.State = ObjectState.Modified;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">if</span> (_propertyChanged != <span style="color: #0000ff">null</span>)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> _propertyChanged(<span style="color: #0000ff">this</span>, <span style="color: #0000ff">new</span> PropertyChangedEventArgs(propertyName));</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> </p> <p> Ok so maybe a bit more than raising the event. It also marks the object as modified in the <font face="Courier New">ChangeTracker</font>. The <font face="Courier New">ChangeTracker</font> state is partly how the STE serializes its self tracked changes. It is this data that is used by the <font face="Courier New">ApplyChanges</font> extension method to work out what has changed. So the thing to remember here is that the change tracking is performed by <strong>code generated into the property setters</strong>. </p> <p> Well the T4 Template has done its work so we create our service contract using these conveniently generated types and the client uses metadata and Add Service Reference to build its proxy code. It gets the <font face="Courier New">OrderLine</font> from the service, updates the quantity and sends it back. The service calls <font face="Courier New">ApplyChanges</font> on the context and then saves the changes and … <em>nothing changes in the Database</em>. What on earth went wrong? </p> <p> At this point we have to step back and think about what those types we use in service contracts are actually doing. <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx">Those types are nothing more than serialization helpers</a> – to help us bridge the object world to the XML one. The metadata generation uses the type definition and the attribute annotations to generate a schema (XSD) definition of the data in the class. Notice we’re only talking about data – there is no concept of behavior. And this is the problem When the Add Service Reference code generation takes place its based on the schema in the service metadata – so the objects *look* right, just the all important code in the property setters is missing. So you can change the state of entities in the client and the service will never be able to work out if the state has changed – so changes don’t get propagated to the database. </p> <p> There is a workaround for this problem. You take the generated STEs and put them in a separate assembly which you give to the client. Now the client has all of the change tracking code available to it, changes get tracked and the service can work out what has changed and persist it. </p> <p> But what have we just done? We have forced the client to be .NET. Not only that, we’ve probably compiled against .NET 4.0 and so we are requiring the client to be .NET 4.0 aware – we might as well have taken out a dependency on Entity Framework 4.0 in the client at this point. In addition, changes I make to the EDMX file are going to get reflected in the T4 generated code – I have coupled my client to my data access layer. Lets go back to the problems with using DataSets on service boundaries again. We’re back where we pretty much started – although the data being transmitted is more controlled. </p> <p> So STEs at first glance look very attractive, but in service terms they are in fact similar to using DataSets in terms of the effect on the service consumer. So what is the solution? We’ll we’re back with our old friends DTOs and <a href="http://www.codeplex.com/AutoMapper">AutoMapper</a>. To produce real decoupling and allow heterogeneous environments we have to explicitly model the *data* being passed at service boundaries. How this is patched this into our data access layer is up to the service. Entity Framework 4.0 certainly improves matters here over 1.0 as we can use POCOs which aid testability and flexibility of our service </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=b9c1ff65-8823-4a5e-ae07-7531c258a5ac" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,93eeba3c-1dda-4f49-980d-03485fe9572e.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,93eeba3c-1dda-4f49-980d-03485fe9572e.aspx Dr Rockman is IN! <p> I’ve just noticed that <a href="http://andyclymer.blogspot.com/2010/02/ask-doctor-devweek-2010.html">Andy has blogged</a> about our drop in clinic we are running at <a href="http://www.devweek.com/welcome.asp">DevWeek 2010</a>. All of the <a href="http://rocksolidknowledge.com/Home.mvc/us">Rock Solid Knowledge guys</a> will be at the conference so come over and let us help solve your design and coding problems – whether it be WCF, Workflow, Multithreading, WPF, Silverlight, ASP.NET MVC,&nbsp; Design Patterns or whatever you are currently wrestling with. We’re also doing a bunch of talks (detailed on our <a href="http://rocksolidknowledge.com/Conferences.mvc/">Conferences page</a>) </p> <p> <a href="http://rocksolidknowledge.com/"><img style="border-right-width: 0px; display: inline; border-top-width: 0px; border-bottom-width: 0px; border-left-width: 0px" title="DrRockman" border="0" alt="DrRockman" src="http://www.dotnetconsult.co.uk/weblog2/content/binary/WindowsLiveWriter/DrRockmanisIN_BB50/DrRockman_3.png" width="144" height="244"></a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=93eeba3c-1dda-4f49-980d-03485fe9572e" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,67272417-08bb-4bb0-b01c-b91a44d0f433.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,67272417-08bb-4bb0-b01c-b91a44d0f433.aspx DevWeek on the Horizon <p> I’ve just realised that <a href="http://www.devweek.com/">DevWeek 2010</a> is on the horizon. DevWeek is one of my favourite conferences&nbsp; - lots of varied talks, vendor independence and I get to hang out with lots of friends for the week. </p> <p> This year I’m doing a preconference talk and two sessions: </p> <p> <font size="4">A Day of .NET 4.0 <br> </font><font size="2">Mon 15th March 2010</font><small> <br> <font size="2"><i>WORKSHOP REF: M1</i> <br> .NET 4.0 is a major release of .NET, including the first big changes to the .NET runtime since 2.0. In this series of talks we will look at the big changes in this release in C#, multithreading, data access and workflow.<br> The best-known change in C# is the introduction of dynamic typing. However, there have been other changes that may affect your lives as developers more, such as support for generic variance, named and optional parameters. There is a whole library for multithreading, PFx, that not only assists you in parallelizing algorithms but in fact replaces the existing libraries for multithreading with a unified, powerful single API.<br> Entity Framework has grown up – the initial release, although gaining some popularity, missed features that made it truly usable in large-scale systems. The new release, version 4.0, introduces a number of features, such as self-tracking objects, that assist using Entity Framework in n-tier applications.<br> Finally, workflow gets a total rewrite to allow the engine to be used far more widely, having overcome limitations in the WF 3.5 API.<br> This workshop will take you through all of these major changes, and we’ll also talk about some of the other smaller but important ones along the way.</font></small> </p> <p> <small><font size="2"></font></small><small><font size="2"><font size="4">An Introduction to Windows Workflow Foundation 4.0</font> <br> Tues 16th March 2010<small> <br> </small>.NET 4.0 introduces a new version of Windows Workflow Foundation. This new version is a total rewrite of the version introduced with .NET 3.0. In this talk we look at what Microsoft are trying to achieve with WF 4.0, why they felt it necessary to rewrite rather than modify the codebase, and what new features are available in the new library. Along the way we will be looking at the new designer, declarative workflows, asynchronous processing, sequential and flowchart workflows and how workflow’s automated persistence works.</font></small> </p> <p> <small><font size="2"><font size="4">Creating Workflow-based WCF Services<br> </font>Tues 16th March 2010<br> </font></small><small><font size="2">There are very good reasons for using a workflow to implement a WCF service: workflows can provide a clear platform for service composition (using a number of building block services to generate a functionally richer service); workflow can manage long running stateful services without having to write your own plumbing to achieve this. The latest version of Workflow, 4.0, introduces a declarative model for authoring workflows and new activities for message based interaction. In addition we have a framework for flexible message correlation that allows the contents of a message to determine which workflow the message is destined for. In this session we will look at how you can consume services from workflow and expose the resulting workflow itself as a service.</font></small> </p> <p> <small><font size="2">As well as these you may well see me popping up as a guest code-monkey in the other <a href="http://rocksolidknowledge.com/Conferences.mvc/">Rock Solid Knowledge</a> sessions. Hope to see you there</font></small> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=67272417-08bb-4bb0-b01c-b91a44d0f433" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,3d5766cb-4d78-46c3-b9ab-57c3c72678c1.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,3d5766cb-4d78-46c3-b9ab-57c3c72678c1.aspx New Screencast &ndash; Introducing the Routing Service <p> The Routing Service is a new feature of WCF 4.0 (shipping with Visual Studio 2010). It is an out-of-the-box SOAP Intermediary able to perform protocol bridging, multicast, failover and data dependent routing. I’ve just uploaded a new screencast walking through setting up the Routing Service and showing a simple example of protocol bridging (the client sends messages over HTTP and the service receives them over NetTcp). This screencast is one of a series I will be recording about the Routing Service. You can find the screencast <a href="http://rocksolidknowledge.com/ScreenCasts.mvc">here</a>. </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=3d5766cb-4d78-46c3-b9ab-57c3c72678c1" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,3c481d20-caf5-49c7-9b6a-aa3c9a5663bd.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,3c481d20-caf5-49c7-9b6a-aa3c9a5663bd.aspx Executing Workflows from XAML Files <p> Seeing as this has changed completely from WF 3.5 I thought I’d post a quick blog entry to describe how to run a workflow declared in a XAML file. </p> <p> You may have heard that the WF 4.0 default authoring model is now XAML. However, the Visual Studio 2010 workflow projects store the XAML as a resource in the binary rather than as a text file. So if you want to deploy your workflows as XAML text files how do you run them? In .NET 3.5 you could pass the workflow runtime an <font face="Courier New">XmlReader</font> pointing at the XAML file but in WF 4.0 there is no <font face="Courier New">WorkflowRuntime</font> class. It turns out you need to load the XAML slightly indirectly by creating a special activity called a <font face="Courier New">DynamicActivity</font> </p> <p> <font face="Courier New">DynamicActivity</font> has an <font face="Courier New">Implementation</font> member that points to a <font face="Courier New">Func&lt;Activity&gt;</font> delegate – in other words you wire up a method that returns an activity (the workflow). Here’s an example: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> DynamicActivity dyn = <span style="color: #0000ff">new</span> DynamicActivity();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #008000">// this line wires up the workflow creator method</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> dyn.Implementation = CreateWorkflow;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">&nbsp;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> WorkflowInvoker.Invoke(dyn);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">&nbsp;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">static</span> Activity CreateWorkflow()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #008000">// we use the new XamlServices utility class to deserialize the XAML</span></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Activity act = (Activity)XamlServices.Load(<span style="color: #006080">@"..\..\workflow1.xaml"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">&nbsp;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">return</span> act;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=3c481d20-caf5-49c7-9b6a-aa3c9a5663bd" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2e3ac342-e003-4587-b577-f05f86a131fc.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2e3ac342-e003-4587-b577-f05f86a131fc.aspx Demos from Last Week&rsquo;s Guerrilla.NET <p> Thanks to everyone who attended <a href="http://www.develop.com/course/guerrilla-net">Guerrilla.NET</a> last week. As promised the demos are now online and you can find them here </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/GNET261009.zip">http://rocksolidknowledge.blob.core.windows.net/demos/GNET261009.zip</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=2e3ac342-e003-4587-b577-f05f86a131fc" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,51443278-6c7c-4eba-8335-075d97b9f66d.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,51443278-6c7c-4eba-8335-075d97b9f66d.aspx Slides and Demos from Software Architect 2009 are now available <p> I just got back from speaking at <a href="http://www.software-architect.co.uk/">Software Architect 2009</a>. I had a great time at the conference and thanks to everyone who attended my sessions. As promised the slides and demos are now available on the <a href="http://rocksolidknowledge.com">Rock Solid Knowledge</a> website and you can get them from the <a href="http://rocksolidknowledge.com/Conferences.mvc/">Conferences</a> page. </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=51443278-6c7c-4eba-8335-075d97b9f66d" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0a7f5b10-21c1-4a01-91d3-62dee7cbd03a.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0a7f5b10-21c1-4a01-91d3-62dee7cbd03a.aspx WSCF Blue Goes RTM <p> I had a lucky coincidence while speaking at <a href="http://www.software-architect.co.uk/">Software Architect 2009</a>. Four hours before I gave a talk on Contract First Design with WCF the WSCF Blue guys released version 1.0 of their tool. Contract first design is the most robust way to build services that potentially have to exist in a heterogeneous environment – it essentially means you start from the WSDL which means everyone can consume the service as no implementation details leak on to the wire. The major stumbling block in the WCF world has been there is no tool that can take a WSDL document and generate the skeleton of a service that implements the defined contract. Finally we have a released tool that does this very thing in the shape of WSCF Blue. In fact it can go further than that because writing WSDL by hand is too much like heavy lifting for many people – so WSCF Blue can also take one or more schema and runs a wizard to build a WSDL document that creates a contract based on the messages in the schema documents. </p> <p> WSCF Blue solves a problem that has been there since WCF 3.0 and the great thing is that its free – <a href="http://wscfblue.codeplex.com/">being release on codeplex</a> </p> <p> Enjoy! </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=0a7f5b10-21c1-4a01-91d3-62dee7cbd03a" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,f72e977b-bf54-41a5-bf20-d23e3f6bc561.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,f72e977b-bf54-41a5-bf20-d23e3f6bc561.aspx MVP&rsquo;d Once More <p> I used to be a C# MVP a couple of years ago. When I took on the role of CTO of DevelopMentor I found I had a far smaller amount of time to devote to community based activity and so I lost my MVP status. I stepped down as DevelopMentor’s CTO back in January and as a result suddenly found I had time again and so can often be found hanging out at the MSDN WCF forum, speaking at conferences, etc. Consequently I have just heard that I’ve been awarded MVP status for Connected Systems :-) - nice to be back in the fold </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=f72e977b-bf54-41a5-bf20-d23e3f6bc561" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,539cffbc-01e3-4079-a6e3-738c3a3b29ed.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,539cffbc-01e3-4079-a6e3-738c3a3b29ed.aspx Slides and Demos from BASTA! <p> Thanks to everyone who came to my sessions at <a href="http://it-republik.de/dotnet/basta09/micro">BASTA!</a> My first time at that conference and I had a great time. Here are the slides and demos </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/BastaWF4.zip?timeout=300">What’s New in Workflow 4.0</a> </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/BastaContractFirst.zip?timeout=300">Contract First Development with WCF</a> </p> <p> <a href="http://rocksolidknowledge.blob.core.windows.net/demos/BastaBeyondListOfT.zip?timeout=300">Generics, Extension Methods and Lambdas – Beyond List&lt;T&gt;</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=539cffbc-01e3-4079-a6e3-738c3a3b29ed" /> http://blogs.mantiso.com/blog/kevin/2009/08/18/Microsoft-Mouse-Preventing-Screen-Saver-Working http://blogs.mantiso.com/blog/kevin/2009/08/18/Microsoft-Mouse-Preventing-Screen-Saver-Working Microsoft Mouse Preventing Screen Saver Working I've just installed Windows 2008 R2 and I could not get the screen saver or power management to work. Turns out I needed to install the correct drivers for my mouse. This is the Wireless Laser 5000, the drivers can be found <a href="http://www.microsoft.com/hardware/download/download.aspx?category=MK">here</a>. http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,386102ab-f8ce-4189-b189-7e6039d3e541.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,386102ab-f8ce-4189-b189-7e6039d3e541.aspx Throttling changes in WCF 4.0 <p> <a href="http://blogs.msdn.com/wenlong/archive/2009/07/26/wcf-4-higher-default-throttling-settings-for-wcf-services.aspx">Wenlong Dong has just posted</a> about changes to the WCF thottling defaults in WCF 4.0. The new throttle defaults are going to be based on the number of processors/cores in the machine – this means the more powerful the machine the higher the throttle will be - which is a good thing. The throttle that always hit people first were either session, if they had a session as a result of contract/binding settings or, no session, concurrent calls. Now the changes (100 * processor count for session and 16 * processor count for calls) will mean that either one would bite first. </p> <p> As Wenlong says, the original values were always too low for enterprise applications. What they did do, however, is force people to address throttling if they were writing enterprise apps. And Wenlong is right that that sometimes meant people putting the throttles up to int.MaxValue which is really the same as no throttle at all. But although, in general, I think the change is the right move (it mostly works out of the box), it will lead to people facing performance problems with absolutely no idea why they might be taking place. </p> <p> What I mean by this is problems caused by the current throttles are really easy to spot “as soon as I put more than 10 calls though it breaks”. You can google that and find the problem and the solution. The new values make it hugely non-obvious why an application suddenly has problems with more than 400 clients (NetTcpBinding on machine with 4 cores for example). Good time to be a consultant in the <a href="http://rocksolidknowledge.com/">UK</a> and <a href="http://www.thinktecture.com">Europe</a> I guess ;-) </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=386102ab-f8ce-4189-b189-7e6039d3e541" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,8ed9b492-1f24-49e3-8af6-2469295f7f9c.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,8ed9b492-1f24-49e3-8af6-2469295f7f9c.aspx Azure platform pricing announced <p> It has been one of the bug bears for me as I have given talks on the Azure platform that I have not been able to answer any question that involved commercial details with anything other than “we’ll have to see the prices when they announce them. Finally, today, the team have announced the pricing model and availability </p> <p> <a href="http://blogs.msdn.com/windowsazure/archive/2009/07/14/confirming-commercial-availability-and-announcing-business-model.aspx">http://blogs.msdn.com/windowsazure/archive/2009/07/14/confirming-commercial-availability-and-announcing-business-model.aspx</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=8ed9b492-1f24-49e3-8af6-2469295f7f9c" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,8c509806-8bdb-47ae-a763-495002fc9972.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,8c509806-8bdb-47ae-a763-495002fc9972.aspx WSCF Blue goes into Beta <p> One of the frustrations with the current WCF tooling is that, although I can generate the client proxy code from a WSDL document I cannot generate the server side skeleton that matches the WSDL. In situations where two parties agree a contract based on WSDL this makes implementing the service side error prone. Back in the ASMX days WSDL.EXE had a /s switch that would create the service side skeleton, but this feature was not carried through into SVCUTIL.EXE. </p> <p> Fortunately the WSCF (Web Service Contract First) guys&nbsp; have finally released a beta of a WCF compatible version of their tool that allows you to build up a model of the service and then generate the client and/or service </p> <p> Here’s Santosh’s <a href="http://santoshbenjamin.wordpress.com/2009/07/04/wscf-blue-beta-1/">announcement</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=8c509806-8bdb-47ae-a763-495002fc9972" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,9601b6a2-e1f5-4edd-bb8b-cdda9e6a481f.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,9601b6a2-e1f5-4edd-bb8b-cdda9e6a481f.aspx New Screencast: Streamed Messages in WCF <p> In my <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0464ef2a-cbaf-4cd1-8f05-d058a0503a2f.aspx">last post</a> I linked to the screencast I made on processing large messages in WCF using buffering. I also said that I would be putting up another one on streaming messages shortly. That second screencast has now gone live on the <a href="http://rocksolidknowledge.com/">Rock Solid Knowledge website</a>. In part 2 of the large message handling screencast I talk about enabling streaming, designing contracts for streaming and how this affects the way the receiver has to process the data. You can find the new screencast here </p> <p> <a href="http://rocksolidknowledge.com/ScreenCasts.mvc">http://rocksolidknowledge.com/ScreenCasts.mvc</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=9601b6a2-e1f5-4edd-bb8b-cdda9e6a481f" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0464ef2a-cbaf-4cd1-8f05-d058a0503a2f.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0464ef2a-cbaf-4cd1-8f05-d058a0503a2f.aspx New Screencast: Working with Large Messages in WCF (Part 1) <p> I’ve just uploaded a new screencast on to <a href="http://rocksolidknowledge.com">Rock Solid Knowledge</a>. This one walks though configuring WCF to be able to pass large messages between client and service. Its the of two parts, this one talks about the default mode WCF uses for transferring data – buffering. I’ll be doing another one soon that looks at WCF in streaming mode. </p> <p> You can find the screencast <a href="http://rocksolidknowledge.com/ScreenCasts.mvc">here</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=0464ef2a-cbaf-4cd1-8f05-d058a0503a2f" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b891610a-6b78-4b54-b9a6-4ec81c82b7c0.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,b891610a-6b78-4b54-b9a6-4ec81c82b7c0.aspx WCF Duplex Messaging <p> I am one of the moderators of the <a href="http://social.msdn.microsoft.com/Forums/en-US/wcf/threads">MSDN WCF Forum</a>. One of the main areas of questions on the forum is duplex messaging – particularly using the WSDualHttpBinding. So instead of typing long messages repeating the same thing in answer to these questions I’ve decided to write this blog post to give a bit of background about duplex messaging and then discuss the options for bindings and common problems people have. </p> <h5>What is Duplex Messaging? </h5> <p> There are many ways that messages can be exchanged between two parties in a service based system: the client can send messages to the server and never get any back; the client can send a message and wait for a response; the client and service can send eachother messages without any pre-defined pattern; the client can send the service a message but not wait synchronously for a response and then then service can send a message back asynchronously; and there are many others. However, the first three of these are supported natively in WCF and are known as One-way, request/response and duplex. </p> <p> So Duplex messaging is where, unsolicited, the client and service can send eachother messages. Most commonly this is characterized by the service sending the client “events” or notifications or progress of “interesting things”. </p> <h5>Duplex Contracts in WCF </h5> <p> To send messages to eachother the client and service must have an idea of what operations are available and what messages are sent and received during the communication. In WCF this idea is modelled by the contract. Now normally a contract just determines what functionality is available at the service. However, now the service is going to be sending messages to the client that the client isn’t specifically waiting for so it needs an idea of what messages the client can deal with. So we need a contract that models both directions of the conversation. </p> <p> A bi-directional contract is modelled using two interfaces bound together with a ServiceContract – like this: </p> <p> </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">[ServiceContract(<strong>CallbackContract=<span style="color: #0000ff">typeof</span>(IPizzaProgress)</strong>)]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">interface</span> IOrderPizza</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> [OperationContract]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">void</span> PlaceOrder(<span style="color: #0000ff">string</span> PizzaType);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">interface</span> IPizzaProgress</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> [OperationContract]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">void</span> TimeRemaining(<span style="color: #0000ff">int</span> minutes);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> [OperationContract]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">void</span> PizzaReady();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> The import bit here is the CallbackContract that establishes the relationship between the service’s and client’s contracts. </p> <h5>Writing the Service </h5> <p> The service is implemented normally apart from two issues: firstly it needs to access the callback contract to be able to send messages back to the client; secondly the communication infrastructure (modelled by the binding) needs to be able to cope with duplex messaging. Firstly lets look at accessing the callback contract: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">class</span> PingService : IOrderPizza</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> IPizzaProgress callback;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> PlaceOrder(<span style="color: #0000ff">string</span> PizzaType)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <strong>callback = OperationContext.Current.GetCallbackChannel<IPizzaProgress> (); </strong></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Action preparePizza = PreparePizza;</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> preparePizza.BeginInvoke(ar => preparePizza.EndInvoke(ar), <span style="color: #0000ff">null</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">void</span> PreparePizza()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">for</span> (<span style="color: #0000ff">int</span> i = 10 - 1; i >= 0; i--)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> callback.TimeRemaining(i);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Thread.Sleep(1000);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> callback.PizzaReady();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> </p> <p> The critical line here is calling GetCallbackContract on the OperationContext. This gives the service access to a proxy to call back to the client. </p> <p> Now the service also needs to use a contract that is compatible with duplex messaging. WSHttpBinding is the default for the built in WCF projects but it does not support duplex messaging. People generally then move to the WSDualHttpBinding which is similar to the WSHttpBinding but does support duplex. I will go into more depth about bindings for duplex shortly but for now lets stick to this for now - it will work in our test rig on a single machine without issue. </p> <h5>Writing the Client </h5> <p> If the client is going to receive these messages it needs to provide an implementation of the callback contract. It can gets its definition from either a shared contract assembly or from metadata. If using metadata the callback contract will be named the same as the service’s contract but with the work Callback appended. It will also need to supply this implementation to the WCF infrastructure and it does this by wrapping an instance in an InstanceContext object and passing it to the proxy constructor. So here is the client: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">class</span> Program</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> Main(<span style="color: #0000ff">string</span>[] args)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><strong> InstanceContext ctx = <span style="color: #0000ff">new</span> InstanceContext(<span style="color: #0000ff">new</span> Callback());</strong></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> OrderPizzaClient proxy = <span style="color: #0000ff">new</span> OrderPizzaClient(ctx);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> proxy.PlaceOrder(<span style="color: #006080">"Pepperoni"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Console.WriteLine(<span style="color: #006080">"press enter to exit"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Console.ReadLine();</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><strong><span style="color: #0000ff">class</span> Callback : IOrderPizzaCallback</strong></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> TimeRemaining(<span style="color: #0000ff">int</span> minutes)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Console.WriteLine(<span style="color: #006080">"{0} seconds remaining"</span>, minutes);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> PizzaReady()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Console.WriteLine(<span style="color: #006080">"Pizza is ready"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> Running the service and the client will have this working quite happily – so it would seem that duplex messaging and WCF works very well … so why on earth do people keep asking questions about it on the WCF forums? </p> <h5>It Worked on My Machine but Broke when we Deployed It! </h5> <p> Ahh well you probably did the thing that is obvious but almost always a bad idea. You went and chose WSDualHttpBinding as your duplex binding. To understand why this is a bad idea we need to dig a little deeper into how the WSDualHttpBinding works. HTTP is a unidirectional protocol: the client makes a request and the server sends a response. There is no way for a server to initiate an exchange with the client. So how on earth is duplex messaging going to work because it requires exactly this facility? Well the “Dual” in the name is significant, the WSDualHttpBinding actually consists of two connections: one outbound from client to server and one inbound from server to client – this second connection may already be ringing alarm bells with you. The are a two big problems with inbound connections to a client: firewalls very often block inbound connections to clients; the client may not be reachable from the server, it may be using NAT translation behind a router and so cannot be contacted without port forwarding being set up on the router. Both of these issues are showstoppers in real network topologies. You can take some small steps to help – you can specify what port the client should listen on for example by using the clientBaseAddress property of the WSDualHttpBinding. This means the network admin will only have to punch one hole in their firewall (but lets face it, network admins don’t allow any holes to be punched in the firewall). </p> <p> So if you really shouldn’t use WSDualHttpBinding for duplex, what should you use instead? Well NetTcpBinding supports duplex out of the box and the nice thing about this is that the outbound connection that it establishes can also be used be used for inbound traffic – suddenly we don;t have the inbound connection firewall/NAT issues. “But hold on, isn’t NetTcpBinding for intranet? I’ve read books that tell me that in their ‘which binding should I use?’ flowcharts!” Well it turns out those flowcharts are talking rubbish – NetTcpBinding works very happily over the internet, its just not interoperable by design. “Aha! but I need interop so WSDualHttpBinding is for me!” Well unfortunately not, NetTcpBinding is non-interoperable by design, WSDualHttpBinding is non-interoperable despite its design. From the name it would suggest interoperability but Arun Gupta from Sun wrote <a href="http://blogs.sun.com/arungupta/entry/wshttpdualbinding_a_non_interoperable_binding">this excellent post</a> describing why it wasn’t. </p> <p> So now seeing that we really are not talking about interop anyway, NetTcpBinding is far more useful than WSDualHttpBinding. Its not bullet proof, if the firewall only allows outbound port 80 but also allows inbound port 80, then WSDualHttpBinding would work where NetTcpBinding wouldn’t – but in this situation we’re really talking server to server and so I’d argue its probably better to roll your own bidirectional communication with two standard HTTP based connections. </p> <p> The final option you have for duplex communication is to add a piece of infrastructure into the mix. <a href="http://www.microsoft.com/azure/servicebus.mspx">The .NET Services Service Bus</a> (part of the Azure platform) allows two parties to exchange messages both making outbound connections – potentially even using HTTP port 80. The two outbound connections rendezvous in the Service Bus which mediates their message exchanges. If the receiver has had to use outbound port 80 then it polls to receive message bound for it. </p> <h5>It Worked for the First 10 Clients and then the Rest Timed Out! </h5> <p> Irrespective if which of the standard bindings you are using, duplex assumes a constant relationship between proxy and service. In WCF this idea is modelled by the concept of session. All duplex bindings require session. A while back <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,af6e6325-2e30-42e3-acb9-57e1363fa51e.aspx">I wrote in some detail about sessions</a>. You will have to either put up with increasing the session throttle (see the linked article for details) or roll your own custom binding that can do duplex without session – you can find an example of this <a href="http://blogs.msdn.com/ralph.squillace/archive/2006/10/10/Sessionless-duplex-services_3F00_-No-problem.-Small-issues_2C00_-yes_3B00_-problems_2C00_-no_2E00_.aspx">here</a>. </p> <h5>I Use the Callback While the Client is calling the Service and it Deadlocks! </h5> <p> This is because your client is probably a Rich Client GUI based application (Windows Forms or WPF). To understand why this is a problem we need to step back briefly and look at UI clients, threading and WCF threading. UI applications have a rule: you must only update the UI from the thread that created those UI components. In general a GUI application has one UI thread so anything that changes the UI needs to be done from that thread. .NET 2.0 introduced a new construct to simplify the process of a background thread updating the UI: SynchronizationContext. The idea is that a UI framework creates an implementation of a SynchronizationContext derived class that handles the mechanics of marshalling a call on to the UI thread. An instance of this implementation is then made available on the UI and accessible via the SynchronizationContext.Current. </p> <p> WCF adds more complexity into the mix by enforcing a rule that says “unless you tell me otherwise I will only allow one thread at a time into an object that I control”. You see this with singleton services that will only allow one call at a time by default. The same is also true of the callback implementation object – so WCF will only allow one active thread in the client at a time. So while WCF is performing an outbound call it will not allow an inbound call into the object. This causes the initial problem with the deadlock that the service’s callback cannot be dispatched while the client’s outbound call is in progress. To solve this we use the “unless you tell me otherwise” part of the above rule. You do this by annotating the callback implementation class with a [CallbackBehavior] attribute like this: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><strong>[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]</strong></pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">class</span> Callback : IOrderPizzaCallback</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> TimeRemaining(<span style="color: #0000ff">int</span> minutes)</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Console.WriteLine(<span style="color: #006080">"{0} seconds remaining"</span>, minutes);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> </pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> PizzaReady()</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> {</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> Console.WriteLine(<span style="color: #006080">"Pizza is ready"</span>);</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> }</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> But now there is another problem: by default WCF will attempt to dispatch using an available SynchronizationContext. The problem with this callback is the UI thread is already blocked in an outbound call. SO for the call to dispatch we need to tell WCF not to use the SynchronizationContext – again using the CallbackBehavior attribute: </p> <div id="codeSnippetWrapper"> <div style="border-bottom-style: none; text-align: left; padding-bottom: 0px; line-height: 12pt; border-right-style: none; background-color: #f4f4f4; padding-left: 0px; width: 100%; padding-right: 0px; font-family: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px" id="codeSnippet"><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">[CallbackBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant, <strong>UseSynchronizationContext=<span style="color: #0000ff">false</span></strong>)]</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"><span style="color: #0000ff">class</span> Callback : IOrderPizzaCallback</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">{</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px"> ...</pre> <!--CRLF--><pre style="border-bottom-style: none; text-align: left; 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: 'Courier New', courier, monospace; direction: ltr; border-top-style: none; color: black; font-size: 8pt; border-left-style: none; overflow: visible; padding-top: 0px">}</pre> <!--CRLF--> </div> </div> <p> Now the issue is of course that the call is going to be processed on a non UI thread so you would have to manually marshal any UI interaction using the SynchronizationContext.Post method. </p> <p> Duplex messaging can be a useful message exchange pattern but in WCF there can be some unexpected issues. Hopefully this blog post clarifies those issues and demonstrates workarounds for them. </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=b891610a-6b78-4b54-b9a6-4ec81c82b7c0" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,847c6d5c-4fcb-4271-8be9-61833877e8d1.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,847c6d5c-4fcb-4271-8be9-61833877e8d1.aspx News of our death has been greatly exaggerated <p> <sigh> it seems that the ever increasing immediacy of social networking and blogging has some downsides. Ted Neward has posted a <a href="http://blogs.tedneward.com/CommentView,guid,dd85708f-48d8-47dc-a9c6-cc4a1287ad31.aspx#commentstart">eulogy</a> for Developmentor (who I regularly teach for). Unfortunately Ted didn’t bother checking his facts. DM are very much still in business and delivering courses (I’m teaching one the week after next and the week after that in fact! Plus several in July and September!) </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=847c6d5c-4fcb-4271-8be9-61833877e8d1" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,86b7d987-6db0-4da3-99fe-1c37a99a1715.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,86b7d987-6db0-4da3-99fe-1c37a99a1715.aspx New Screencast &ndash; Using WCF Tracing for Debugging <p> We’ve just posted a new screencast at <a href="http://rocksolidknowledge.com/">Rock Solid Knowledge</a>. In this one I walk you through enabling WCF tracing to assist in diagnosing bugs in your services using the example of a serialization failure. You can find the screen casts here </p> <p> <a href="http://rocksolidknowledge.com/ScreenCasts.mvc">http://rocksolidknowledge.com/ScreenCasts.mvc</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=86b7d987-6db0-4da3-99fe-1c37a99a1715" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2fee98c4-abb6-455e-a738-47f286bfaf51.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2fee98c4-abb6-455e-a738-47f286bfaf51.aspx DevWeek Interview Online <p> Every year I speak at the excellent <a href="http://www.devweek.com/">DevWeek</a> conference in London. <a href="http://geekswithblogs.net/iupdateable/Default.aspx">Eric Nelson</a>, a Microsoft Developer Evangelist in the UK is also a regular attendee. This year Eric, <a href="http://mtaulty.com/communityserver/blogs/mike_taultys_blog/default.aspx">Mike</a> and <a href="http://blogs.msdn.com/mikeormond/">Mike</a> were recording interviews with people at the conference. Eric interviewed me about Workflow 4.0 (I was delivering a post conference day on WF 4.0, Dublin and Oslo). He’s just got round to published it online </p> <p> <a href="http://geekswithblogs.net/iupdateable/archive/2009/05/20/devweek-2009-interview-with-richard-blewett-on-workflow-4.0.aspx">http://geekswithblogs.net/iupdateable/archive/2009/05/20/devweek-2009-interview-with-richard-blewett-on-workflow-4.0.aspx</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=2fee98c4-abb6-455e-a738-47f286bfaf51" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,06c841b2-52b8-473a-8168-b063b3a24b34.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,06c841b2-52b8-473a-8168-b063b3a24b34.aspx Visual Studio 2010 Beta 1 Ships <p> Soma has blogged that beta 1 has finally shipped. Lots of new stuff in here since PDC. His blog post is here </p> <p> <a href="http://blogs.msdn.com/somasegar/archive/2009/05/18/visual-studio-2010-and-net-fx-4-beta-1-ships.aspx">http://blogs.msdn.com/somasegar/archive/2009/05/18/visual-studio-2010-and-net-fx-4-beta-1-ships.aspx</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=06c841b2-52b8-473a-8168-b063b3a24b34" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,6b977408-c307-4ba1-9774-3fdeead0521c.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,6b977408-c307-4ba1-9774-3fdeead0521c.aspx New Screencasts at Rocksolidknowledge.com <p> We’ve started a library of screencasts at <a href="http://rocksolidknowledge.com/">rock solid knowledge</a>. I’ve created one on WCF Serialization and one on using SSL with Self hosted WCF services. <a href="http://andyclymer.blogspot.com/">Andy Clymer</a> has recorded one on Visual Studio Tricks and Tips and Dave Wheeler has one on character animation in Silverlight 2.0. You can find the screen casts at </p> <p> <a href="http://rocksolidknowledge.com/ScreenCasts.mvc">http://rocksolidknowledge.com/ScreenCasts.mvc</a> </p> <p> We’ll be adding to the library as time goes on so subscribe to the library RSS feed </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=6b977408-c307-4ba1-9774-3fdeead0521c" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ac27a12b-23a9-4154-b3e1-4c1c27e26c1e.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ac27a12b-23a9-4154-b3e1-4c1c27e26c1e.aspx What&rsquo;s new in WF 4.0 Beta 1 <p> Cliff Simpkins has just <a href="http://blogs.msdn.com/endpoint/archive/2009/05/01/the-road-to-4-wf-changes-between-beta-1-and-ctp.aspx">posted a blog entry</a> detailing some of the changes between the PDC preview of WF 4.0 and what is coming in beta 1, due shortly. </p> <p> Important information here not just about beta 1 but also about things you can expect and also things that won’t make it into RTM </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=ac27a12b-23a9-4154-b3e1-4c1c27e26c1e" /> http://blogs.mantiso.com/blog/kevin/2009/04/16/Problem-When-Upgrading-From-Rails-2-2-2-to-2-3-2 http://blogs.mantiso.com/blog/kevin/2009/04/16/Problem-When-Upgrading-From-Rails-2-2-2-to-2-3-2 Problem When Upgrading From Rails 2.2.2 to 2.3.2 <p> I've just installed the latest Active* gems to move my Rails install to 2.3.2. When I ran a console I got the following error </p> <pre> Loading development environment (Rails 2.3.2) /Library/Ruby/Gems/1.8/gems/activesupport-2.3.2/lib/active_support/dependencies.rb:443:in `load_missing_constant':NameError: uninitialized constant ApplicationController </pre> <p> I googled this and found a couple of posts on the issue but nothing obvious that I was doing. After generating a 2.3.3 app and comparing files the solution was obvious and easy. I 2.2.2 the ApplicationController class is in a file called Application.rb, in 2.3.2 this has changed to application_controller.rb. Changing the file name has fixed my problem. </p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2ce96651-c153-416a-a680-cced6ee34fdd.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2ce96651-c153-416a-a680-cced6ee34fdd.aspx Extension Methods and Good Practice &ndash; or OI! Get Out of my Namespace! <p> I’ve been doing some work with the <a href="http://aspnet.codeplex.com/Release/ProjectReleases.aspx?ReleaseId=24644">WCF REST Starter Kit</a> for our website <a href="http://rocksolidknowledge.com">http://rocksolidknowledge.com</a>. Preview 2 of the start kit has a bunch of client side plumbing (the original release concentrated on the service side) </p> <p> The client side code looks something like this: </p> <p> <font size="2"><font face="Courier New"><font color="#2b91af"><font color="#2b91af">HttpClient</font></font> client = <font color="#0000ff"><font color="#0000ff">new</font></font> <font color="#2b91af"><font color="#2b91af">HttpClient</font></font>(<font color="#a31515"><font color="#a31515">"http://twitter.com"</font></font>);</font></font> </p> <p> <font size="2"><font face="Courier New"><font color="#2b91af"><font color="#2b91af">HttpResponseMessage</font></font> response = client.Get(<font color="#a31515"><font color="#a31515">"statuses/user_timeline/richardblewett.xml"</font></font>);</font></font> </p> <p> <font size="2"><font face="Courier New"><font color="#2b91af"><font color="#2b91af">Console</font></font>.WriteLine(response.Content.ReadAsString());</font></font> </p> <p> <font size="2">As compact as this is I was a bit disappointed to see that I only had a few options for processing the content: <font face="Courier New">ReadAsString</font>, <font face="Courier New">ReadAsStream</font> and <font face="Courier New">ReadAsByteArray</font>. Now seeing as they had a free hand to give you all sorts of processing options I was surprised there weren’t more. However, one of the assemblies with the start kit is called <font face="Courier New">Microsoft.Http.Extensions</font>. So I opened it up in <a href="http://www.red-gate.com/products/reflector/">Reflector</a> and lo and behold there are a whole bunch of extension methods in there – so why wasn’t I seeing them? </font> </p> <p> <font size="2">Extension methods become available to your code when their namespace is in scope (e.g. when you have a using statement for the namespace in your code). It turns out that the team put the extension methods in the namespaces appropriate to the technology they were exposing. So for example the <font face="Courier New">ReadAsXElement</font> extension method is in the <font face="Courier New">System.Xml.Linq</font> namespace and the <font face="Courier New">ReadAsXmlSerializable&lt;T&gt;</font> method is in the <font face="Courier New">System.Xml.Serialization</font> namespace.</font> </p> <p> <font size="2">Although I really like the functionality of the WCF Starter Kit, this particular practice, to me, seems bizarre. Firstly, it makes the API counter intuitive – you use the HttpClient class and then there is no hint in the library that there are a bunch of hidden extensions. Secondly, injecting your extensions into someone else’s namespace increases the likelihood of extension method collision (where two libraries define the same extension method in the same namespace). The same named extension method in difference namespaces can be disambiguated, the same named extension in the same namespace gives you no chance.</font> </p> <p> <font size="2">I think if you want to define extension methods then you should keep them in your own namespace – it makes everyone’s life simpler in the long run.</font> </p> <p> <font size="2"></font> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=2ce96651-c153-416a-a680-cced6ee34fdd" /> http://blogs.mantiso.com/blog/kevin/2009/04/02/DevWeek-2009-Demos http://blogs.mantiso.com/blog/kevin/2009/04/02/DevWeek-2009-Demos DevWeek 2009 Demos Are now available on the <a href="http://www.rocksolidknowledge.com/Conferences.mvc/">Rock Solid Knowledge</a> site. I've upload the 'So you think you now JavaScript', 'Design for Testing' and Day of 'Ruby and Rails' talks. Andy's already put up the 'Day of Patterns' and 'Patterns Dartboard' talks http://blogs.mantiso.com/blog/kevin/2009/04/01/Ruby-idioms-in-ASP-Net-MVC http://blogs.mantiso.com/blog/kevin/2009/04/01/Ruby-idioms-in-ASP-Net-MVC Ruby idioms in ASP.Net MVC <p> In Rails there is a mechanism by which you can mimic variadic methods (Ruby also supports true variadic methods) by treating the last parameter as a hash. I can write a function definition like this </p> <pre class="brush: ruby"> def pass_a_hash(s, h) puts s h.each { |key, value| puts "#{key} => #{value}"} if h.class == Hash end </pre> <p> and call it either like </p> <pre class="brush: ruby"> pass_a_hash "kevin", {:a => "b", :c => "d"} </pre> or <pre class="brush: ruby"> pass_a_hash "kevin", :a => "b", :c => "d" </pre> either way this prints <pre> kevin a => b c => d </pre> <p> The second style is much neater, it hides the use of the hash and instead makes it seem like we are using named parameters. This is used all over Rails, especially on web pages where you need to specify things such as controllers and actions. You will often see code like: </p> <pre class="brush: ruby"> &lt;%= link_to "Add", :action => :add, :controller => :students %> </pre> <p> Here we are calling the 'link_to' method passing a string and a hash of options, just like above </p> <p> Microsoft (bless 'em) have tried to mimic this in ASP.Net MVC by letting you can write code similar to the 'link_to' Rails method. On an ASP.Net view you can do something like: </p> <pre class="brush: csharp"> &lt;%= Html.RouteLink("Add", new {action = "add", controller = "students"}) %> </pre> <p> And this adds a link to the page with the text "Add" and a url something like http://server.com/students/add. This is similar to ActionLink and they both eventually call into a method called GenerateRouteLink. In the ASP.Net case the second parameter is not a hash (oh for first class hashes in C#) but an instance of an anonymous class. Using <a href="http://www.red-gate.com/products/reflector/">Reflector</a> we can see what this method does. </p> <p> Internally RouteLink creates a RoutedDictionary passing the anonymous instance as a parameter to its constructor </p> <pre class="brush: csharp"> return htmlHelper.RouteLink(linkText, new RouteValueDictionary(routeValues)); </pre> <p> The RouteValueDictionary constructor looks like this </p> <pre class="brush: csharp"> public RouteValueDictionary(object values) { this._dictionary = new Dictionary&lt;string, object>(StringComparer.OrdinalIgnoreCase); this.AddValues(values); } </pre> <p> and AddValues does this: </p> <pre class="brush: csharp"> private void AddValues(object values) { if (values != null) { foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values)) { object obj2 = descriptor.GetValue(values); this.Add(descriptor.Name, obj2); } } } public void Add(string key, object value) { this._dictionary.Add(key, value); } </pre> <p> So AddValues uses reflection to build a dictionary of name/value pairs </p> <p> Just like in Rails, when the element is rendered this dictionary is interrogated and the values used to build the URL. </p> <p> Neat, but still more ceremony than in Ruby! </p> http://blogs.mantiso.com/blog/kevin/2009/04/01/Ruby-Essence-vs-Ceremony http://blogs.mantiso.com/blog/kevin/2009/04/01/Ruby-Essence-vs-Ceremony Ruby Essence vs Ceremony <p>Last week at <a href="www.devweek.com">DevWeek</a> Tim Ewald and I tried to show some of the elegance of Ruby and I'd like to try and repeat that example here.</p> <p> We started with a Lion class in honour of the news story that week about "Christian the Lion" (hey, look it up yourselves!). The class is very simple </p> <pre class="brush: ruby"> class Lion attr_accessor :message, :name def speak @message end def to_s "#{self.name} says #{self.message}" end @@lions = {} def self.create message, name if @@lions[name] == nil @@lions[name] = Lion.new(message, name) end return @@Lions[name] end def initialize(message, name) @message = message @name = name end end </pre> <p>The bit we care about is the self.create method. The idea here is that we provide a function to only allow the creation of one lion with any given name (this was a demo so it didn't need to make sense). To do this there is a class level dictionary (a static) in which to store new lions. We only add lions to this dictionary if they are unique, otherwise we return an existing lion. The code as it is written is not very Ruby-ish, it reads more like C++, C# or Java code than Ruby and that's what I'd like to change. </p> <p> The first step is to remove the 'return' keyword. In Ruby the last statement in a method is the return value so we can change the code to look like this: </p> <pre class="brush: ruby"> def self.create message, name if @@lions[name] == nil @@lions[name] = Lion.new(message, name) end @@Lions[name] end </pre> <p> The 'if' statement isn't very idiomatic either and in Ruby this can be reduced to </p> <pre class="brush: ruby"> def self.create message, name @@lions[name] = Lion.new(message, name) if @@lions[name] == nil @@lions[name] end </pre> <p> We're still not quite there though. Ruby (like C#) has a 'null co-alescing' operator, which lets me say "if 'x' is not null, use it, else do 'y'", and I can rewrite the above 'if' using this operator (|| in Ruby). It also means I can do away with the final return statement </p> <pre class="brush: ruby"> def self.create message, name @@lions[name] || @@lions[name] = Lion.new(message, name) end </pre> <p> Which says, if @@lions[name] is not null return the value, else assign Lion.new to @@lions[name] and return that value </p> <p> One line to do what it would take four lines to do in other languages and no keywords. As my friend Stu Halloway would put it, essence over ceremony! </p> http://blogs.mantiso.com/blog/kevin/2009/03/27/Dev-Week-2009 http://blogs.mantiso.com/blog/kevin/2009/03/27/Dev-Week-2009 Dev Week 2009 <p>Just finished DevWeek 2009</p> <p>It's been another great week. Spent time with people I haven't seen for a while. I've enjoyed giving the talks and hope you have enjoyed listening to them. I always love spending time hanging out the speakers, there are so many really smart people there. Just spent a day with Tim Ewald - it always blows me away how good a presenter Tim is and how much he knows, this time on Ruby and Rails.</p> <p>Hopefully I'll be back for Software Architect in Sept/Oct and at DevWeek next year.</p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,76bd58e0-39e7-4624-b3af-b6794d047cef.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,76bd58e0-39e7-4624-b3af-b6794d047cef.aspx Slides and demos from my Windows Workflow Session at Devweek <p> Thanks to all who attended my <a href="www.devweek.com">Devweek</a> session: A Beginners Guide to Windows Workflow. The slides and demos can be downloaded <a href="http://dotnetconsult.blob.core.windows.net/demos/WorkflowForBeginners.zip">here</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=76bd58e0-39e7-4624-b3af-b6794d047cef" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2c0c3854-b442-4107-aee5-9c0f726eb652.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,2c0c3854-b442-4107-aee5-9c0f726eb652.aspx A Tale of Two Reader/Writer Locks <p> If you look in the System.Threading namespace you will notice something that looks slightly odd: there are a pair of classes ReaderWriterLock and ReaderWriterLockSlim. What are these for and why are there two of them? </p> <p> Whenever you have multiple threads there is a need to protect state shared between them from corruption. The simplest tool in the .NET Framework is the Monitor class (encapsulated by the lock statement in C#) that provides mutual exclusion. In other words, only one thread at a time can acquire it and anyone else trying to acquire it blocks until the first thread releases it. It situations of high update this provides a reasonable approach. However, if we had no writers we could allow everyone to access a resource without acquiring a lock. So if we had many readers and only an occasional writer, ideally we’d like all the readers to be able to access a resource at the same time and only be blocked if someone needed to write. Unfortunately a Monitor would only allow one reader in at a time so this is the role of a Reader/Writer lock – to allow many concurrent readers but only a single writer, blocking all readers. </p> <p> So we come to the next question: why are there two of them? ReaderWriterLock was introduced in version 2.0 of .NET and provided the above functionality. However, there was a problem. Imagine this scenario: we have 10 readers currently reading when a writer wants access. Obviously the writer has to let the readers finish and so waits patiently for the readers to release their read locks. However, as the readers drop to one, suddenly a brand new reader arrives – there i still a read lock being held but thats ok as it can also acquire a read lock in that situation. Now the writer is blocked on a new reader and more can continue to arrive so that the writer never gets in – this is called writer starvation. ReaderWriterLock suffers from the possibility of writer starvation. </p> <p> For version 3.5 SP1 the .NET framework team decided to address this. They introduced a new class called ReaderWriterLockSlim that provides the reader/writer lock functionality but does not suffer from writer starvation (new readers are blocked when there is a writer waiting). However, why didn’t the team just fix the original one? They say that some people depend on the feature that new readers can get a lock if a reader is already there. They didn’t want to break existing code. </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=2c0c3854-b442-4107-aee5-9c0f726eb652" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,6c02ac47-3336-47f9-b0c9-36025c58cc89.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,6c02ac47-3336-47f9-b0c9-36025c58cc89.aspx Keeping things safe wth AsyncCallback <p> The .NET Async pattern is a very neat way of running functionality asynchronously. The async pattern is where for a synchronous method DoWork be have a pair of methods BeginDoWork and EndDoWork to handle running the DoWork functionality on the threadpool. Now it is well documented that if I call the Begin method I must also call the End method to allow the async infrastructure to clean up resources it may have acquired. However, where do I call the End version? </p> <p> Consider async delegate invocation. Quite often I’d like to just fire off the async method and forget about it but I have to call EndInvoke. Fortunately lambdas make this really easy </p> <p> <font face="Courier New">Action a = DoWork;<br> a.BeginInvoke( ar =&gt; a.EndInvoke(ar) );</font> </p> <p> Now there is a nasty problem. What happens if DoWork throws an exception? The async delegate infrastructure will conveniently cache the exception and re-throw it when I call EndInvoke. However, the issue is that this is happening in an AsyncCallback delegate on a threadpool thread and so I cannot catch it easily in this construct. Why is that a problem? well since .NET 2.0 an unhandled exception on a background thread will terminate the process. This means to reliably call EndInvoke in an AsyncCallback we must put it in a try … catch. This is annoying code to reliably put in place and is easily forgotten. So I have written an extension method to wrap this functionality for you </p> <font size=4> <p> </font><font size=2><font face="Courier New"><font color=#0000ff><font color=#0000ff>public</font></font> <font color=#0000ff><font color=#0000ff>static</font></font> <font color=#0000ff><font color=#0000ff>class</font></font> <font color=#2b91af><font color=#2b91af>Extensions<br> </font></font></font></font><font face="Courier New" size=2>{<br> &nbsp; </font><font size=2><font face="Courier New"><font color=#0000ff><font color=#0000ff>public</font></font> <font color=#0000ff><font color=#0000ff>static</font></font> <font color=#2b91af><font color=#2b91af>AsyncCallback</font></font> Try(<font color=#0000ff><font color=#0000ff>this</font></font> <font color=#2b91af><font color=#2b91af>AsyncCallback</font></font> cb, <font color=#2b91af><font color=#2b91af>Action</font></font>&lt;<font color=#2b91af><font color=#2b91af>Exception</font></font>&gt; exceptionAction)<br> &nbsp; </font></font><font face="Courier New" size=2>{<br> &nbsp;&nbsp;&nbsp; </font><font size=2><font face="Courier New"><font color=#2b91af><font color=#2b91af>AsyncCallback</font></font> wrapper = <font color=#0000ff><font color=#0000ff>delegate</font></font>(<font color=#2b91af><font color=#2b91af>IAsyncResult</font></font> iar)<br> </font></font><font face="Courier New" size=2>&nbsp;&nbsp;&nbsp; {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font color=#0000ff><font color=#0000ff><font face="Courier New" size=2>try<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></font></font><font face="Courier New" size=2>{<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face="Courier New" size=2>cb(iar);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face="Courier New" size=2>}<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font size=2><font face="Courier New"><font color=#0000ff><font color=#0000ff>catch</font></font> (<font color=#2b91af><font color=#2b91af>Exception</font></font> e)<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></font><font face="Courier New" size=2>{<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face="Courier New" size=2>exceptionAction(e);<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font><font face="Courier New" size=2>}<br> &nbsp;&nbsp;&nbsp; </font><font face="Courier New" size=2>};<br> &nbsp;&nbsp;&nbsp; </font><font size=2><font face="Courier New"><font color=#0000ff><font color=#0000ff>return</font></font> wrapper;<br> </font></font><font face="Courier New" size=2>&nbsp; }<br> </font><font face="Courier New" size=2>}</font>> <p> <font size=2>So this code extends AsyncCallback and takes a delegate to call if an exception takes place it then wraps its own AsyncCallback around the one passed in this time putting it in a try … catch block. The usage looks like this:</font> </p> <font size=2><font color=#2b91af size=4><font color=#2b91af size=4> <p> <font face="Courier New" size=2>Action</font> </font></font><font face="Courier New"> a = DoStuff;<br> </font><font face="Courier New"><font color=#2b91af><font color=#2b91af>AsyncCallback</font></font> cb = ia =&gt; a.EndInvoke(ia);<br> </font><font face="Courier New">a.BeginInvoke(cb.Try(e =&gt; <font color=#2b91af><font color=#2b91af>Console</font></font>.WriteLine(e)), <font color=#0000ff><font color=#0000ff>null</font></font><font size=4><font size=2>);</font></font></font>> <p> <font face="Courier New"><font size=4><font face="Trebuchet MS" size=2>The only awkward thing here is having to take the lambda out of the call to BeginInvoke because the C# compiler won’t allow the dot operator on a lambda (without casting it to an AsyncCallback) but at least this wraps up some of the issues</font> </p> </font>>><img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=6c02ac47-3336-47f9-b0c9-36025c58cc89" /> http://blogs.mantiso.com/blog/kevin/2009/03/16/VSTS-Load-Web-Testing-and-Browser-Definitions http://blogs.mantiso.com/blog/kevin/2009/03/16/VSTS-Load-Web-Testing-and-Browser-Definitions VSTS Load/Web Testing and Browser Definitions <p> When you add a VSTS load test or when you configure a web test you can specify the browser(s) to use for the test. The data for each type of browser is held in files with a .browser extension in the C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Templates\LoadTest\Browsers directory. </p> <p> You can add your own browsers to this list by copying and renaming one of these files and changing the details within the file. The files are XML so this is easy to do, they look something like this </p> <p> <pre id="browsers" class="brush: xml"> &lt;Browser Name="Netscape 6.0"> &lt;Headers> &lt;Header Name="User-Agent" Value="Mozilla/5.0 (Windows; U; Windows NT 5.0; en; rv:1.0) Netscape/6.0" /> &lt;Header Name="Accept" Value="image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*" /> &lt;Header Name="Accept-Language" Value="{{$IEAcceptLanguage}}" /> &lt;Header Name="Accept-Encoding" Value="GZIP" /> &lt;/Headers> &lt;/Browser> </pre> </p> <p> Remember to change the Name attribute on the Browser element otherwise you'll see the same browser listed twice inside visual studio. </p> <p> After making the changes you will need to re-start Visual Studio to see your new browser listed. </p> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,5a7759a2-c6c3-41f6-af58-ba4f82becc9a.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,5a7759a2-c6c3-41f6-af58-ba4f82becc9a.aspx WF4: Why do I have to pass the context to get data from an argument? <p> I talked about the new <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,707e4cb9-6111-4069-96b3-596e87f2e262.aspx">WF4 Runtime model</a> a while back. One of the things I discussed was the new data flow model of arguments and variables. However, if you are used to WF 3.5 something looks a bit odd here. Lets look at a simple activity example: </p> <p> <span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent"><span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">public</span> <span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">class</span> WriteLineActivity : WorkflowElement<br> {<br> <span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">&nbsp;&nbsp;&nbsp; public</span> <strong>InArgument&lt;<span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">string</span>&gt; Text</strong> { get; set; }<br> <span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">&nbsp;&nbsp;&nbsp; protected</span> <span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">override</span> <span style="font-size: 11px; color: blue; font-family: courier new; background-color: transparent">void</span> Execute(ActivityExecutionContext context)<br> &nbsp;&nbsp;&nbsp; {<br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Console.WriteLine(<strong>Text.Get(context)</strong>);<br> &nbsp;&nbsp;&nbsp; }<br> }</span> </p> <p> <span style="font-size: 11px; color: black; font-family: courier new; background-color: transparent"><font face="Trebuchet MS" size="2">Why do I need to pass the ActivityExecutionContext when I want to get the data from the argument? This highlights a subtlety to the change in the runtime model. The activity is really just a template. A class called ActivityInstance is the thing that is actually executed, it just has a reference to the actual activity to be able to hand off to the activty’s methods (e.g. Execute). The actual argument state is stored in a construct called the LocalEnvironment. The ActivityExecutionContext gives access to&nbsp; the current ActivityInstance and that in turn holds a reference to the current LocalEnvironment. Therefore, to get from&nbsp; an activity’s Execute method to its state we have to go via the ActivityExecutionContext.<br> </font> </p> ><img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=5a7759a2-c6c3-41f6-af58-ba4f82becc9a" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ba2f9f7f-6819-4f45-aa05-b8ded1c7ad14.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,ba2f9f7f-6819-4f45-aa05-b8ded1c7ad14.aspx BlobExplorer Released on to CodePlex <p> I’ve finally got round to pushing the code for <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,38b4889c-b9a6-4576-a944-b9286637dc14.aspx">BlobExplorer</a> to <a href="http://www.codeplex.com">CodePlex</a>. You can find the CodePlex site <a href="http://www.codeplex.com/blobexplorer">here</a>. If you want to contribute to the project, let me know at <em>richard at nospam dotnetconsult dot co dot uk</em> and I’ll add you to the contributors list. The releases will continue being pushed to blob storage <a href="http://dotnetconsult.blob.core.windows.net/tools/BlobExplorer.zip">http://dotnetconsult.blob.core.windows.net/tools/BlobExplorer.zip</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=ba2f9f7f-6819-4f45-aa05-b8ded1c7ad14" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,fb857c16-d50e-4e23-8eb8-58e981eddbd6.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,fb857c16-d50e-4e23-8eb8-58e981eddbd6.aspx Mapping from Business Objects to DTOs &ndash; Enter AutoMapper <p> A while back I did <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx">this post</a> talking about how WCF contract definitions should model the messages being passed and not use business&nbsp; objects. This inevitably&nbsp; means that you have to translate from the Data Transfer Object (DTO) in the contract to business object and back again. This can feel like a lot of overhead but it really does protect you from a lot of heartache further down the line. </p> <p> However <a href="http://www.leastprivilege.com">Dom</a> just pointed out the <a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2009/01/22/automapper-the-object-object-mapper.aspx">AutoMapper</a> to me. This is in its early stages but looks like the kind of library that will really take away a lot of the grunt work associated with using DTOs – kudos! </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=fb857c16-d50e-4e23-8eb8-58e981eddbd6" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,56569101-55f5-476b-8272-e416edc5df9b.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,56569101-55f5-476b-8272-e416edc5df9b.aspx BlobExplorer Now Supports Blob Metadata <p> I've just dropped&nbsp;a new release of Blob Explorer for managing Windows Azure Blob Storage </p> <p> Two new features: </p> <ul> <li> Blob metadata can now be added and viewed</li> <li> There is a status bar to show that long running uploads and downloads are in progress</li> </ul> <p> As always you can get it from blob storage here </p> <p> <a href="http://dotnetconsult.blob.core.windows.net/tools/BlobExplorer.zip">http://dotnetconsult.blob.core.windows.net/tools/BlobExplorer.zip</a> </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=56569101-55f5-476b-8272-e416edc5df9b" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0a7cd196-c36b-4afa-ab02-5e4e6829c42d.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,0a7cd196-c36b-4afa-ab02-5e4e6829c42d.aspx WCF, Messages and DataSets &hellip; Oh My! <p> Sometimes you have to wonder if this subject will ever go away … </p> <p> A few weeks ago I posted on using <a href="http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,a3775eb1-b441-43ad-b9f1-e4aaba404235.aspx">OO constructs in your DataContracts</a>. It’s one of those things that is understandable when .NET developers first start building message based systems. Another issue that raises its head over and over again goes along the lines of “I’m trying to send a DataSet back to my client and it just isn’t working properly”. This reminds me of the old joke: </p> <p> Patient: Doctor, doctor it hurts when I do this (patient raises his arm into a strange position over his head)<br> Doctor: Well don’t do it then </p> <p> So what is the issue with using DataSets as parameters or return types in your service operations? </p> <p> Lets start off with interoperability – or the total lack thereof. If we are talking about interoperability we have to think about what goes into the WSDL for the DataSet – after all it is a .NET type. In fact DataSets, by default serialize as XML so surely it must be ok! Here’s what a DataSet looks like in terms of XML Schema in the WSDL </p> <p> <span class="m"><font color="#0000ff">&lt;</font></span><span class="t"><font color="#990000">xs:sequence</font></span><span class="m"><font color="#0000ff">&gt;<br> </font></span><span class="b"><strong><font face="Courier New" color="#ff0000">&nbsp;</font></strong></span> <span class="m"><font color="#0000ff">&lt;</font></span><span class="t"><font color="#990000">xs:element</font></span> <span class="t"><font color="#990000">ref</font></span><span class="m"><font color="#0000ff">="</font></span><b>xs:schema</b><font color="#0000ff"><span class="m">"</span><span class="m"> /&gt;</span></font>&nbsp;<br> <span class="b"><strong><font face="Courier New" color="#ff0000">&nbsp;</font></strong></span> <span class="m"><font color="#0000ff">&lt;</font></span><span class="t"><font color="#990000">xs:any</font></span> <span class="m"><font color="#0000ff">/&gt;<br> </font></span><span class="m"><font color="#0000ff">&lt;/</font></span><span class="t"><font color="#990000">xs:sequence</font></span><span class="m"><font color="#0000ff">&gt;</font></span> </p> <p> <span class="m">In other words I’m going to send you some … XML – you work out what do with it. But hold on – if I use Add Service Reference, it *knows* its a DataSet so maybe it is ok. Well WCF cheats; just above that sequence is another piece of XML</span> </p> <p align="left"> <span class="m"><span class="m"><font color="#0000ff">&lt;</font></span><span class="t"><font color="#990000">xs:annotation</font></span><span class="m"><font color="#0000ff">&gt;<br> &nbsp;&nbsp;&nbsp; </font></span><span class="m"><font color="#0000ff">&lt;</font></span><span class="t"><font color="#990000">xs:appinfo</font></span><span class="m"><font color="#0000ff">&gt;<br> </font></span><span class="m"><font color="#0000ff">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;</font></span><span class="t"><font color="#990000">ActualType </font></span><span class="t"><font color="#990000">Name</font></span><span class="m"><font color="#0000ff">="</font></span><b>DataSet</b><span class="m"><font color="#0000ff">"</font></span><span class="t"><font color="#990000"> Namespace</font></span><span class="m"><font color="#0000ff">="</font></span><b>http://schemas.datacontract.org/2004/07/System.Data</b><span class="m"><font color="#0000ff">"</font></span><span class="ns"><font color="#ff0000"> <br> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; xmlns</font></span><span class="m"><font color="#0000ff">="</font></span><b class="ns"><font color="#ff0000">http://schemas.microsoft.com/2003/10/Serialization/</font></b><font color="#0000ff"><span class="m">"</span><span class="m"> /&gt;</span></font>&nbsp;<br> <span class="b"><strong><font face="Courier New" color="#ff0000">&nbsp;</font></strong></span> <span class="m"><font color="#0000ff">&lt;/</font></span><span class="t"><font color="#990000">xs:appinfo</font></span><span class="m"><font color="#0000ff">&gt;<br> </font></span><span class="m"><font color="#0000ff">&lt;/</font></span><span class="t"><font color="#990000">xs:annotation</font></span><span class="m"><font color="#0000ff">&gt;</font></span></span> </p> <p align="left"> <span class="m"><span class="m">So WCF cheats by putting an annotation only it understands into the schema so it knows to use a DataSet. If you really do want to pass back arbitrary XML as part of a message then use an XElement.</span></span> </p> <p align="left"> <span class="m"><span class="m">So how about if I have WCF on both ends of the wire? Well then you’ve picked a really inefficient way to transfer around the data. You have to remember how highly functional a DataSet actually is. Its not just the data in the tables that support that functionality, there is also : change tracking data to keep track of what rows have been added, updated and removed since the DataSet was filled; relationship data between tables; a schema&nbsp; describing itself. DataSets are there to support disconnected processing of tabular data, not as a general purpose data transfer mechanism.</span></span> </p> <p align="left"> <span class="m"><span class="m">Then you may say – “hey we’re running on an intranet – the extra data is unimportant”. So the final issue you get with a DataSet is tight coupling of the service and the consumer. Changes to the structure of the data on one side of the wire cascade to the other side to someone who may not be expecting the changes. Admittedly not all changes will be breaking ones but are you sure you know which ones will be and which ones won’t. As long as the data you actually want to pass isn’t changing why are you inflicting this instability on the other party in the message exchange. The likelihood that you will have to make unnecessary changes to, say, the client when the service changes is increased with DataSets&nbsp; </span></span> </p> <p align="left"> <span class="m"><span class="m">So what am I suggesting to do instead? Instead model the data that you do want to pass around using DataContract (or XElement if you truly want to be able to pass untyped XML). Does this mean you have to translate the data from a DataSet to this DataContract when you want to send it? Yes it does, but that code can be isolated in a single place. When you receive the data as a DataContract and want to process it as a DataSet, does this mean you have to recreate a DataSet programmatically? Yes it does, but again you can isolate this code in a single place.</span></span> </p> <p align="left"> <span class="m"><span class="m">So what does doing this actually buy you if you do that work? You get something which is potentially interoperable, that only passes the required data across the wire and that decouples the service and the consumer. </span></span><span class="m"> </p> ><img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=0a7cd196-c36b-4afa-ab02-5e4e6829c42d" /> http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,d32be8a7-aa1b-4d2f-9e54-780cf57528a4.aspx http://www.dotnetconsult.co.uk/weblog2/PermaLink,guid,d32be8a7-aa1b-4d2f-9e54-780cf57528a4.aspx Workflow 4.0 Services and &ldquo;InvalidOperationException: DispatchOperation requires Invoker&rdquo; <p> I’ve been writing a lab on Workflow Services in 4.0 recently. Part of what I was showing was the new data orientated correlation (the same kind of mechanism that BizTalk uses for correlation). So I wanted to have two operations that were correlated to the same workflow instance based on data in the message (rather than a smuggled context id as 3.5 does it). As I was writing this lab I suddenly started getting an <font face="Courier New">InvalidOperationException</font> stating <strong><em>DispatchOperation requires Invoker</em></strong> every time I brought the .xamlx file up in a browser. It appeared that others had seen this as well but not really solved it. So I dug around looking at the XAML (workflow services can be written fully declaratively now) and the config file and could see no issues there. I asked around but no one I asked knew the reason. </p> <p> So I created a simple default Declarative Workflow Service project and that worked ok. I compared my lab workflow and the default one and it suddenly dawned on me what was wrong. The default project has just one operation on the contract and has a ServiceOperationActivity to implement it. My contract had my two operations but I had, so far, only bound one ServiceOperationActivity. So in other words I had not implemented the contract. This is obviously an issue and looking back I’m annoyed I didn’t see it sooner. </p> <p> However, the problem is that this is a change in behavior between 3.5 and 4.0. In 3.5 if I didn’t bind a ReceiveActivity to every operation I got a validation warning but I could still retrieve metadata; in 4.0 you get a fatal error. Its not hugely surprising that the behavior has changed – after all the whole infrastructure has been rewritten. </p> <p> On the whole its a good thing that implementation of the contract is enforced – although it would be nice if the validation infrastructure caught this at compile time rather than it being a runtime failure. </p> <img width="0" height="0" src="http://www.dotnetconsult.co.uk/weblog2/aggbug.ashx?id=d32be8a7-aa1b-4d2f-9e54-780cf57528a4" /> http://blogs.mantiso.com/blog/kevin/2008/12/12/212F21AA1AF7ACD5F0A8069C5A00F850 http://blogs.mantiso.com/blog/kevin/2008/12/12/212F21AA1AF7ACD5F0A8069C5A00F850 Ruby 1.9 and Active Record <p> I'm trying to use ActiveRecord outside of Rails and with Ruby 1.9. I kept getting an error </p> <pre class="brush: ruby"> /opt/local/lib/ruby1.9/gems/1.9.1/gems /activerecord-2.2.2/lib/active_record/base.rb:394:in `&lt;class:Base>': undefined method `cattr_accessor' for ActiveRecord::Base:Class (NoMethodError) from /opt/local/lib/ruby1.9/gems/1.9.1/gems/activerecord- 2.2.2/lib/active_record/base.rb:391:in `&lt;module:ActiveRecord>' from /opt/local/lib/ruby1.9/gems/1.9.1/gems/activerecord- 2.2.2/lib/active_record/base.rb:4: in `&lt;top (required)>' from /opt/local/lib/ruby1.9/gems/1.9.1/gems/activerecord- 2.2.2/lib/active_record.rb:34: in `require' from /opt/local/lib/ruby1.9/gems/1.9.1/gems/activerecord- 2.2.2/lib/active_record.rb:34: in `&lt;top (required)>' from /opt/local/lib/ruby1.9/gems/1.9.1/gems/activerecord- 2.2.2/lib/activerecord.rb:1 :in `require' from /opt/local/lib/ruby1.9/gems/1.9.1/gems/activerecord- 2.2.2/lib/activerecord.rb:1: in `&lt;top (required)>' from SimpleTest.rb:2:in `require' from SimpleTest.rb:2:in `<main>' </pre> <p> so and undefined method cattr_accessor in ActiveRecord::Base. </p> <p> Trying the same code in 1.8 worked fine. After much searching I discovered that ActiveSupport had to be installed. This looked like it was installed when I installed ActiveRecord, but it possibly wasn't a complete install. </p> <p> so after a </p> <pre> sudo gem install ActiveSupprt </pre> <p> I'm good to go </p> <div class="posttagsblock"><a href="http://technorati.com/tag/Ruby" rel="tag">Ruby</a></div> http://blogs.mantiso.com/blog/kevin/2008/12/02/B64D01983CD260D66CE1935346E056D8 http://blogs.mantiso.com/blog/kevin/2008/12/02/B64D01983CD260D66CE1935346E056D8 Running the latest version of Rails <p>By this I mean running the latest Gem version not Edge. In config/environment.rb is a line that says something like</p> <pre class="brush: ruby"> RAILS_GEM_VERSION = '2.1.0' unless defined? RAILS_GEM_VERSION </pre> <p>You can either set this to a specific version or if you want to run off the latest installed (Gem) version then simply comment out the line</p> <div class="posttagsblock"><a href="http://technorati.com/tag/Rails" rel="tag">Rails</a></div> http://blogs.mantiso.com/blog/kevin/2008/11/10/B3346581008011A831343A29D045E147 http://blogs.mantiso.com/blog/kevin/2008/11/10/B3346581008011A831343A29D045E147 Rails - Routing <p> It's been a while since my last post, that's a mixture of being at PDC and battling with Rails routing so that I understand it better and so that I can bend it to my will! I've finally got something working to my liking but it's taken a while. </p> <p> Routing is a huge part of Rails and, like most things in Rails, I'm not going to be able to do it full justice in this post. </p> <p>Rails provides a flexible and convenient routing mechanism, which sounds like marketing speak but is true. If the application uses RESTful routes then much of the work is done for it, although only if you want to work exactly the way Rails expects, otherwise you have to understand the routing to get it to fit into your scheme. </p> <p> Routing information is stored in a file called routes.rb which is in the config directory. The route data 'draws' routes by mapping from resources to HTTP verbs/URLs and vice versa. This means that for a given HTTP verb (GET say) and a given URL ("/blog/foo") there is a map to a specific controller/action pair. </p> <p>When a controller is generated from a script an entry is automatically placed in /config/routes.rb. For a 'blogs' controller the entry would look like this: </p> <pre class="brush: ruby"> map.resources :blogs </pre> <p> This entry sets up a bunch of routes for the "blogs" controller in this application. There are several ways to see these routes. The generated BlogsController class will have a set of commented methods that show which URLs will be directed to which methods (shown here but shortened for convenience) </p> <pre name="code" class="brush: ruby"> # GET /blogs # GET /blogs.xml def index # GET /blogs/1 # GET /blogs/1.xml def show # GET /blogs/new # GET /blogs/new.xml def new # GET /blogs/1/edit def edit # POST /blogs # POST /blogs.xml def create # PUT /blogs/1 # PUT /blogs/1.xml def update # DELETE /blogs/1 # DELETE /blogs/1.xml def destroy </pre> <p> However this does not tell the whole story, for example these routes have names and these names can be used in your code to add references to the URLs. </p> <p>Another way to look at the roots available is to get Rails to list them. One way of doing this is to execute the <span style="white-space: pre;font-family:monospace;">rake routes</span> command: </p> <pre name="code" class="brush: ruby"> $ rake routes blogs GET /blogs {:controller=>"blogs", :action=>"index"} formatted_blogs GET /blogs.:format {:controller=>"blogs", :action=>"index"} POST /blogs {:controller=>"blogs", :action=>"create"} POST /blogs.:format {:controller=>"blogs", :action=>"create"} new_blog GET /blogs/new {:controller=>"blogs", :action=>"new"} formatted_new_blog GET /blogs/new.:format {:controller=>"blogs", :action=>"new"} edit_blog GET /blogs/:id/edit {:controller=>"blogs", :action=>"edit"} formatted_edit_blog GET /blogs/:id/edit.:format {:controller=>"blogs", :action=>"edit"} blog GET /blogs/:id {:controller=>"blogs", :action=>"show"} formatted_blog GET /blogs/:id.:format {:controller=>"blogs", :action=>"show"} PUT /blogs/:id {:controller=>"blogs", :action=>"update"} PUT /blogs/:id.:format {:controller=>"blogs", :action=>"update"} DELETE /blogs/:id {:controller=>"blogs", :action=>"destroy"} DELETE /blogs/:id.:format {:controller=>"blogs", :action=>"destroy"} </pre> <p> The format is probably screwed as you look at this but hopefully it's still easy to work out what is going on. This lists the VERB/URL mapping to Controller/action, in this case the routes are only shown for the "blogs" resource, the actual listing is much longer and contains all resources as well as the default routing behaviour. The list is fairly straightforward, it shows the name of the route (if there is one), the HTTP verb, the URL and the controller/action these map to. For example the 'blog' named route says that sending a URL of the form blog/[:id] (e.g. /blogs/1) with the HTTP GET verb results in a call to the blogs controller's show method. In this case the value '1' at the end of the URL will be available as the :id value in the params collection. Notice that not all routes are /controller/action style, but that some simply rely on /controller and the HTTP verb to work out the method to call. </p> <p> The names of the routes are very useful. For example in the above there are routes named 'blogs', 'blog' and 'new_blog' amongst others. These names can be used to display a URL for that route. As an example in views/blogs/index.html.erb there is a line like this: </p> <pre> &lt;%= link_to 'New blog', new_blog_path %> </pre> <p> that says to use the path generated from the new_blog route to get the URL to display. </p> <p> This is all well and good, and nice and easy to use and if you simply want to use the Rails conventions then you are good. However there are going to be occasions when simply using the defaults does not work. Luckily, for those cases the routing infrastructure is extensible. In the case of this blog I wanted to do two things, I wanted to support multiple blog authors, and I wanted blog IDs to be friendlier. In fact both these things are related, although I've only tackled the first issue at the moment, but the second issue is resolvable using a similar mechanism. </p> <p> These issues are to do with the way that Rails identifies resources. It does this via the 'id' primary key. So to get to a blog you would send a GET to http://localhost/blogs/1 where blogs is the name of the controller and 1 is the id of the blog. This isn't ideal for a user. The id is an internal representation that the database uses to identify the blog. An end user doesn't want to say 'go to blog 1', they want to say "kevin's blog" or "harry's blog". To support that blogs should have 'nicknames' and these nicknames then get used to identify the blog, meaning that the url becomes http://localhost/blogs/kevin. Similarly with blog entries, the URL to the entry should include the nickname of the blog and maybe the title of the entry. So something like http://localhost/blog/kevin/my-title rather than http://localhost/blog_entry/1/1, where 'blog-entry' is the name of the controller, the first '1' is the id of the blog and the second '1' is the id of the entry. Fixing this requires several steps some of which I'll cover here. At this point I've not fully converted the code to produce URLs like the above but I'm a large step towards it. That step means not relying on the default routes drawn for REST based controllers and rewriting some of the usage of named routes in the controller and views. </p> <p> The first thing I wanted to prevent was the user having to use the 'blog_entry' name for the controller. This is an internal representation and, as a user, I don't like the name. I wanted something shorter, so I've chosen 'blog' as the alias for the controller, you can guarantee that at some point in the future I'll have come up with something else! I also want to use a 'nickname' as an identifier to show whose blog entries we were looking at. This meant I wanted a URL something like http://localhost/blog/kevin to retrieve all blog entries for "kevin". I did this by modifying routes.rb. </p> <p> In routes.rb I took out the entry for <span style="white-space: pre;font-family:monospace;">map.resources blog_entries</span> and added explicit entries for routing. The entries look like this: </p> <pre name="code" class="brush: ruby"> map.blog_entries 'blog/:nickname', :controller => "blog_entries", :action => "index", :conditions => {:method => :get} map.connect 'blog/:nickname', :controller => "blog_entries", :action => "create", :conditions => {:method => :post} map.new_blog_entry 'blog/:nickname/new', :controller => "blog_entries", :action => "new", :conditions => {:method => :get} </pre> <p> There are many more entries and there are also also entries for formatted output (basically, I did a rake routes, copied and pasted the code and edited it). The above entries show a number of things: there are two named routes (blog_entries and new_blog_entry), and one unnamed route (the call to map.connect). As an aside notice the the named routes are named with a call to map.some_function. This function does not exist and shows the power of Ruby as a language. Internally the map class will override the method_missing method to add this named route. The routes specify the HTTP verb, the controller to call and the action to use on that controller. Notice that all the routes all specify an extra paramter, :nickname. This will be part of the URL and be passed into code in the params collection in much the same way that :id is passed. Once these routes have been defined you can then use them in code. </p> <p> The nickname is associated with an individual blog and through that with the entries in that blog. This means that to use the nickname we always need to load the blog associated with it. In the BlogEntriesController class I added a "before_filter" entry. before_filters are code that gets executed before the action. The before_filter looks like this: </p> <pre name="code" class="brush: ruby"> before_filter :get_associated_blog protected def get_associated_blog if params[:nickname] @blog = Blog.find_by_nickname(params[:nickname]) else @blog = nil end end </pre> <p> This finds the associated blog (if it can) and stores it as a member variable of the class. The action is then called, and the action can decide what to do if the blog hasn't been found which will typically be to redirect somewhere. </p> Modifying routing - recreate mapped routes; unnamed and named; use link_to with params to generate url! Needed to add another column: ruby script/generate migration add_usershortname_to_user user_id:string then migrate: rake db:migrate </p> <pre name="code" class="brush: ruby"> def show if @blog # work here else redirect_to(:controller => "blogs") end end </pre> <p> This is nice and easy. However you can also use the nickname to build URLs. For example when we create a new blog entry we want to re-direct back to the blog for this nickname. The code for that looks something like: </p> <pre name="code" class="brush: ruby"> def create if @blog @blog_entry = BlogEntry.new(params[:blog_entry]) if @blog_entry.save flash[:notice] = 'BlogEntry was successfully created.' format.html { redirect_to(:nickname => @blog.nickname) } </pre> <p> Notice that the redirect_to uses the nickname. This ensures that we redirect back to http://localhost/blog/kevin rather than http://localhost/blog. </p> <p> Another place the nicknames are used are in the views. If we use the standard Rails mapping for routes then we can use the helper functions directly, something like: </p> <pre name="code" class="brush: ruby"> &lt;%= link_to 'Edit', edit_blog_path(@blog) %> | &lt;%= link_to 'Back', blogs_path %> </pre> <p> Where we use the default 'blogs' routing to build URLs for an edit entry and to get to the blogs controller's index page. Now that we've amended the blog_entry routes though we also need to track down and edit the uses of link_to (and url_for and any other use of these paths) in the view files. The primary change is to add the :nickname value to all the links. This is why we made @blog an instance variable in the BlogEntriesController class, so that it would be available in the views. The views will look something like: </p> <pre name="code" class="brush: ruby"> &lt;%= link_to 'Show', blog_entry_path(:nickname => blog_entry.blog.nickname, :id => blog_entry.id) %> &lt;%= link_to 'Edit', edit_blog_entry_path(:nickname => blog_entry.blog.nickname, :id => blog_entry.id) %> &lt;%= link_to 'Delete', blog_entry_path(:nickname => blog_entry.blog.nickname, :id => blog_entry.id), :confirm => 'Are you sure?', :method => :delete %> &lt;%= link_to 'New Entry', new_blog_entry_path(:nickname => @blog.nickname) %> </pre> <p> Notice that for each of these routes we set the :nickname and the :id values. In fact this was the trickiest part of the entire procedure, figuring out what parameters I needed to pass to the link_to methods. For example there are times when I have to explicitly set :id to an empty string and others where the :id isn't needed at all. </p> <p> There are some other changes I had to make along the way, notably: </p> <ul> <li>Added foreign key constraints to blog table.</li> <li>Change admin interface to add name</li> <li>Change/add a create blog UI</li> </ul> <p> Now that's done I intend to go back and fix up the 'blogs' routing so that it also supports nicknames. </p> http://blogs.mantiso.com/blog/kevin/2008/10/22/CCC458BD84A1F541294DE050CAE46866 http://blogs.mantiso.com/blog/kevin/2008/10/22/CCC458BD84A1F541294DE050CAE46866 Rendering and Layouts <p>I'm assuming that most people reading this are .Net folk and that you will have at least a passing familiarity with ASP.Net, so occasionally I'll draw comparisons with Microsoft's framework. ASP.Net has had, since 2.0, the concept of Master pages. These are pages that provode the overall structure of parts of a web site. ASP.Net lets a page author design a template that contains content placeholders, this template is called a 'master page', individual pages can then specify that they want to use a specific master page and also specify which content replaces which placeholder within the page. Internally this turns out to be a fairly convoluted mechanism as the master page and the content page have to be woven together so that the right events get delivered to the right thing at the right time.</p> <p>Rails, as you would expect, has a similar mechanism which known as 'layouts'.</p> <p>In a Rails app, content is defined in a template. If you use the default generators of Rails 2.0 these templates are in the form of .erb files. A .erb file is essentially an HTML page with "turd-lets" of code embedded into it between &lt;% %&gt; and &lt;%= %&gt; symbols. This is just like other templating technologies such as ASP, ASP.Net, JSP or PHP</p> <p>Templates are part of the view (obviously) and a typical template renders content for an action. For example in the rblog application there is a <span style="white-space: pre;font-family:monospace;">BlogsController</span> class this has an index action with an associated index template. Of course none of this is mandatory, this is though the default behaviour if you use the scaffolding. The templates live in app/views and this index template lives in app/views/blogs/index.html.erb</p> <p>The template looks something like this:</p> <pre class="brush: ruby" name="code"> &lt;h1>Latest Output&lt;/h1> &lt;div id='blog-entries-main-body'> &lt;div id='blog-entries'> &lt;% for blog_entry in @blog_entries %> &lt;div class='blog-entry-surround'> &lt;span class="blog-title">&lt;%=h blog_entry.title %>&lt;/span> &lt;div>&lt;%=h blog_entry.entry %>&lt;/div> &lt;span class="blog-author">&lt;%=h blog_entry.author_id %>&lt;/span> &lt;/div> &lt;% end %> &lt;/div> &lt;/div> </pre> <p> The template is a mixture of HTML and ruby. This Ruby code iterates over a collection of blog_entries (stored in @blog_entries) and for each one formats some output. </p> <p> The action that causes this particular view to be rendered looks like: </p> <pre class="brush: ruby" name="code"> def index @blog_entries = BlogEntry.find(:all, :order => 'updated_at DESC', :limit => 10) @blogs = Blog.find(:all) respond_to do |format| format.html # index.html.erb format.xml { render :xml => @blogs } end end </pre> <p> The first thing to note is that there are two member variables initialized, @blogs and @blog_entries. These are initialized in the controller and are also available in the view, that's where the view gets its @blog_entries reference from. </p> <p> The other piece of interest is the <span style="white-space: pre;font-family:monospace;">respond_to</span> section. This says that if the format is html use the default rendering (the '#' is a comment, so the 'index.html.erb' on that line is there as an aide memoire), and if the format is XML then use the XML renderer. </p> <p> This means that when a request comes into /blogs then the index action of the blogs controller is executed, the @blogs and @blog_entries objects are created, control passes to the view and the output is rendered. However the output looks like this... </p> <img src="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/kevinj/200810170814.jpg" width="480" height="422" alt="200810170814.jpg" /> <p> There is some extra stuff in here, for example there is styling and also things like a Register and Login button. This extra HTML comes from the layouts. </p> <p> The layouts live in the app/layouts directory and by default there is one layout per controller, this is generated as part of the scaffolding. This means that if nothing explicit is done a default layout will be used, however there are various other ways to specify the layout needed, as will be seen. </p> <p> The layout used for the blogs page looks like this </p> <pre name="code" class="brush: ruby"> &lt;html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> &lt;head> &lt;meta http-equiv="content-type" content="text/html;charset=UTF-8" /> &lt;title>RBlog: &lt;%= controller.action_name %>&lt;/title> &lt;%= stylesheet_link_tag 'general' %> &lt;/head> &lt;body> &lt;div class="header" id="header"> &lt;div id="header-message"> Welcome to RBlog &lt;/div> &lt;div id="flash"> &lt;p>&lt;%= flash[:notice] %>&lt;/p> &lt;/div> &lt;div id="logon"> &lt;%= link_to "Register", :action => "register", :controller => "authenticate" %> &lt;%= link_to "Login", :action => "login", :controller => "authenticate" %> &lt;/div> &lt;/div> &lt;div class="main" id="main"> &lt;%= yield %> &lt;/div> &lt;div class="sidebar" id="sidebar"> &lt;div id="bloglist"> &lt;div id="blogs-list-title">Blogs&lt;/div> &lt;% for blog in @blogs %> &lt;div class="blog-title">&lt;%= link_to h(blog.title), blog %>&lt;/div> &lt;% end %> &lt;/div> &lt;/div> &lt;div class="footer" id="footer"> &lt;/div> &lt;/body> &lt;/html> </pre> <p> The highlights are: <ul> <li>The use of &lt;%= controller.action_name %> to get the name of the action used to show this page</li> <li>&lt;%= stylesheet_link_tag 'general' %> to load a stylesheet, more than one can be specified</li> <li>The use if 'flash' to display messages</li> <li>The use of link_to to display URLs</li> <li>Access to data members from the controller (for blog in @blogs)</li> <li>The call to yield</li> </ul> </p> <p> It's the last one that's most interesting here. It's the call to yield that says 'take the default rendered output from the view and display it at this point in the page'. One thing to note here is that the view 'code' has already been executed at this point, i.e. the view template is rendered, that output is saved, then the layout is executed and the output from the template inserted into the layout. </p> <p> This layout is called 'blogslisting.html.erb' so is not the default layout for the blogs controller, this means that the code has to explicitly specify this layout to use. Like many things in Rails there is a great deal of flexibility in doing this. </p> <p> A global or default layout can be specified in app/controllers/application.rb , this contains the base class that all controllers derive from. A 'layout' declaration can be added In the class definition. </p> <pre name="code" class="brush: ruby"> class ApplicationController &lt; ActionController::Base layout "general" </pre> <p> A layout can also be specified per controller </p> <pre name="code" class="brush: ruby"> class BlogsController &lt; ApplicationController layout "blogslisting" </pre> <p> And this can be further overwritten on a per action basis. So if a given controller wants different layouts for each action it can have code something like this: </p> <pre class="brush: ruby"> def show @blog = Blog.find(params[:id]) respond_to do |format| format.html {render(:layout => "layouts/blog" )} format.xml { render :xml => @blog } end end </pre> <p> Where the code in the format.html block says to render with the layout with the 'layouts/blogs' layout file. </p> <p>This piece is already much longer than I though it would be so it's time to stop. There's more to be said about this, such as getting multiple content into the layout (multiple calls to yield), and sharing content with partial page templates. More on that soon.</p> http://blogs.mantiso.com/blog/kevin/2008/10/10/661B8FD80CC3D946393B9A3969ED8A1E http://blogs.mantiso.com/blog/kevin/2008/10/10/661B8FD80CC3D946393B9A3969ED8A1E Rails - Database Access <p>One of the driving forces of Rails is to make things easier for developers. It does this partly by taking decisions out of developers hands. It's an 'opinionated' framework, and one of the opinions it has is on the pattern to use for database access. Its choice in this case is the 'active record' pattern. </p> <p> Rails has an <span style="white-space: pre;font-family:monospace">ActiveRecord</span> module and the model classes all derive from</p> <pre class="brush: ruby"> ActiveRecord::Base </pre>for example <pre class="brush: ruby"> BlogEntry &lt; ActiveRecord::Base </pre> <p> it is this module that provides the active record support for the framework. </p> <p>Like much of the rest of Rails, ActiveRecord follows naming conventions. Here for example the BlogEntry class represents a row in the blog_entries table. How does this happen?</p> <p>Looking back to the <a href="/community/blogs/kevinj/archive/2008/09/25/learning-rails-part-2.aspx">Learning Rails - Part 2</a> post you will see that this script was run</p> <pre> script/generate scaffold blog_entry ... </pre> <p>This script created two files, the file with the model class BlogEntry definition and a "migration". The migrations are "scripts" that help create and mange the database definitions, essentially they are DDL for Rails.</p> <p>Migrations are used to both set up and tear down databases. The files contain class definitions that specify the steps to take when managing the database.</p> <p>Migrations are timestamped so that it is easy to apply migrations in the correct order and to rollback those migrations in reverse order if needs be. The migrations live in the db/migrate directory. Currently there are 4 migrations in there</p> <pre> 20080925064318_create_sessions.rb 20080925065056_create_blogs.rb 20080925064319_create_users.rb 20080925065210_create_blog_entries.rb </pre> <p>The first is a fairly standard Rails migration that creates the session tables (run <span style="white-space: pre;font-family:monospace;">rake db:sessions:create</span> to create this), the others are specific to this application. Each migration has a date-time as part of the file name and it's this name that determines the order in which the migrations are run. The 20080925065210_create_blog_entries.rb looks like this</p> <pre class="brush: ruby"> class CreateBlogEntries &lt; ActiveRecord::Migration def self.up create_table :blog_entries do |t| t.string :title, :null =&gt; false t.text :entry, :null =&gt; false t.integer :author_id, :null =&gt; false t.datetime :entry_added_date t.datetime :entry_last_edited t.timestamps end end def self.down drop_table :blog_entries end end </pre> <p>So it's a class that derives from <span style="white-space: pre;font-family:monospace;">ActiveRecord::Migration</span> and provides two class methods (static methods to C#/C++ folks), up and down (it's the "self" that indicates that these are class methods and not instance methods). You can run the migration from the command line by using the Rake command</p> <pre> rake db:migrate </pre> <p>This runs any migrations that have not yet been run. How does it know which migrations to run? Tthere is a database table that holds the information about the migrations that have been run.</p> <pre style="background-color:white; color:black; border: solid thin grey"> $ mysql -u root mysql> use rblog_development mysql> show tables; </pre> <p>shows something like</p> <pre style="background-color:white; color:black; border: solid thin grey"> +-----------------------------+ | Tables_in_rblog_development | +-----------------------------+ | blog_entries | | blogs | | schema_migrations | | sessions | | users | +-----------------------------+ </pre> <p>and</p> <pre style="background-color:white; color:black; border: solid thin grey"> mysql> select * from schema_migrations; +----------------+ | version | +----------------+ | 20080923152418 | | 20080923152427 | | 20080923152435 | | 20080925064318 | | 20080925064319 | | 20080925065056 | | 20080925065210 | +----------------+ </pre> <p>on my machine as I type this. Notice that the last entry in the table matches the datetime portion of the name of the last migration file.</p> <p>When a migration is run (assuming it has not yet been added to the database), then the <span style="white-space: pre;font-family:monospace;">self.up</span> method is executed. This method creates or modifies database entries. In the case of the blog_entries migration it creates the table and adds the eight columns from these five entries. <pre> (title, entry, author_id, entry_added_date, entry_last_edited and timestamps </pre> <p>mysql shows this</p> <pre style="background-color:white; color:black; border: solid thin grey"> mysql&gt; show create table blog_entries; +--------------+---------------------------------+ | Table | Create Table | +--------------+---------------------------------+ | blog_entries | CREATE TABLE `blog_entries` ( `id` int(11) NOT NULL auto_increment, `title` varchar(255) NOT NULL, `entry` text NOT NULL, `author_id` int(11) NOT NULL, `entry_added_date` datetime default NULL, `entry_last_edited` datetime default NULL, `created_at` datetime default NULL, `updated_at` datetime default NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 | +--------------+---------------------------------+ </pre> <p> Notice that timestamps turns into two columns, and that an id column has been added as a primary key </p> <p> A migration can also be rolled back. Running rake db:migrate <span style="white-space: pre;font-family:monospace;">rollback</span> will rollback the last migration, or a specific version can be specified. For example <span style="white-space: pre; font-family:monospace;">rake db:migrate VERSION=20080925065056</span> </p> <p> Running the migrations this way runs the migrations in reverse order up to the specified migration, on the way the <span style="white-space: pre;font-family:monospace;">self.down</span> mwthod of each migration is called. For the <span style="white-space: pre;font-family:monospace;">blog_entries</span> migration that would drop the table. The <span style="white-space: pre;font-family:monospace;">down</span> method should undo whatever the <span style="white-space: pre;font-family:monospace;">up</span> method did! </p> <p> One of the interesting (and frustrating) things about Rails is the way the migrations and the models work together. Running the <span style="white-space: pre;font-family:monospace;">script/generate scaffold blog_entry</span> creates two files, the migration and the model. Looking in the model file there is ... nothing, just the class definition. The knowledge about the members of this class is in the migrations. This takes DRY (Do Not Repeat Yourself) to the limit but it can mean looking in several files (there maybe more than one migration per model) to find everything that the class uses. If the migrations get too "spread out", i.e. there are three or more migrations with modifications to one table then it is worth amalgamating those migrations into one file. </p> <div class="posttagsblock"><a href="http://technorati.com/tag/Rails" rel="tag">Rails</a>, <a href="http://technorati.com/tag/Ruby" rel="tag">Ruby</a></div> http://blogs.mantiso.com/blog/kevin/2008/09/29/CE2DBB8D30F2FCAD052E6932F9A87645 http://blogs.mantiso.com/blog/kevin/2008/09/29/CE2DBB8D30F2FCAD052E6932F9A87645 Rails - Testing <p>Now that we have a Rails app up and running, all be it a simple one, it's time to think about testing. When you generate an application you also get a test structure created for us. This structure lets us create unit, functional and integration tests. Each kind of test has a different scope and I'll start, as we should, with unit tests.</p> <p> Looking in the test/unit directory there's a single ruby source file for each model created previously, each of these files looks like this </p> <pre name="code" class="brush: ruby"> class BlogEntryTest &lt; ActiveSupport::TestCase # Replace this with your real tests. def test_truth assert true end end </pre> <p> Pretty straightforward, assert that true is true. (If this is your first glance at Ruby code the first line says that BlogEntryTest derives from TestCase and the 'def' statement defines a method). </p> <p> Before running the test I create the test database </p> <pre> mysqladmin -u root create rblog_test </pre> <p> There are two ways (at least) to run this test, running </p> <pre> ruby -I test test/unit/blog_entry_test.rb </pre> <p> (-I test here includes the test directory in the search path) or </p> <pre> rake test:units </pre> <p> Running the first command line on my machine gives this: </p> <pre> Loaded suite test/unit/blog_entry_test Started E Finished in 0.033476 seconds. 1) Error: test_truth(BlogEntryTest): ActiveRecord::StatementInvalid: Mysql::Error: Table 'rblog_test.users' doesn't exist: DELETE FROM `users` </pre> <p> This shows us that the database tables don't exist. Running </p> <pre> rake db:test:prepare </pre> <p> fixes this and re-running the test now succeeds. </p> <pre> Started . Finished in 0.095619 seconds. </pre> <p> It's also possible to run </p> <pre> rake test:units </pre> <p> This will run all the unit tests </p> <pre> Started ... Finished in 0.056533 seconds. 3 tests, 3 assertions, 0 failures, 0 errors </pre> <p> Now that there's some confidence that the testing framework is in place it's time to start thinking about real tests. </p> <p> The user class represents a user of the system, either a user with a blog or a user posting comments. This user must have a username, email and password. The user class looks like this </p> <pre class="brush: ruby" name="code"> class User &lt; ActiveRecord::Base validates_presence_of :name validates_presence_of :email validates_uniqueness_of :email validates_confirmation_of :password validate :password_non_blank </pre> <p> This suggest some tests. Does the user have a name and email, is the emil unique and does the password have some data! The first test checks that the user is valid </p> <pre class="brush: ruby" name="code"> class UserTest &lt; ActiveSupport::TestCase def test_empty_user_is_invalid user = User.new assert !user.valid? assert !user.errors.empty? assert user.errors.invalid?(:name) assert user.errors.invalid?(:email) assert_equal "Missing password", user.errors.on_base end </pre> <p> The test creates a User then calls the valid? method (if you're new to Ruby the ? on the end of a method is part of the method name and indicates that the method returns a boolean, a ! on the end indicates that the method mutates data) . The test asserts that the user is not valid and then asserts that the appropriate errors have been added to the errors collection. </p> <p> The code has other tests for the user, checking that the password and password_confirmation match and that the password is not blank. There is also a test that a User is valid if all the fields are set correctly, none of these are shown here but the code is available <a href="http://www.mantiso.com/svn/rblog/trunk">here</a> not that there's much to see at the moment! </p> <p> The final test for the moment checks that the User must have a unique email. The code looks like this: </p> <pre class="brush: ruby" name="code"> def test_user_unique_email user = User.new(:name => "Test Name", :email => users(:kevin).email, :password => "wibble", :password_confirmation => "wibble") assert !user.save assert_equal "has already been taken", user.errors.on(:email) assert_equal ActiveRecord::Errors.default_error_messages[:taken], user.errors.on(:email) end </pre> <p> The thing of interest in this code is the line </p> <pre class="brush: ruby" name="code"> :email => users(:kevin).email, </pre> <p> This loads a fixture named :kevin. Fixtures are test data defined in a yml file (YAML Ain't a Markup Language) file. Fixtures have names and cen be loaded by name in the test code. The fixture looks like this: </p> <pre> kevin: email: kevin@test.com hashed_password: hash name: Kevin </pre> <p> The fixture data is loaded into the database, then the line 'users(:kevin).email' loads the fixture and gets its email value. This means that the test tries to save a user with the same email address as one that already exists, and that should fail. </p> http://blogs.mantiso.com/blog/kevin/2008/09/25/FBB6FE89C6289EA99E0A3B86558DB39D http://blogs.mantiso.com/blog/kevin/2008/09/25/FBB6FE89C6289EA99E0A3B86558DB39D Learning Rails - Part 2 <p>I wanted to make this a series about Rails and about Ruby. To that end I'm going to write a series of entries on building an MVC application. As I said in the previous post I am a Ruby and Rails neophyte, so I'll be learning as I go along, regard this as a developer's journal. The aim being that you can learn from the mistakes that I make. If this really gets going I also hope to do some screencasts along the way.</p> <p>What am I going to write - a blog of course (is there any other sort of web app out there today :) ). I chose blogging software because</p> <ul> <li>Everybody understands what a blog is, so no trying to figure out the behaviour</li> <li>It gives me a chance to play with different formats (html and RSS)</li> <li>At some point I'll need to write support for the various APIs (atom, etc)</li> <li>There'll be chances to use AJAX</li> <li>I can learn how to deploy to Apache</li> <li>It shouldn't take too long to get things going</li> </ul> <p>I'm going to rely heavily on the <a href="http://pragprog.com/titles/rails2/agile-web-development-with-rails">'Agile Development With Rails'</a> book, and hopefully any feedback I get. I'm learning Ruby at the same time as Rails and Ruby is a very idiomatic language, I know I'll get some of the idioms wrong, so again feedback is welcome. Oh and initially I'm doing this on MacBook using TextMate as the editor. At some point I'm going to play with NetBeans and Eclipse as tools and so try out JRuby, not that I like a challenge of learning 17 new things at once!</p> <h3>Start at the beginning. Go on the end and then stop, said the Red Queen</h3> <p>So the beginning of a Rails app is the code generator, to create the application I fire up a terminal make sure I'm in the right directory and call</p> <pre> rails rblog </pre> <p>This gives the well known directory structure of</p> <pre> app config db doc lib log public script test tmp vendor </pre> <p>Most of the time I'll be in the app directory (that's where the models, controllers and views are), but I'll also use stuff from the db directory where the 'migrations' are stored, in the public directory where public the web files are and in config, where various setup files live.</p> <p>Once the application has been created I can fire up another terminal (I usually have three open, one for my commands, one for the server and another to see the log file), change the the project directory and run the server with the command 'script/server'</p> <p>This starts the server on port 3000, the server I'm using here is Mongrel, you can also start WEBrick. There's plenty of discussion on these servers out on the web so I won't go into the differences here.</p> <p>Once the server is running you can point your browser at http://localhost:3000 and you should see something like:</p> <p><img src="http://www.pluralsight.com/community/cfs-file.ashx/__key/CommunityServer.Blogs.Components.WeblogFiles/kevinj/RailsHomePage.jpg" width="480" height="346" alt="RailsHomePage" /></p> <p>I'm going to use <a href="http://mysql.com">MySql</a> for the database and this needs to be configured. To do this I've edited config/database.yml to look like this:</p> <pre> development: adapter: mysql encoding: utf8 database: rblog_development username: root password: socket: /tmp/mysql.sock </pre> <p>Adding similar entries for test and production databases. Once that's done I created the development database</p> <pre> mysqladmin -u root create rblog_development </pre> <p>Now that all the necessary structure is in place I can create the first controllers and models. What do I know about the blog? I know it's going to have users, users can have blogs and blogs will have entries and comments. There may be more things eventually, such as tags, categories, pingbacks etc, but for now that's enough. So not to get too far ahead of myself I decided to create scaffolding for users, blogs and blogentries.</p> <p>For the users model I'm going to user a similar approach to that used in the Rails book, so the user will have an email address and password, the password will be stored as a hash will be salted. A user will have a name that can be displayed on comments or on a blog and users may also own blogs. For now I'm going to limit this to one blog per user, but in the future this may expand to multiple blogs.</p> <p>Running</p> <pre> script/generate scaffold user email:string hashed_password:string name:string blog_id:integer </pre> <p>gives me what I want. Doing something similar for blogs and blogentries</p> <pre> script/generate scaffold blog title:string sub_title:string owner_id:integer admin:boolean script/generate scaffold blog_entry title:string entry:text author_id:integer entry_added:datetime entry_last_edited:datetime </pre> <p>creates those models and their corresponding controllers and migrations.</p> <p>Notice that as in my previous post I'm using singular names for the model components, so user, blog and blog_entry.</p> <p>Now that's done it's then onto setting out some of the UI and writing some unit testing code.</p> <div class="posttagsblock"><a href="http://technorati.com/tag/Rails" rel="tag">Rails</a>, <a href="http://technorati.com/tag/Ruby" rel="tag">Ruby</a></div> http://blogs.mantiso.com/blog/kevin/2008/09/22/443058CE64B2D084AF604C516EEDDFF8 http://blogs.mantiso.com/blog/kevin/2008/09/22/443058CE64B2D084AF604C516EEDDFF8 Learning Rails - Part 1 <p>I've been looking at Ruby and Rails for a long time, when I say looking at here what I really mean is staring through the glass and wondering what the fuss was about. Now that I finally have a MacBook I decided to actually sit down and learn Rails and Ruby at the same time. This means that on my hour long commute to and from my current contract I'm writing web code, and much fun it is. The commute is split over two trains so each part is about 30 minutes which gives me a very fractured learning experience but I'm still getting something done.</p> <p>I wanted to use the web app I'm working on (it's only a toy) as a learning tool. This means that a) I wanted to minimize the new concepts and b) not be led by the hand too much. Because of that I decided that I would initially not use <a href="http://api.rubyonrails.org/classes/ActionController/Resources.html">REST based routing</a> as I would need to understand more about REST and using the built in routing would hide the routing system from me. So taking my routes in hand I initially did things the 'hard' way (actually, it's not that hard)</p> <p>I finally figured that I knew enough to then try the RESTian approach, so firing up my trusty console, and TextMate I tried adding a new controller and model to the application.</p> <p>I ran a command, something like,</p> <pre>script/generate scaffold foo<br /></pre> <p>then ran </p> <pre>rake db:migrate</pre> <p>pointed the browser at http://localhost:3000/foos and everything seemed good. I added a new foo, life was good. Then I tried to browse to http://localhost:3000/foo/1 and I get an error: </p> <pre>Unknown action No action responded to 1 </pre> <p>After much Googling and running of</p> <pre>rake routes<br /></pre> <p>I couldn't find an answer. </p> <p>Eventually after much re-reading of the routing chapter in <b><a href="http://pragprog.com/titles/rails2/agile-web-development-with-rails">The Book</a></b> something must have lodged in my head and I decided to kill the web server and restart it, and suddenly the routes started working. The moral is "you do sometimes need to re-start the rails web server"!</p> <p>The second issue was even more stupid. After fix the above problem, and getting my head more around the REST idea I decided I needed a bunch of controllers, so I duly run</p> <pre>script/generate scaffold bars<br /></pre> <p>restart the server and immediately get strange errors along the lines of </p> <pre>undefined method `edit_bars_result_path' for #&lt;ActionView::Base:0x255a508&gt;<br /></pre> <p>eh! </p> <p>Rails experts will be laughing right now, or thinking 'been there, done that.' Rails adopts naming conventions, in this case models and controllers are singular. RESTian routing is based around the ideas of things and collections of things, the things are singular and the collections are plural. I tried to generated things that were already plural (bars), and the RAILs pluralization had no idea what to do with it, so the naming broke (at least that's what I think happened :) )</p> <div class="posttagsblock"><a href="http://technorati.com/tag/Rails" rel="tag">Rails</a>, <a href="http://technorati.com/tag/Ruby" rel="tag">Ruby</a></div> http://blogs.mantiso.com/blog/kevin/2008/05/04/More-Ubuntu-Settings http://blogs.mantiso.com/blog/kevin/2008/05/04/More-Ubuntu-Settings More Ubuntu Settings I was going to call this entry "More Ubuntu Woes" and maybe I should have. <p> Ubuntu makes certain things that should be difficult, easy and some things that should be easy, difficult, like assigning keys to commands. I'm a keyboard jockey, I'm way happier using the keyboard than the mouse> I tell my self this is because the keyboard is quicker, but it's probably because I cut my teeth in the days before mouse, and and in Emacs where key chords are king! </p> <p> This means I am lost without my keyboard shortcuts, in Windows such things as W+L to lock (where W is the Windows key). I use Windows a lot, and if I'm using Ubuntu I'd like the same keys to work. This should be easy, however it appears that having Compiz enabled, Compiz and Gnome clash!. Gnome has dialogs to set up keybindings, but you have to jump through hoops to get it to work. </p> <p> First hoop is getting Ubuntu to recognise the Windows key (called the Super key in Linux) as a key modifier, like Control and Alt. To do this go to System..Preferences..Keyboard, select the Layouts tab and then Layout Options. From here select Alt/Win key behavior and then choose "Super is mapped to the Win-keys" </p> <p> Once you've done this you can now edit the Gnome keyboard preferences. From System..Preferences..Keyboard Shortcuts, scroll down to Desktop. Here you can click on the "Show the panel run application dialogue", select this and hit WindowsKey + r on the keyboard. Do the same for Run a terminal, but select WindowsKey + t. You may think you can do the same thing for the Search, Home Folder and Lock screen commands (assign them to Windows + f, Windows + e and Windows +l respectively), however, those commands cannot be assigned from here and if you try, not only will the commands not work but you may have trouble re-assigning the keys elsewhere. Instead to assign these key you will need to you the Compiz Configuration Manager </p> <p> Select System..Preferences..Advanced Desktop Effects Settings. In the dialog box select General and then Commands. I have my first three commands set to "beagle-search", "nautilus" and "gnome-screensaver-command --lock" respectively and the key bindings set to <Super>f, <Super>e and <Super>l. And this all works. </p> <p> There's more <a href="https://bugs.launchpad.net/gnome-control-center/+bug/12153">here</a> on this. </p> <p> Now, if only I can get Ctrl+Esc to bring up the main menu! </p> http://blogs.mantiso.com/blog/kevin/2008/05/01/CruiseControl-Net http://blogs.mantiso.com/blog/kevin/2008/05/01/CruiseControl-Net CruiseControl.Net <p> I'm working with CruiseControl.net this week. First time I've worked with the product and I'm finding a couple of issues (that are all my mistakes) but that aren't particularly well documented. So this is as much for my benefit as anything else. </p> <p> Firstly, last night after editing the config file I couldn't get the build to run. Now, there are several config files. in c:\Program Files\CruiseControl.NET\server, the main one is the ccnet.config file, this is the default location for this file, that location can be changed, to do that you'd edit the ccservice.exe.config file. </p> <p> The ccservice.exe.config file is re-read when the CCNet service is (re)started, as is the ccnet.config file. When you edit the ccnet.config file it appears that the service does re-read the file, however, if the file is invalid the service ignores it, and doesn't appear to log this fact anywhere. Re-starting the service will force a re-read of the config file and then log an error if the file is invalid. </p> <p> I was changing a CCNet config file to do multiple checkouts, after a bit of trial and error the source control section of the file ended up looking like this <pre> &lt;sourcecontrol type="multi"> &lt;sourceControls autoGetSource="true" applyLabel="true"> &lt;vsts autoGetSource="true" > &lt;server>http://server:8080&lt;/server> &lt;project>$/FOO/SharedUILibraries&lt;/project> &lt;username>user&lt;/username> &lt;password>user&lt;/password> &lt;domain>nt&lt;/domain> &lt;workingDirectory> C:\...\FOO\SharedUILibraries &lt;/workingDirectory> &lt;cleanCopy>true&lt;/cleanCopy> &lt;workspace>WS_MINE&lt;/workspace> &lt;deleteWorkspace>true&lt;/deleteWorkspace> &lt;/vsts> &lt;vsts autoGetSource="true" > &lt;server>http://server:8080&lt;/server> &lt;project>$/FOO/SharedEnterpriseLibrary&lt;/project> &lt;username>user&lt;/username> &lt;password>user&lt;/password> &lt;domain>nt&lt;/domain> &lt;workingDirectory> C:\...\SharedEnterpriseLibrary &lt;/workingDirectory> &lt;cleanCopy>true&lt;/cleanCopy> &lt;workspace>WS_MINE&lt;/workspace> &lt;deleteWorkspace>true&lt;/deleteWorkspace> &lt;/vsts> &lt;vsts autoGetSource="true" > &lt;server>http://server:8080&lt;/server> &lt;project>$/FOO/WD&lt;/project> &lt;username>user&lt;/username> &lt;password>user&lt;/password> &lt;domain>nt&lt;/domain> &lt;workingDirectory> C:\...\FOO\WD &lt;/workingDirectory> &lt;cleanCopy>true&lt;/cleanCopy> &lt;workspace>WS_MINE&lt;/workspace> &lt;deleteWorkspace>true&lt;/deleteWorkspace> &lt;/vsts> &lt;/sourceControls> &lt;/sourcecontrol> </pre> And this worked, however there was one gotcha. </p> <p> Before getting this to a working stage I was getting a status in the CCNet dashboard of CheckingModifications, whatever I did I'd get this status, even forcing a build wouldn't change it. It turned out the reason for this was that I had put the wrong name in the project element. This meant that CCNet was trying to look for bits that didn't exist, and sat there spinning its wheels. Once corrected everything worked fine. </p> <p> So if you get the CheckingModifications status, check that your source control settings are correct and that you can do a checkout </p> http://blogs.mantiso.com/blog/kevin/2008/03/26/LINQ-Nasties http://blogs.mantiso.com/blog/kevin/2008/03/26/LINQ-Nasties LINQ Nasties This was raised on an internal mailing list by <a href="http://staff.develop.com/ballen/blog/">Brock Allen</a>, and as he isn't blogging much (not that I can comment) I thought I'd raise it here. <p> Look at this query: </p> <pre> NorthwindDataContext db = new NorthwindDataContext(); db.Log = Console.Out; var supp = (from s in db.Suppliers select s).FirstOrDefault(); var prods = from p in supp.Products where p.UnitsInStock > 10 select p; foreach (var p in prods) { Console.WriteLine(p.ProductName); } </pre> <p> Looks pretty harmless, get a supplier, then get the products fromt that supplier where the UnitsInStock > 10. </p> <p> Problem is if yuou run this, you see the following in SQLProfiler </p> <pre> exec sp_executesql N'SELECT TOP (1) [t0].[SupplierID], [t0].[CompanyName], [t0].[ContactName], [t0].[ContactTitle], [t0].[Address], [t0].[City], [t0].[Region], [t0].[PostalCode], [t0].[Country], [t0].[Phone], [t0].[Fax], [t0].[HomePage] FROM [dbo].[Suppliers] AS [t0] WHERE [t0].[SupplierID] = @p0',N'@p0 int',@p0=1 exec sp_executesql N'SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued] FROM [dbo].[Products] AS [t0] WHERE [t0].[SupplierID] = @p0',N'@p0 int',@p0=1 </pre> <p> The first statement is executed when you call FirstOrDefault(), the second when you execute the foreach. Notice anything about the statements? They are almost exactly the same, except the second statement loses the TOP(1) part. This means that the where clause is happening on the client! Not a big deal you may think, unless of course the select returns 1000s of rows. </p> <p> Fixing this is easy </p> <pre> var prods = from p in db.Products join s in db.Suppliers on p.SupplierID equals s.SupplierID where s.SupplierID == 2 && p.UnitsInStock > 10 select p; </pre> <p> which gives: </p> <pre> exec sp_executesql N'SELECT [t0].[ProductID], [t0].[ProductName], [t0].[SupplierID], [t0].[CategoryID], [t0].[QuantityPerUnit], [t0].[UnitPrice], [t0].[UnitsInStock], [t0].[UnitsOnOrder], [t0].[ReorderLevel], [t0].[Discontinued] FROM [dbo].[Products] AS [t0] INNER JOIN [dbo].[Suppliers] AS [t1] ON [t0].[SupplierID] = ([t1].[SupplierID]) WHERE ([t1].[SupplierID] = @p0) AND ([t0].[UnitsInStock] > @p1)',N'@p0 int,@p1 int',@p0=2,@p1=10 </pre> <p> Which is probably what you want. </p> <p> I like LINQ, especially LINQ to XML, but this reminds of the dark days of EJB Entity Beans. You really have to profile the generated code to understand exactly what LINQ is giving you, don't be seduced by the ease of use. </p> <p> <b>Update</b> </p> <p> Ian Griffith pointed this out: </p> <p> "One subtlety with your LINQ Nasties post is that you kind of make it look like the solution is to use one query instead of two. In fact, the key is understanding which operations will evaluate the query and which won't." </p> <p> And he's dead right, Ian's blogged about this <a href="http://www.interact-sw.co.uk/iangblog/2007/09/10/linq-aggregates ">here</a>. Even if you don't read Ian's full post, read the "Know Your Tools" section at the end. </p> http://blogs.mantiso.com/blog/kevin/2008/03/20/ASP-Net-Page-XXX-events http://blogs.mantiso.com/blog/kevin/2008/03/20/ASP-Net-Page-XXX-events ASP.Net Page_XXX events In ASP.Net the engine looks for various methods to call to handle events such as <pre> public void Page_Load(object sender, EventArgs e) {} </pre> I had always assumed that the framework searched for these methods based on their full signature, turns out this isn't the case. The ASP.Net MVC framework uses a <pre> public void Page_Load() {} </pre> method, and I was trolling through the code trying to find where this is called from, when I ended up inside the Page ProcessRequest method, i.e. the default ASP.net processing. Which meant there was no special processing for this version of Page_Load. <p> I quickly create a bog standard web app and added a no parameter Page_Load to it, and sure enough it fires! </p> <p> Note that if you have the parameterised and no parameter Page_Load only the parameterised one is called. </p> http://blogs.mantiso.com/blog/kevin/2008/03/20/Good-Things-With-MVC http://blogs.mantiso.com/blog/kevin/2008/03/20/Good-Things-With-MVC Good Things With MVC I've just started playing with ASP.NET MVC (or Microsoft's Homage to Ruby on Rails as Tim Ewald labelled it!), it's good to see a <a href="http://www.codeplex.com/MVCContrib">community</a> growing up around this. http://blogs.mantiso.com/blog/kevin/2008/03/20/Upgrading-SQL-Server http://blogs.mantiso.com/blog/kevin/2008/03/20/Upgrading-SQL-Server Upgrading SQL Server <p> As a developer I constantly use Visual Studio and SQL Server, and it turns out thatn when you install these, the install order is important. If you install SQL Server before VS200x then you get all the SQL tools such as the Management Studio and the Profiller. However, if you install VS200x and then install SQLServer the tools do not get installed. This has annoyed and frustrated me for years, then I discovered it wasn't just me, other people were having the same problem. </p> <p> If only I'd read the warnings! </p> <p> This week when I was going through the process again, having already installed VS200x I paid attention to what the SQL Server installation was telling me. When you install SQLServer it goes through a systems check to make sure you are able to install the software, things such as how much memory you have, whether you have IIS etc. One of the warnings I got was an "Edition Change Check (Warning)". Normally I ignore this as it's only a warning. But this time I took notice </p> <p> The warning says <blockquote> To change an existing instance of Microsoft SQL Server 2005 to a different edition of SQL Server 2005, you must run SQL Server 2005 Setup from the command prompt and include the SKUUPGRADE=1 parameter. </blockquote> and this time I did take notice. I fired up a command prompt, flipped to the Servers directory and ran <pre>Setup SKUUPGRADE=1</pre> and joy of joys all the tools appear as part of the install. </p> <p> Of course, the annoying thing is, why doesn't the installer do this. It's detected the problem, one little 'Do you want to upgrade?' checkbox wouldn't have hurt anybody! </p> </p> http://blogs.mantiso.com/blog/kevin/2007/10/21/Ubuntu-Suspend http://blogs.mantiso.com/blog/kevin/2007/10/21/Ubuntu-Suspend Ubuntu Suspend Suspend was was working in Feisty but when I updated to 7.10 (Gutsy) it stopped. When I resumed all I'd get a blank screen. <p> <a href="http://koon.fr/wiki/suspend_to_ram_on_the_dell_d820_proprietary_nvidia_drivers_under_ubuntu_gutsy">This post</a> seems to have fixed things for me. </p> <p> Having played with these settings it looks like I only need <br/> POST_VIDEO=false <br/> from the <br/> /etc/defaults/acpi-support <br/> file </p>. http://blogs.mantiso.com/blog/kevin/2007/10/05/Books-Ive-Read-Recently http://blogs.mantiso.com/blog/kevin/2007/10/05/Books-Ive-Read-Recently Books I've Read Recently Somebody was asking about books on an in internal DevelopMentor listserver. <p> This is a list of recent books that I've read (and these are just the ones within the last three months) </p> <p> <ul> <li><a href="http://en.wikipedia.org/wiki/Revelation_Space">Revelation Space</a> series by Alastair Reynolds. Hard Science Fiction. First two books are great, the third was slightly disappointing.</li> <li><a href="http://en.wikipedia.org/wiki/Harry_Potter_and_the_Deathly_Hallows">Harry Potter an the Deathly Hallows</a> I'm sure you all know this one. It's unremittingly dark</li> <li><a href="http://en.wikipedia.org/wiki/Slaughterhouse_5">Slaughterhouse5</a> by Vonnegut</li> <li><a href="http://en.wikipedia.org/wiki/Rory_Stewart">Occupational Hazards</a> by Rory Stewart. Required reading if you're interested in Iraq and what will happen there</li> <li>Salmon Fishing in the Yemen. Because I'd run out of books on holiday, and yes, it is a novel, and it's actually quite good.</li> <li><a href="http://en.wikipedia.org/wiki/God_is_not_great">God is not Great</a> by Christopher Hitchens. For all us non-believer's out there.</li> <li>This Book Will Save Your Life. Another Novel. Get the doughnuts instead!</li> <li><a href="http://en.wikipedia.org/wiki/A_Short_History_of_Tractors_in_Ukrainian">A Short History of Tractors in Ukranian</a> by Maria Lewycka. Very funny. You'll like all the characters by the end</li> <li><a href="http://en.wikipedia.org/wiki/The_Life_and_Times_of_the_Thunderbolt_Kid">The Life and Times of the Thunderbolt Kid</a> by Bill Bryson. This is laugh-out-loud funny. If you haven't read it, treat yourself and go and buy it. On holiday I read it, my wife read it and the kids read it.</li> </ul> And that was just on holiday Since then it's been <ul> <li><a href="http://en.wikipedia.org/wiki/Exit_Music">Exit Music</a> by Ian Rankin. Crime fiction at its best</li> <li><a href="http://en.wikipedia.org/wiki/Making_Money">Makng Money</a> by Terry Pratchet (say no more)</li> <li><a href="http://en.wikipedia.org/wiki/Iwoz">iWoz</a> by Steve Wozniak</li> </ul> </p> http://blogs.mantiso.com/blog/kevin/2007/10/05/IgNobels http://blogs.mantiso.com/blog/kevin/2007/10/05/IgNobels IgNobels The IgNobels were <a href="http://news.bbc.co.uk/1/hi/sci/tech/7026150.stm">awarded this week</a> <p> I especially loved this one: </p> <p> <blockquote> <b>Literature</b> - Glenda Browne of Blue Mountains, Australia, for her study of the word "the", and how it can flummox those trying to put things into alphabetical order. </p> </blockquote> <p> Sounds like the sort of thing Douglas Adams or Terry Pratchet would write. </p>