<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-12773241</id><updated>2012-01-22T14:56:31.191-08:00</updated><title type='text'>Matt Adamson</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-12773241.post-7242160794264608892</id><published>2009-11-09T13:52:00.000-08:00</published><updated>2009-11-09T14:32:49.555-08:00</updated><title type='text'>Building a mercurial external hook to update Target Process</title><content type='html'>&lt;div&gt;Whilst learning the new &lt;a href="http://mercurial.selenic.com/"&gt;Mercurial&lt;/a&gt; Distributed Version Control system ( DVCS ) I thought it would be useful exercise to learn about hooks by writing one.  There are two types of hooks you can use, either an in process hook which executes with the hg process or an external hook which is executed as a separate process by hg, the core mercurial process. I wanted to develop a hook which integrates with &lt;a href="http://www.targetprocess.com/"&gt;Target Process&lt;/a&gt; to update a specific entity with the changeset comment if the comment referred to it e.g. a comment such as&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;TP#23000 Resolved issue with print manager crashing on XP&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;would update bug 23000 with this comment. The &lt;a href="http://mercurial.selenic.com/guide/"&gt;mercurial definitive guide&lt;/a&gt; recommends using  an external hook if your not familiar with python and performance isn't critical. Given my python experience is non existent I created a NET console applicaiton to perform the work. The application interacts with the hg process to obtain changeset information and uses WSE 3.0 web service calls to the target process API to retrieve and update the entities. The important parts of the process are as follows&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Environment variables passed to the hook process define useful information such as the path to the hg process. However also the parameters to the hook are passed by using a variable with the suffix HG_ followed by the variable name e.g. HG_NODE contains the changeset identifier.&lt;/li&gt;&lt;li&gt;The changeset identifier passed to the hook as the env variable HG_NODE is used to execute the hg process with the log command to extract the description of the changeset. This uses the -template option  to control the specific output of the log command.  When calling the hg process the console output is redirected to a string so the contents can be captured.&lt;/li&gt;&lt;li&gt;The captured changeset description is then parsed to determine whether it matches a TP entity using a regular expression. If the changeset references a TP entity the TP web service methods are called to obtain the entity and update it with the comment.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Although this doesn't provide a feature rich hook similar to the packaged &lt;a href="http://www.bugzilla.org/"&gt;bugzilla&lt;/a&gt; hook, it does provide you few useful features and enough information to build your own external hook. You may wish to change this implementation i.e.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Only bugs are currently supported however it shouldn't be hard to add support for task / story ids. &lt;/li&gt;&lt;li&gt;The bug status entity is currently obtained using a fixed process name "All Practises" however this could be obtained from the entities related projects related process.&lt;/li&gt;&lt;li&gt;Customising the text added to the TP bug through some kind of template.&lt;/li&gt;&lt;li&gt;Mapping TP users to mercurial users. Currently the user credentials are taken from the config file.  &lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;The hook must be installed by adding the following line to mercurial.ini&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;i&gt;[hooks]&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;commit.TPMercurialHook = TPMercurialHook.exe&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.targetprocess.com/"&gt;Target Process&lt;/a&gt; actually supports a plug in model for a number of different SC repositories e.g. one for TFS, which work by continually running and polling the repository for changes. Mercurial hooks work by intercepting events in the repository immediately whereas the plug in model polls for changes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The code for the hook can be downloaded &lt;a href="http://cid-45c8f396c6b26c3a.skydrive.live.com/embedicon.aspx/Development/TPMercurialHook.zip"&gt;here&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-7242160794264608892?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/7242160794264608892/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=7242160794264608892' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/7242160794264608892'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/7242160794264608892'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2009/11/building-mercurial-external-hook-to.html' title='Building a mercurial external hook to update Target Process'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-383262417857986651</id><published>2008-12-20T08:02:00.000-08:00</published><updated>2008-12-20T11:53:29.464-08:00</updated><title type='text'>Enterprise Windows Workflow Foundation Development Part II</title><content type='html'>Over the last week I’ve changed from using the manual thread scheduling service to the default CLR thread pool based one. Some of the techniques I &lt;a href="http://mattadamson.blogspot.com/2008/11/enterprise-windows-workflow-foundation.html"&gt;mentioned before &lt;/a&gt;have been updated in this post and also a few new items discussed&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Exception handling&lt;/li&gt;&lt;li&gt;Workflow performance&lt;/li&gt;&lt;li&gt;Workflow custom tracking service for state mapping&lt;/li&gt;&lt;li&gt;Unit testing&lt;/li&gt;&lt;li&gt;WF design&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;strong&gt;Exception handling&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Using the default thread scheduling service and checking a LastExceptionRaised property from a local service to check exceptions simply will not work now. As the WF execution is performed asyncronously in all cases the property will simply be null when checked straight after calling a WF local service method. Only some time later when the WF thread is scheduled will this property be set.&lt;/p&gt;&lt;p&gt;The best approach I've found to handle this case is to firstly log all exceptions passed to your local service property setter when the WF fault handler kicks in. You can use the &lt;a href="http://msdn.microsoft.com/en-us/library/cc512464.aspx"&gt;enterprise libraries&lt;/a&gt; HandleException method or something similar depending on what logging framework you use. This ensures the rich detailed exception information, including all inner exceptions and their stack traces, is captured and logged.&lt;/p&gt;&lt;p&gt;You should also manage a collection of exceptions within the local service to ensure you don’t miss any e.g. if two WF threads raise exceptions at a similar time. To handle the exceptions you will to create a timer which periodically checks whether any exceptions exist in the collection and simply throws the first exception in the list. This can then be caught and handled/ logged / rethrown in your application depending on the exception handling policies defined. You need to use a timer to check the exception and re throw otherwise the workflow would terminate if an exception re thrown on the WF thread.&lt;/p&gt;&lt;p&gt;In terms of "handling" unexpected exceptions, our application uses the AppDomain UnhandledException filter which processes the exception and uses the “Unhandled Exception” enterprise library policy to define the handling. By default we configure this policy to log the exception to the event log and presents the user with a friendly dialog that a serious issue has occurred ( well about as friendly as an unexpected dialog type window can appear )&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Workflow performance&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;In some scenarios you may have many workflows which continually load / unload e.g. if they are triggered by a delay activity. If the delay activity is relatively short e.g. few minutes and you have a few hundred WF's you may find the WF runtime spending most of it's time loading / unloading WF's. There are a few approaches you could take&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Develop a customised persistence service and override the UnloadOnIdle method e.g. you might customised SqlWorkflowPersistence. In there you could put some custom logic to only unload some workflows. E.g. you might not unload workflows which are in a state with logic driven by a DelayActivity.&lt;/li&gt;&lt;li&gt;Don’t set UnloadOnIdle to true in the constructor of the persistence service and in the WorkflowIdled event you can decide if a workflow should be unloaded using similar rules as in 1.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In relation to diagnosing general WF performance issues I highly recommend reading &lt;a href="http://msdn2.microsoft.com/en-us/library/Aa973808.aspx"&gt;Performance Characteristics of Windows Workflow Foundation&lt;/a&gt;. There are a variety of useful WF performance counters you can use to inspect your running WF host to avoid second guessing where any bottlenecks might be. As always good detailed analysis is essential so you really are tuning the least performant parts of your app and not those you most like to tinker with :)&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Workflow custom tracking service for state mapping&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The original approach &lt;a href="http://mattadamson.blogspot.com/2008/11/enterprise-windows-workflow-foundation.html"&gt;I mentioned&lt;/a&gt; works by mapping the current state to the workflow state in the workflow idle event, however this has the following implications.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The StateMachineWorkflowInstance class can be expensive to construct every time your workflow idles.&lt;/li&gt;&lt;li&gt;The change of status in the state machine may not be immediately reflected in your entities mapped state. i.e. some time passes between entering a specific state and the workflow idling e.g. if performing some work in a StateInitializationActivity within that state the workflow will not idle until the StateInitializationActiviy has completed.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Matt Milner wrote an excellent article on &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163466.aspx"&gt;tracking services&lt;/a&gt; and presents one which tracks state changes in a state machine activity. As soon as a new state activity starts executing the tracking service is called. I’ve adapted this service so it fires an event on a state change which a local service responds to by mapping the current state to an enumerated status value. The status of the WF state machine and status in the entities record are now immediately in sync with each other&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Unit testing&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;There are many excellent articles on unit test approaches to WF i.e. Matt &lt;a href="http://msdn.microsoft.com/en-us/magazine/dd179724.aspx"&gt;wrote one&lt;/a&gt; and Cliffard has also produced an &lt;a href="https://www.microsoft.com/resources/virtuallabs/step1-msdn.aspx?LabId=c4a993a5-d498-4d5c-9f98-476c1f496d15&amp;amp;BToken=reg"&gt;excellent lab&lt;/a&gt; on applying TDD with WF. Two important points when creating tests to add to these articles.&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Always try and refactor logic within activities / workflow into separate components and test them in isolation first. Keep the minimal amount of code in your activity. It’s fine for an activity to simply provide a simple façade around an existing service. If you adopt a TDD approach you would actually find yourself more likely to write those services first, and thus make the activities easier to test using mock objects.&lt;/li&gt;&lt;li&gt;Use IOC mechanisms such as dependency injection so you can mock most of the objects your workflow / activities use. This means your tests can focus as much as possible on testing just the activity or workflow class and not many other dependent classes.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In testing a state machine I’d like to test everything about the model I’ve created i.e. the start state / completed states, possibles transitions from each state and assert any rules embedded within the workflow are evaluated, and ensure ALL activities end up being executed and covered. This is very important when you have many IfElse branch activities in your workflow based on rules. The last thing you want to do is change a condition within a branch only to find the branches beneath it can never be reached :(&lt;/p&gt;&lt;p&gt;&lt;strong&gt;WF Design&lt;/strong&gt; &lt;/p&gt;&lt;p&gt;One thing I’ve found out over the last month working on WF is the vast number of approaches there are to implement any given design. WF is highly extensible, both in the new services you can plug in and existing services that can be customised using standard mechanisms such as inheritance / events / overriding methods.&lt;/p&gt;&lt;p&gt;What ever approach you choose it’s important you try and fit within the WF framework as much as possible. It’s up to you how little or much of your workflow logic you decide to implement in WF. Even if you don’t think your design is ideal and doesn’t feel right I would encourage you to simply start and be prepared to refactor as you learn more about WF.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-383262417857986651?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/383262417857986651/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=383262417857986651' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/383262417857986651'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/383262417857986651'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2008/12/enterprise-windows-workflow-foundation.html' title='Enterprise Windows Workflow Foundation Development Part II'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-3223753893269610552</id><published>2008-12-06T20:30:00.000-08:00</published><updated>2008-12-06T20:30:00.588-08:00</updated><title type='text'>Enterprise Windows Workflow Foundation Development</title><content type='html'>&lt;p&gt;It's nearly a year ago since I blogged about some of the &lt;a href="http://mattadamson.blogspot.com/2007/08/window-workflow-foundation-new-way-to.html"&gt;really cool features of WF&lt;/a&gt; and it's only recently I've had an opportunity to apply this technology in my day job. Although other projects I've worked on until now could have used WF equally well, they were simply too large and complex to refactor WF in easily. However they would have been a great candiate to use WF from the start as they use complex hierarchical state machines for which the logic is unfortunately littered throughout the application.&lt;/p&gt;&lt;p&gt;My previous WF projects were simply for my own learning ( aiming for an &lt;a href="http://www.microsoft.com/learning/en/us/exams/70-504.mspx"&gt;MCP&lt;/a&gt; qualification eventually ) and although I covered a lot of different areas of WF, it's only through developing a production application I've come across areas that needed to be reviewed further. e.g.&lt;/p&gt;&lt;li&gt;Workflow authoring mode - Out of the three options which is the most appropriate&lt;/li&gt;&lt;li&gt;Unhandled exceptions in the workflow . Exceptions need to be logged by the host and in some cases we want to avoid termination of the workflow&lt;/li&gt;&lt;li&gt;Querying workflow state - It is often not feasible to simply load every workflow to query it's state.&lt;/li&gt;&lt;li&gt;Dependency injection - How can types be resolved &lt;/li&gt;&lt;li&gt;Dynamic updates - Useful for simple customisation&lt;/li&gt;&lt;li&gt;Associating business objects with workflow instances &lt;/li&gt;&lt;li&gt;Runtime scheduling service - Is the default service always appropriate&lt;/li&gt;&lt;li&gt;Workflow runtime and instance wrapper classes&lt;/li&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Workflow authoring mode&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Although there are three authoring modes to choose from code, code with separation, and no code, visual studio only lets you choose you the first two. All the guidance on this mentions you should evaluate how much flexibility the end user requires to change activities and workflows. Based on this advice though I found it hard to choose an appropriate model. On the one hand we should keep our applications as simple as possible right now based on our requirments, however on the other hand we need to design to make future changes easier :). &lt;/p&gt;&lt;p&gt;I actually think the no code authoring mode is probably the preferred route as it encourages developing good practises i.e. building your activities upfront and then building your workflow around them being clear to separate the rules and the binding of properties between activities as separate tasks. However given the poor tool support in VS 2008 and also 2010 for no code workflows I find it hard to recommend. If you really can't perceive a need for this level of flexibility i.e. hosting the designer and allowing users to change the workflow, then it maybe overkill. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Note if you do choose a code only route and want to move to code separation it is possible with a bit of work. Simply copy all activities within the designer and then paste into a workflow with code separation. This will created the XOML and then you can add all code activities in as required.&lt;/p&gt;&lt;p&gt;For the project I worked on I applied the code separation model which seems to be no more complex to manage than the code only model, but at least provides some flexibility. The workflow and rules could be modified relatively easily by hosting the designers and new workflow types compiled as required. &lt;/p&gt;&lt;p&gt;&lt;strong&gt;Exception handling&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;It's inenvitable your application will have some bugs no matter how hard you try and in this case it's important that the application ( or more specifically a data store ) maintains it's integrity so users can continue using the system. It's also important to capture these exceptions and log them appropraite e.g. we use enterprise library 4.0 which provides rich support to log exceptions. &lt;/p&gt;&lt;p&gt;The default behaviour for unhandled exceptions is to terminate the workflow which also has the effect of removing the workflow from the persistence store. However if your using a state machine which is currently in one of states you may not wish to terminate the workflow abruptly. If the workflow ends you would have to create a new workflow and start the state machine in the same state perhaps and also ensure workflow properties were set correctly. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;In our project we managed this by setting up fault handlers in nearly every state which could throw an exception. ( it was acceptable for the first state state to throw an exception and terminate the workflow ). In this fault handler we always handle the generic Exception type and when the exception is raised a local service method is called on the host application which passes the Exception object. The host application can then perform any necessary action e.g. transitioning to a failed state , logging the exception and in most cases presenting the user with an exception has occurred type window. Now we should have good information to diagnose this exception further and the state of the workflow is maintained. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Querying workflow state&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;There are many mechanisms to query the workflow state e.g. from &lt;a href="http://msdn.microsoft.com/en-us/library/system.workflow.activities.statemachineworkflowinstance.aspx"&gt;StateMachineWorkflowInstance&lt;/a&gt; there are properties such as CurrentState / PossibleStateTransitions which provide you with a "picture" of the workflow state. However this does require the workflow to be loaded to obtain this state. For many applications it wouldn't be feasible to load all workflow instances just to find out which workflows are in a specific state. It also doesn't lend itself well to standard querying techniques used on a data store e.g. select all invoices from a table which are in state x &lt;/p&gt;&lt;p&gt;Most application entities typically contain a state column which usually maps to an enumerated value defined in the application e.g. InvoiceState with values New, Awaiting Approval / Approved. It would be nice if we could still use this state column to filter out the records were interested in, but at the same time use the workflow instance to drive the workflow, determining possible state transitions / events that can be raised e.t.c. My first thought was to use a custom tracking service to track the changes to the state machine and report them back to the host application which could then update the state column of the related entity to reflect the current state. This way both the workflow instance and state column would always be in sync.&lt;/p&gt;&lt;p&gt;However after creating a custom tracking service to do this I found the excellent &lt;a href="http://msdn.microsoft.com/en-gb/magazine/cc163466.aspx"&gt;article&lt;/a&gt; Matt has written on tracking services which also builds a similar service for tracking state machines, well at least I'd learnt tracking services well :) . I then found a much simpler solution which works well and doesn't require the use of tracking services. In the workflow idle event the current state can be checked from the StateMachineWorkflowInstance wrapper class and then the related entitiy updated. This works well because the workflow always idles between transitioning to new states.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Dependency Injection&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Dependency injection / service locator which are implementations of the IOC pattern are well known good practises however it's not clear how you can inject instances into workflow types / activities. I did raise this question &lt;a href="http://www.codeplex.com/CompositeWPF/Thread/View.aspx?ThreadId=40141"&gt;here&lt;/a&gt; and got some useful links. I haven't followed up the related links in detail however I did manage to find a relatively simple solution by using the services based infrastructure which WF provides.&lt;/p&gt;&lt;p&gt;The host application which creates workflow instances creates the types which need to be resolved by dependency injection. Those objects are then passed to AddService from the WorkflowRuntime instance. You then need to access the interfaces through the IServiceProvider interface or the ActivityExecutionContext instance calling GetService . If you only need to access the interfaces in the Activity.Execute method then you can simply use the ActivityExecutionContext instance directly within Execute. Otherwise override the method OnActivityExecutionContextLoad and store away the interface references. If you do this however be sure to mark the fields in the activity / workflow with the NonSerialized attributes to prevent them also being serialised when the workflow is persisted.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;Scheduling services&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;The default scheduling service uses a thread pool to schedule workflows to be executed as required. However given the workflow types in our project AND the host application access the same business object underling the workflow, this does introduce potential concurrency issues. The manual scheduling service provides a model which is simpler to manage and would be more appropriate here.&lt;/p&gt;&lt;p&gt;You have to specifically schedule the ManualWorkflowSchedulerService to run a workflow using the RunWorkflow method. The host application simply does this after raising any events into the workflow through the local service. However some parts of the state machine activities require work to be continually performed in the background waiting for a specific rule evaluate to true and using a DelayActivity to sleep the workflow. To handle this a simple WPF DispatcherTimer can be used with DispatcherPriority.ApplicationIdle priority to execute any workflows which have expired timers. The timer can be setup using the following code&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;DispatcherTimer workflowPollingTimer = new DispatcherTimer(new TimeSpan(0, 0, 0, 5)),DispatcherPriority.ApplicationIdle,new EventHandler(workflowPollingTimer_Tick), Dispatcher.CurrentDispatcher);workflowPollingTimer.Tick += new EventHandler(workflowPollingTimer_Tick);workflowPollingTimer.Start();&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Within the timer the workflows will be executed when their timers expire&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;ManualWorkflowSchedulerService scheduler = workflowManager.WorkflowRuntime.GetService&lt;manualworkflowschedulerservice&gt;(&lt;&gt;);&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;foreach(SqlCePersistenceWorkflowInstanceDescription workflowDesc in persistence.GetAllWorkflows()){&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;if (workflowDesc.NextTimerExpiration &lt;&gt;&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;{&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;scheduler.RunWorkflow(workflowDesc.WorkflowInstanceId);&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;}&lt;br /&gt;&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Dynamic updates for customisation&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Although dynamically updating a workflow is often used for versioning reasons e.g. migrating old to new workflow versions, or making ad hoc changes to specific workflows at runtime it can often be used to provide flexible customisation within a workflow. Although rules can be managed directly within the workflow, they can also be managed within the application e.g. preferences for document approval. You may find a need where a number of different activities ( based on runtime conditions ) need to be executed and using If / Else type branches within the workflow can quickly make your workflow very complex and hard to maintain.&lt;/p&gt;&lt;p&gt;It's very simple to use a place holder activity within your workflow and then dynamically add activities to add at runtime based on application defined rules. Perhaps you have a number of different approval strategies which need to be executed, these could be added at the point of approval in the workflow. This does provide another option you can use to get the customisation you require without having to write designer hosting support in your applcation :)&lt;strong&gt;&lt;em&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Workflow runtime and instance wrapper classes&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;As you develop the host application you will probably find yourself writing proxies over the WorkflowInstance and WorkflowRuntime CLR classes to provide additional services when executing workflows. They can also make it easier to execute those workflows e.g. defining a ManualResetEvent within the workflow wrapper and then setting this when the workflow completed event fires so you can execute workflows and wait until they've completed. &lt;a href="http://www.bukovics.com/"&gt;Bruce Bukovics&lt;/a&gt; has developed a good set of wrapper classes you can use as a base and adopt as required for your own requirements.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Associating business objects with workflow instances&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;One of the requirements in a workflow applications is to load a specific business object and then raise a workflow event. To do this you need to maintain a link between the business object and it's associated WF workflow instance. You can add the business object link directly into the workflow or add the workflow instance link into the business object or even both.&lt;/p&gt;&lt;p&gt;If you do both so the business object contains a WorkflowId of type Guid in it's entity table, and the workflow itself contains a reference to the identifier of the business object. In this way the business object can be loaded by the client application, when a workflow event needs to be raised into the business object the correct workflow instance can be retrieved and called on. Having the business object reference directly in the workflow also allows the workflow to access the object to query any data within it or to make modifications and save to the data store.&lt;/p&gt;&lt;p&gt;You may find it preferable to you use an object identifier rather than the object reference otherwise for long running workflows you may find yourself using stale data e.g. if the host application modifies the business object and workflow is using a stale copy. Using an object identifier or even using an Identity pattern ( link to Martn fowlers identify pattern reference ) means you can load the object as and when required in the workflow instance.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;em&gt;Conclusion&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;I hope I've shown you a few techniques you can use to make your life a little simpler when developing WF applications. Both &lt;a href="http://www.theproblemsolver.nl/"&gt;Maurice de Beijer&lt;/a&gt; and &lt;a href="http://www.bukovics.com/"&gt;Bruce Bukovics&lt;/a&gt; have provided me with useful feedback when tackling WF design issues. Bruce has written an &lt;a href="http://www.amazon.co.uk/Pro-WF-Windows-Workflow-NET/dp/1430209755/ref=sr_1_1?ie=UTF8&amp;amp;qid=1228168025&amp;amp;sr=8-1"&gt;excellent book&lt;/a&gt; on WF which is even worth getting just for the additional chapters covering NET 3.5 changes. Maurice also teaches a highly respected &lt;a href="http://www.develop.com/course/windows-workflow-foundation-csharp"&gt;course&lt;/a&gt; on WF.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-3223753893269610552?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/3223753893269610552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=3223753893269610552' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/3223753893269610552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/3223753893269610552'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2008/11/enterprise-windows-workflow-foundation.html' title='Enterprise Windows Workflow Foundation Development'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-5808183138231875288</id><published>2007-12-04T13:58:00.000-08:00</published><updated>2007-12-04T14:09:03.804-08:00</updated><title type='text'>User interface automated testing</title><content type='html'>If you’ve read any of my previous posts you’ll know I’m very keen on unit testing and continuous integration. Up until now we’ve managed to automate the testing of pretty much everything i.e. XSL / components covering many different technologies / web applications both ASP and ASP.NET / and also test and integrate database scripts.  One thing I’ve always struggled on though is effective test automation of thick client GUI applications and always managed to push this task aside.&lt;br /&gt;&lt;br /&gt;Recently whilst fixing a defect within a server component, I introduced another defect in a thick client user interface application which was using this component. At the time I added a few new unit tests for the component changes and checked all 3544 of our existing unit tests passed. When I got the green light on cruise control I was very happy with my changes and completely oblivious to the fact I’d just broken the GUI application :( When I discovered this a few weeks later I was determined to create a user interface unit test for this application– this was the kick start I needed.&lt;br /&gt;&lt;br /&gt;John Robbins is usually more renowned for his excellent debugging articles however &lt;a href="http://msdn.microsoft.com/msdnmag/issues/07/03/Bugslayer/default.aspx"&gt;here &lt;/a&gt;he writes about the new features in NET framework 3.0 which support UI automation. This sounded like an ideal technology to drive the UI and test features. I’d strongly encourage you to read this article and download the sample source code.&lt;br /&gt;&lt;br /&gt;In the article Johns written a wrapper over the UIAutomation object model which makes programmatic control of UI elements much simpler than using the UIAutomation API directly. However the wrapper assembly is still incomplete and only covers a few of the common controls. If you use this you will quickly find yourself needing to add new control types however this is relatively simple to do. To select an item in a combo box I created a class called UIComboBox which supports simple methods such as SelectItem. As you can see calling SelectItem sure beats writing this every time you need to select a combo box item in your client code.&lt;br /&gt;&lt;br /&gt;     &lt;span style="font-family:courier new;"&gt;  public void SelectItem(Int32 comboBoxItemIndex)        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;{            &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt; AutomationElementCollection comboBoxItems = this.RootElement.FindAll(TreeScope.Descendants,&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;   new PropertyCondition(AutomationElement.IsSelectionItemPatternAvailableProperty, true));&lt;br /&gt;            AutomationElement itemToSelect = comboBoxItems[comboBoxItemIndex];&lt;br /&gt;            object pattern = null;            &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            if (itemToSelect.TryGetCurrentPattern(SelectionItemPattern.Pattern, out pattern))            &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            {                &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;                ((SelectionItemPattern)pattern).Select();            &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;            }        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;br /&gt; One wrapper control I certainly missed was one associated to the NET DataGrid. I was actually automating a NET 1.1 application and although I found this &lt;a href="http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1591782&amp;amp;SiteID=1"&gt;solution &lt;/a&gt;, it only works on a NET 2.0 DataGridView. Still if you are using this you can build a very nice API with methods such as SetAt and GetAt to retrieve / set cell content within the grid.  The only solution I could find to fill the NET 1.1 grid was to use the SendKeys method to send all the required keystrokes to navigate through the grid.&lt;br /&gt;&lt;br /&gt;All of the UIAutomation and the corresponding wrapper methods in the article download use methods which take a UIAutomation identifier.  To create tests quickly it’s vital to use a tool such as UISpy to obtain these identifiers. All you need to do is put UISpy in “hovering mode” and then simply hold down the Ctrl key whilst hovering over a window in the application being automated. The window is highlighted in red and UISpy then reports all the details in the right hand pane, most importantly including the AutomationId.&lt;br /&gt;&lt;br /&gt;Once you have the automation identifiers it’s very straightforward to write code to access any GUI elements e.g.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;UIEditControl invoiceNoTextBox = appWindow.FindDescendant("invoiceNumberTextBox", ControlType.Edit) as UIEditControl;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;invoiceNoTextBox.Value = "SLOG_Invoice_1";&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span &gt;It is usually far more effective to use FindDescendant to find controls rather than FindChild given this searches all children recursively and will eventually find the control if it exists :)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;When building unit tests you’ll usually find you automate the GUI to a point where you need to test the expected output. This could either be&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Verifying GUI control values have been set correctly by asserting the contents of the controls. E.g. you could take the user through a task such as create a new invoice and then assert the contents of a screen which shows the invoice detail ( perhaps a wizard summary screen ).&lt;/li&gt;&lt;li&gt;Verifying a specific action has occurred by invoking business objects and then asserting the values from the business object. E.g. you could automate the GUI task to create a new invoice and then when this is complete verify the invoice exists in the data store and the values e.g. invoice no, match the values you entered in the GUI.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;User interface testing is just as important as any other component testing that I do hope more people embrace this and start to automate the testing of a good portion of their user interfaces. As developers we cannot and should not rely on QA to find the defects, at least certainly not the obvious ones. With a few simple unit tests we can make great strides to catch any serious defects before QA and then the customer see the product.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-5808183138231875288?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/5808183138231875288/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=5808183138231875288' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/5808183138231875288'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/5808183138231875288'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/12/user-interface-automated-testing.html' title='User interface automated testing'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-1836009283200157134</id><published>2007-10-18T14:32:00.000-07:00</published><updated>2007-10-18T15:04:51.893-07:00</updated><title type='text'>Design - Modelling user interfaces in UML</title><content type='html'>In my &lt;a href="http://mattadamson.blogspot.com/2007/09/my-first-open-source-project-web.html"&gt;previous post&lt;/a&gt; I focused on how to model a web application and it's component parts e.g. server and client side pages into UML elements. In this post I'll describe an EA add in I built to help reverse engineer UML models from user interface elements such as dialogs and there component parts e.g. check boxes, text boxes, button. Although the add in works only on thick client applications, the approach could also be used for web applications.&lt;br /&gt;&lt;br /&gt;Most of the screens in your application, there contents and flow to other screen are typically driven by the use cases you write. It helps to model the screens using UML notation so you can describe each element and model how each element links or depends on other elements. Once the elements are in a UML model you could also show interaction e.g. an actor clicking a button which instigates a business object function which then builds a list box and populates a text box, and then enables another button.&lt;br /&gt;&lt;br /&gt;Enterprise Architect is an excellent low priced modelling package, however whilst it provides many useful features and powerful forward and reverse engineering options ( it even includes a debugger which can auto generate sequence diagram based on a run through code ), it also provides great extensibility through the add in interface. In the previous post I discussed an addin I wrote to reverse engineer the UML model from various web page files, however this addin works differently by using a spy++ type capture pointer. The user only needs to hover the pointer over a window they need to capture, the addin then creates a UML model of the dialog using all the component parts of the window, with the exact same size and position as they appear on screen.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href="http://www.codeproject.com/csharp/screen_capturing.asp"&gt;Mark Belles&lt;/a&gt; for writing the windows capture code which provides the hover utility to obtain a window handle. From this it was a simple matter of extracting all the windows information using the Win32 API. The add in also should also provide a good template for anyone else writing one and contains supporting classes that help wrap the unmanaged EA interfaces.&lt;br /&gt;&lt;br /&gt;The screen below shows the EA options dialog&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img id="BLOGGER_PHOTO_ID_5122797382269921458" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 481px; CURSOR: hand; HEIGHT: 248px; TEXT-ALIGN: center" height="233" alt="" src="http://4.bp.blogspot.com/_ijDVdKqddNs/RxfVE9J_6LI/AAAAAAAAAAs/51aA6xtrbvk/s320/EAOptionsDialog.jpg" width="411" border="0" /&gt;&lt;br /&gt;When you start the add in through EA you are presented with the following dialog&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_ijDVdKqddNs/RxfXeNJ_6OI/AAAAAAAAABE/B8yCmRiP_pg/s1600-h/GUIModellerOptions.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5122800015084873954" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_ijDVdKqddNs/RxfXeNJ_6OI/AAAAAAAAABE/B8yCmRiP_pg/s320/GUIModellerOptions.jpg" border="0" /&gt;&lt;/a&gt;The UML diagram below then gets generated.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;img id="BLOGGER_PHOTO_ID_5122797863306258626" style="DISPLAY: block; MARGIN: 0px auto 10px; WIDTH: 469px; CURSOR: hand; HEIGHT: 276px; TEXT-ALIGN: center" height="276" alt="" src="http://4.bp.blogspot.com/_ijDVdKqddNs/RxfVg9J_6MI/AAAAAAAAAA0/vAxTZXj47Fg/s320/EAOptionsDialogUMLDiagram.jpg" width="404" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Although the output isn't perfect it's a lot more productive than creating all yours screens manually. Not a job Id want to do often :)&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The full source code to the add in written in C# is available in the &lt;a href="http://wiki.eausergroup.org/"&gt;EA WIKI&lt;/a&gt;, I hope you find this useful.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-1836009283200157134?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/1836009283200157134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=1836009283200157134' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/1836009283200157134'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/1836009283200157134'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/10/design-modelling-user-interfaces-in-uml.html' title='Design - Modelling user interfaces in UML'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_ijDVdKqddNs/RxfVE9J_6LI/AAAAAAAAAAs/51aA6xtrbvk/s72-c/EAOptionsDialog.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-7562613910205244533</id><published>2007-09-06T13:33:00.000-07:00</published><updated>2007-09-06T14:16:38.718-07:00</updated><title type='text'>My first open source project - Web modelling UML add-in for Enterprise Architect</title><content type='html'>I recently created my first open source project called &lt;a href="http://sourceforge.net/projects/eawebmodaddin"&gt;EA WebModeller Add In&lt;/a&gt; which is an add in for the Enterprise Architect ( EA) UML modelling tool. The add in provides a much filled gap to the product to enable users to reverse engineer web projects into UML artifacts. Specifically using the &lt;a href="http://www.amazon.co.uk/Building-Web-Applications-Addison-Wesley-Object-Technology/dp/0201730383"&gt;web extensions for UML&lt;/a&gt; which Jim Conallen produced. The web extensions provide a standardised way of modelling the components which make up a web application.&lt;br /&gt;&lt;br /&gt;A seemingly simple concept, which most would just think of as one web page associated with another quickly becomes very complex and is proof of why Jim could write a substantial book on this subject and still leave room for more. Classes are used with a variety of different UML stereotypes to define the various components which combine to produce a web page e.g. server side page which builds a “client side page” which aggregates a number of “forms”. Various stereotypes of association are also defined to support different associations between the components e.g. one server side page redirects to another server side page or a client side pages links to another client side page ( through hyperlinks perhaps ). Components contained within pages both on the server and client are also modelled appropriately.&lt;br /&gt;&lt;br /&gt;The example web project included with the download available on source forge contains a number of scenarios e.g. file 1.asp includes files include1.asp and include2.asp. Both included files contain server side functions. 1.asp also contains a redirect call to 2.asp, an embedded class, some client side functions ( in java script ) and an embedded form. The 1.asp server side page and it’s associated elements are shown in the diagram below&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://1.bp.blogspot.com/_ijDVdKqddNs/RuBqu9cDMsI/AAAAAAAAAAc/2D7sohSQzOA/s1600-h/Diagram.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5107199332436882114" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://1.bp.blogspot.com/_ijDVdKqddNs/RuBqu9cDMsI/AAAAAAAAAAc/2D7sohSQzOA/s320/Diagram.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This is produced by the following settings in the add in&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://3.bp.blogspot.com/_ijDVdKqddNs/RuBpydcDMrI/AAAAAAAAAAU/vW2m3P_QBYQ/s1600-h/OptionsPage.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5107198293054796466" style="DISPLAY: block; MARGIN: 0px auto 10px; CURSOR: hand; TEXT-ALIGN: center" alt="" src="http://3.bp.blogspot.com/_ijDVdKqddNs/RuBpydcDMrI/AAAAAAAAAAU/vW2m3P_QBYQ/s320/OptionsPage.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The add in is built in an extensible way to allow new script parsing languages to be easily integrated within the framework e.g. a base ScriptParserBase class contains JavaScriptParser and VBScriptParser derived classes. Similarly the ServerPage class which models the UML server side page contains derived classes ActiveServerPage (ASP ) JavaServerPage (JSP) and DotNetActiveServerPage ( ASP.NET ) for each of the web application technologies. Note only the ActiveServerPage class is fully supported for ASP pages, I’m hoping the open source community will develop the JSP and ASP.NET technologies :)&lt;br /&gt;&lt;br /&gt;The add in uses mostly regular expressions to parse the script source into it’s appropriate components. They range from very simple expressions such as #include\s+(?&lt;pathtype&gt;virtualfile)=""(?&lt;includedfile&gt;.*) which parses include directives within ASP pages. The PathType and IncludedFile are named captured groups which here capture the type of file reference e.g. virtual or absolute file location. To relatively compex expressions such as “^\s*function\s*(?&lt;name&gt;\w+)\((?&lt;arguments&gt;.*)\)\s*(?&lt;functionbody&gt;(?:(?&lt;leftbrace&gt;\{)(?&lt;rightbrace-leftbrace&gt;\})(?(LeftBrace)[^\{\}]*.*))*)” which use “balance grouping” to support recurision within the expression. This power is required here to match all function definitions because we can’t simply match an opening and closing brace as we may find the first closing brace is not closing the function, it’s in fact closing the first for loop defined within the function.&lt;br /&gt;&lt;br /&gt;To parse the client side page the internet explorer active x control is used to load the htm file produced when navigating to the web page. By using the IE control, the parts of the web page such as embedded forms and controls within the form can be found and added to the UML components. I actually wrote a &lt;a href="http://mattadamson.blogspot.com/2006/12/unit-tests-web-applications.html"&gt;web application testing framework&lt;/a&gt; around this control however recently I’ve started to use the &lt;a href="http://watin.sourceforge.net/"&gt;WatIN framework&lt;/a&gt; which is more feature rich.&lt;br /&gt;&lt;br /&gt;Given the main web application our team develops is written in ASP with many hundreds of pages, the productivity boost from using the add in is huge. Although we couldn’t possibly try and reverse engineer the whole web application in one go, being able to selectively single out and reverse engineer a few web pages when adding new features or doing some refactoring is of great help. It clearly shows the effected pages and where the new logic is best placed and perhaps most importantly helps to show the impact of any changes on existing functionality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-7562613910205244533?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/7562613910205244533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=7562613910205244533' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/7562613910205244533'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/7562613910205244533'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/09/my-first-open-source-project-web.html' title='My first open source project - Web modelling UML add-in for Enterprise Architect'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_ijDVdKqddNs/RuBqu9cDMsI/AAAAAAAAAAc/2D7sohSQzOA/s72-c/Diagram.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-675722826169332142</id><published>2007-08-27T13:27:00.000-07:00</published><updated>2007-08-27T14:05:21.265-07:00</updated><title type='text'>Window Workflow Foundation - A new way to develop workflow</title><content type='html'>I’ve recently reviewed the new workflow framework called Windows Workflow Foundation ( WWF ) which is part of the .NET framework 3.0 runtime. Using the framework successfully within our applications will require a completely different thought process on traditional methods e.g. where we typically put most of the workflow behaviour directly within the code.&lt;br /&gt;&lt;br /&gt;I started to develop a generic workflow framework implementation of core business object services a few years back, however even with considerable effort, the implementation lacks many of the features provided by WWF. Given that most business applications go some way to make them flexible by developing a generic workflow framework, use of WWF should allow most teams to concentrate more on the back end business logic rather than trying to do what WWF does very well.&lt;br /&gt;&lt;br /&gt;I would highly recommend reading Bruce Bukovics excellent WWF book &lt;a href="http://www.apress.com/book/bookDisplay.html?bID=10213"&gt;http://www.apress.com/book/bookDisplay.html?bID=10213&lt;/a&gt; which provides coverage of all the important features in WWF very clearly.&lt;br /&gt;&lt;br /&gt;I have summarised the main points of WWF below&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;General Points&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Multiple types of workflow – It handles both sequential and state machine workflows, although typically P2P / Banking applications which Bottomline develops use state machine workflows because the processes don't define a fixed flow of control within the workflow. &lt;/li&gt;&lt;li&gt;Scalability - The ability of a workflow to persist itself could allow multiple servers to be workflow runtime hosts and therefore a workflow could be loaded and executed on a different server than the one that started it.&lt;/li&gt;&lt;li&gt;Workflow tracking - This is one of the most powerful features of WWF. However whilst it provides rich support for tracking the workflow through the different stages in the lifecycle, it also tracks rules.  Rules evaluation records each rule or rule set as it is evaluated. This could also help to easily explain to users why the workflow has progressed in a particular way. You can even go further and use custom tracking profiles to track the values of the entities at particular points in time when for example a rule was evaluated. This  provides a complete tracking picture for rules evaluation&lt;/li&gt;&lt;li&gt;Hosting of workflow designers - The tools to host the designer tools within your own applications are exposed and available as part of the WWF framework. This allows you to create even simple designer interfaces very easily e.g. allowing a user to create a number of different states within a state machine and chain them together to describe how each state transitions to the next and the event which cause the transition.&lt;/li&gt;&lt;li&gt;Parallel execution of activities within a workflow – Whilst activities cannot execute truly concurrently within a workflow the framework does support execution of two parallel branches of activities in that the first activity of the first branch will execute, when this finishes, the first activity in the second branch executes and so on&lt;/li&gt;&lt;li&gt;Exception handling – Provides support for handling exceptions in the workflow e.g. if activities which are part of the workflow do not complete as expected, different activities can be called and activities cleaned up correctly. Related to this is compensation which allows an activity to be undone rather than rolled back, when typical long running transactional flows could not possibly maintain a database transaction for a long period of time.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Rules &lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The rules and workflow data can be specified in an XML based format which is compiled by the WWF into code making it very quick to execute at runtime. The rules files can either be created manually or modified through using a rules designer.&lt;/li&gt;&lt;li&gt;Very feature rich rules can be created e.g. if you have access to the invoice entity you could say if Invoice.LineItems.Count &gt; 1 then HasMultipleLineItems, and then write control of flow in your workflow using this rule.  &lt;/li&gt;&lt;li&gt;Support for forward chaining of rules also means that you don't need to be so concerned with the order or priority you specify rules in. If a rule further down in a list of rules causes fields to change for which previous rules relied upon, this will cause those previous rules to be re-evaluated. Although you can override this for specific rules and specify a priority and indicate you don’t want any forward chaining to occur&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Persistence of workflow&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Objects associated with the workflow are serialized and de-serialised seamlessly. E.g. an invoice workflow object may require references to the invoice itself, and perhaps related purchase orders. &lt;/li&gt;&lt;li&gt;Handles the persistence of the workflows in the database or any other data store as required. Given the complex workflows you can create this support coming out of the box is a big plus. Not only is the workflow itself persisted i.e. the current state machine workflow , but all the associated rules and rule sets that the workflow contains&lt;/li&gt;&lt;li&gt;Workflow versioning / Dynamic workflow updates - Versioning is also handled well i.e. as you evolve your workflows and add new activities, create new or modify existing rules. Multiple entities can therefore exist which are associated with older and newer workflows. Although conversely with very long running workflows e.g. when a process will take a considerable time to complete you may want to change an existing workflow, this is also supported through dynamic updates.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Integration &lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Publishing of workflows – Workflows can be published as web services, which provide very powerful integration features to third party systems. This enables applications to call into the workflow and take appropriate actions e.g. approve an invoice. &lt;/li&gt;&lt;li&gt;Workflow chaining - Allows you to chain workflows together i.e. call one entirely new workflow from within an activity of another workflow. &lt;/li&gt;&lt;li&gt;Activities within workflows can call into web services, which provide easy integration points into many different ERP systems.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;State machine workflows&lt;/strong&gt;&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Support complex state machines - Support for recursive composition of states which effectively means states can contains other states i.e. any events defined by the outer state are available while the workflow is currently in any of the inner states.  This allows more elegant state machines to be designed which don’t contain redundant activities e.g. for an invoice a Cancel activity could be defined in a single state rather than all possible states from which the invoice could be cancelled.&lt;/li&gt;&lt;li&gt;Visibility of permissible events - The framework provides support within state machine workflows to easily see which events can be called when the workflow is in a specific state. We can easily see how this would be useful e.g. for invoices to determine which action buttons to display such as "Approve" could be driven on whether the "Approve" event is available. This would also facilitate external components knowing the events which they could call through a web service interface.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;          &lt;br /&gt;Using WWF should allow you more time to concentrate on the development of the business logic and also reduce the risks that are inherent in building a generic workflow framework. &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-675722826169332142?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/675722826169332142/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=675722826169332142' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/675722826169332142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/675722826169332142'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/08/window-workflow-foundation-new-way-to.html' title='Window Workflow Foundation - A new way to develop workflow'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-5684595796606127882</id><published>2007-08-16T14:02:00.000-07:00</published><updated>2007-08-16T14:08:02.688-07:00</updated><title type='text'>Continuous Integration – Using integration queues</title><content type='html'>One of the long standing issues we had with our continuous integration project was the lack of any concurrency control when multiple projects were executing. Although there was some support for this through custom plug ins to ccnet it wasn’t integrated within the core code well i.e. you couldn’t easily see through cctray which projects were executing and which projects were pending, waiting on other projects to complete.&lt;br /&gt;&lt;br /&gt;I managed to successfully integrate this new release with our project today which means for example when our unit test project is building, the core NET build project can no longer execute, which previously could cause all components to be removed whilst tests were running L. We have quite a few ccnet projects with a few dependencies so this is very useful. I’ve included the project dependencies in the diagram below&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;a href="http://4.bp.blogspot.com/_ijDVdKqddNs/RsS8DtcDMqI/AAAAAAAAAAM/8CKCmnxc3fU/s1600-h/CCNET1.3+-+Dependencies.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5099407450013119138" style="WIDTH: 461px; CURSOR: hand; HEIGHT: 289px" height="249" alt="" src="http://4.bp.blogspot.com/_ijDVdKqddNs/RsS8DtcDMqI/AAAAAAAAAAM/8CKCmnxc3fU/s320/CCNET1.3+-+Dependencies.jpg" width="414" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;The dependencies shown in the diagram are not true UML dependencies, they simply show the project dependencies which trigger builds to occur i.e. if the Sprinter3.6.4 database project performs a new successful build, it will trigger the web app project to build. &lt;br /&gt;&lt;br /&gt;If the diagram showed true UML dependencies then there would be a dependency between the NET assemblies project and the Sprinter3.6.4 database because the NET components depend on the schema of the database. However the NET code doesn’t need to be re built if the database changes, only component or web application unit tests should be re-executed.&lt;br /&gt;&lt;br /&gt;&lt;div align="center"&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-5684595796606127882?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/5684595796606127882/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=5684595796606127882' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/5684595796606127882'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/5684595796606127882'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/08/continuous-integration-using.html' title='Continuous Integration – Using integration queues'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_ijDVdKqddNs/RsS8DtcDMqI/AAAAAAAAAAM/8CKCmnxc3fU/s72-c/CCNET1.3+-+Dependencies.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-7265763130170188309</id><published>2007-05-18T03:23:00.000-07:00</published><updated>2007-05-18T03:30:04.656-07:00</updated><title type='text'>Debugging - Exception stack traces are not always detailed enough</title><content type='html'>&lt;p&gt;We often use the Microsoft Exception Management Application Block ( MEMAB )to publish unhandled exceptions in our applications. This provides a detailed log including all inner exceptions contained within the outer most exception. For each exception the message and stack trace are output.  For the inner most exception the stack trace usually contains the actual method which caused the exception. &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Although most well written applications should contain small reusable methods of perhaps no more than 20 lines, this is often not the case. If methods only contain a few lines, even with a stack trace it is sometimes very difficult or impossible to pin point the exact line which is causing the exception to occur. To find out the exact line causing the error the best course of action would be to take a dump. You can find out how to do this for a .NET application in my article &lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/07/Debugging"&gt;http://msdn.microsoft.com/msdnmag/issues/05/07/Debugging&lt;/a&gt; under “Managed First-Chance Exception”. Once you have a dump you can usually find the line of code on the production server without even using debugging symbols using the techniques highlighted below.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Assuming you have a System.NullReferenceException thrown from a .NET component you should trap access violation exceptions ( av code ) and take a full dump on this type of exception. E.g. assuming the MEMAB logs the following exception info&lt;/p&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;Exception Type: System.NullReferenceException&lt;br /&gt;Message: Object reference not set to an instance of an object.&lt;br /&gt;TargetSite: Void Tranmit.Common.Interfaces.IXmlSerialisable.LoadFromNode(System.Xml.XmlNode, System.Collections.Hashtable)&lt;br /&gt; We can find out the exact location in LoadFromNode by loading the full dump file in windbg then executing&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We can find out the exact location in LoadFromNode by loading the full dump file in windbg then executing&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;0:000&gt; !u @eip&lt;br /&gt;Will print '&gt;&gt;&gt; ' at address: 04a34312&lt;br /&gt;Normal JIT generated code&lt;br /&gt;[DEFAULT] [hasThis] Void Tranmit.Sprinter.AccountCodeCollection.Tranmit.Common.Interfaces.IXmlSerialisable.LoadFromNode(Class System.Xml.XmlNode,Class System.Collections.Hashtable)&lt;br /&gt;Begin 04a34168, size 25b&lt;br /&gt;04a34168 55               push    ebp&lt;br /&gt;04a34169 8bec             mov     ebp,esp&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;04a342de ff15381ea204     call    dword ptr [04a21e38] (Tranmit.Sprinter.AccountCode.ExtractIdentityFromNodeAsString)&lt;br /&gt;04a342e4 8945d8           mov     [ebp-0x28],eax&lt;br /&gt;04a342e7 b9241fa204       mov     ecx,0x4a21f24 (MT: Tranmit.Sprinter.HistoryItem)&lt;br /&gt;04a342ec e827ddf8fb       call    009c2018mscorwks.pdb not exist&lt;br /&gt;Use alternate method which may not work.&lt;br /&gt;04a342f1 8bf0             mov     esi,eax&lt;br /&gt;04a342f3 8b45e8           mov     eax,[ebp-0x18]&lt;br /&gt;04a342f6 8945c8           mov     [ebp-0x38],eax&lt;br /&gt;04a342f9 8b157cc31202     mov     edx,[0212c37c] ("The level {0} account code {1} could not be found")&lt;br /&gt;04a342ff 8955cc           mov     [ebp-0x34],edx&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;04a34302 b978afba79       mov     ecx,0x79baaf78 (MT: System.Int32)&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;04a34307 e80cddf8fb       call    009c2018mscorwks.pdb not exist&lt;br /&gt;Use alternate method which may not work.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&lt;br /&gt;04a3430c 8945d0           mov     [ebp-0x30],eax&lt;br /&gt;04a3430f 8b4ddc           mov     ecx,[ebp-0x24]&lt;br /&gt;&gt;&gt;&gt; 04a34312 8b01             mov     eax,[ecx]&lt;br /&gt;04a34314 8b400c           mov     eax,[eax+0xc]&lt;br /&gt;04a34317 8b803c040000     mov     eax,[eax+0x43c]&lt;/span&gt;&lt;br /&gt;&lt;span &gt;&lt;/span&gt;&lt;br /&gt;&lt;span &gt;Reviewing the source code we can see&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;String accountCodeIdentity = Tranmit.Sprinter.AccountCode.ExtractIdentityFromNodeAsString(accountCodeNode);&lt;br /&gt;              historyItems.Add(new HistoryItem(this,&lt;br /&gt;              String.Format("The level {0} account code {1} could not be found", accountCode.Level, accountCodeIdentity),&lt;br /&gt;DocumentType.SupplierInvoiceLineSplit));&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;br /&gt;Although we have no symbols loaded on the production server we can be pretty sure that the line&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;04a34302 b978afba79       mov     ecx,0x79baaf78 (MT: System.Int32)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;/span&gt;&lt;br /&gt;Refers to the references in the String.Format method call to the Int32 property Level referenced on the accountCode property. Reviewing the code surrounding this line we can see why the account code object would be equal to a null reference and proceed to diagnose the issue further.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-7265763130170188309?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/7265763130170188309/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=7265763130170188309' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/7265763130170188309'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/7265763130170188309'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/05/debugging-exception-stack-traces-are.html' title='Debugging - Exception stack traces are not always detailed enough'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-5820750514041829443</id><published>2007-01-26T06:23:00.000-08:00</published><updated>2007-01-26T06:26:30.686-08:00</updated><title type='text'>Code Reviewing - Improving our process</title><content type='html'>We have implemented a code review process over the past 3 years which seems to work reasonably well. This helps considerably to reduce the number of defects QA and ultimately the customer will see. However it’s only recently that I’ve started to analyse our current process with a view to improve it.&lt;br /&gt;&lt;br /&gt;One of my biggest concerns is that we find a lot of non functional defects and not many functional defects in code review. Whilst the non functional defects are important in terms of helping with code maintainability, functional defects should be the top priority on any code review as these defects usually manifest themselves as issues which would be visible to a customer.&lt;br /&gt;&lt;br /&gt;I have recently read a copy of “Best Kept secrets of peer code review” which is freely available from smart bear software at &lt;a href="http://smartbearsoftware.com/"&gt;http://smartbearsoftware.com&lt;/a&gt;. It provides useful techniques which can be used to improve your code review process and are based on real life case studies. Although of course the book does lean towards using smart bears code collaborator product to help with the code review process it does have a lot of useful content to warrant reading it even if you’re not likely to purchase these tools.&lt;br /&gt;&lt;br /&gt;Some points I picked up from the book which I’m going to look at in improving our process are&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;Initial quick scan&lt;/strong&gt; – The first initial scan can be very important in helping find defects throughout the code. As there is a negative correlation in the time the reviewers takes on the first scan versus the detected speed. The more time the reviewer takes on their first scan, the faster the reviewer will find defects. If you don’t perform a preliminary scan your first issues identified may focus on the wrong areas. With a quick scan you can identify areas with the highest possible issues and then address each one with a good change you’ve selected the right code to study.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Review for at most one hour at a time&lt;/strong&gt; – The importance of reviewing in short time periods shouldn’t be underestimated. We should try and avoid large reviews and try and split them up into smaller reviews where possible. E.g. you could certainly split up reviews of unit test codes versus core code. Although of course this isn’t an excuse to submit code with known defects for review.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Omissions are hardest defects to find&lt;/strong&gt; – It’s very easy to find issues for code you’re reviewing, it’s much harder to find defects in code which isn’t there. Having a review check list illeviates this issue some what to remind the reviewer to look for code which may not be present. Defects that aren’t associated with any checklist item should be scanned periodically. Usually there are categorical trends in your defects; turn each type of defect into a checklist item that would cause the reviewer to find it.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Defect density and author preparation&lt;/strong&gt; – Providing some preparatory comments before code is submitted for review does seem to have an impact on defect density. The key point here is that by annotating certain areas of code, developers are forced to do some kind of self review of their code which obviously increases the quality. Although there is a danger that the developer by preparing could disable the reviewer’s ability for criticism i.e. he’s not thinking afresh. However usually by developers preparing these kind of comments makes them think through their logic and hence write better code.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Leverage the feedback you’re getting&lt;/strong&gt; - Improve your ability and make yourself a better developer by reviewing the points you commonly receive. Code review points should be learned so you reduce the number of defects over time. A useful exercise could be to put your comments in your own personal check list which you visit when ever performing a code review. Any points which aren’t covered on the global check list should be added&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Developer and reviewer joint responsibility&lt;/strong&gt; – Defects found in code review are good. A defect found in review is a defect which never gets to QA or the customer. Developer and reviewer are a team and together plan to produce excellent code in all respects. The back and forth of coding and finding defects is not one developer punishing another, it’s simply a process in which two people can develop software of far greater quality than either could do single-handedly. reviewer finds in the developers code the better, this should be thought  excellent summary&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Checklist&lt;/strong&gt; – Use check lists as an aid to identify common defects. The most effective way to build and maintain the checklist is to match defects found during review to the associated checklist item. Items that turn up many defects should be kept. Defects that aren’t associated with any checklist item should be scanned periodically. Usually there are categorical trends in your defects; turn each type of defect into a checklist item that would cause the developer to find them next time.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-5820750514041829443?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/5820750514041829443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=5820750514041829443' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/5820750514041829443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/5820750514041829443'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/01/code-reviewing-improving-our-process.html' title='Code Reviewing - Improving our process'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-4609532354845559042</id><published>2007-01-09T02:52:00.000-08:00</published><updated>2007-01-09T03:01:32.216-08:00</updated><title type='text'>Design - Transitioning from conceptual domain to physical data model</title><content type='html'>When creating the design for new requirements we often design a domain model of key entities and then when were happy with it we migrate this domain model into a logical and then physical data model. Although we should go to the logical model and then transition to the physical data model we often go straight to a physical data model.&lt;br /&gt;&lt;br /&gt;We currently perform this process manually however Enterprise Architect ( UML modelling tool ) has got great support for transforming a domain model into a data model using model driven architecture ( MDA ) templates. It simply reads the entities and the multiplicity relationships between them and generates an appropriate data model. Handling many to many relationships isn't handled with the built in templates however you can easily customise the transformation template using an editor e.g. you can specify&lt;br /&gt;&lt;br /&gt;%if attTag:"columnLength" != ""%&lt;br /&gt;length=%qt%%attTag:"columnLength"%%qt%&lt;br /&gt;%elseIf classTag:"columnLength" != ""%&lt;br /&gt;length=%qt%%classTag:"columnLength"%%qt%&lt;br /&gt;%endIf%&lt;br /&gt;&lt;br /&gt;to use tagged values to denote the length of a character string in the domain model. Although you shouldn't be too concerned with lengths of strings in the domain model, if you want to specify this information in a tagged value you can at this point, and then ensure it's carried over to the data model e.g. to create a varchar(100) field for a UserName attribute of a User entity. Sparx support are currently developing these templates further and the latest version of the template handles many to many relationships by creating a link table in the format Join&lt;entity&gt;To&lt;entity&gt; however you could customise this to fit your own database standards.&lt;br /&gt;&lt;br /&gt;It would be great if through automation we could eventually create a data access layer from the conceptual model using the following steps&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create the conceptual domain model. A business analyst would ideally create the first draft&lt;/li&gt;&lt;li&gt;Add attributes as required to turn this model into a logical data model&lt;/li&gt;&lt;li&gt;Transform the logical data model into a physical data model&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We actually use LLBLGen ( object relational mapping tool ) to generate a data access / business object layer from the database so in this way we could continue this process and generate the LLBLGen classes by following some additional steps&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Create the database from the physical data model.&lt;/li&gt;&lt;li&gt;Create the LLBLGen classes from the database directly.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Both of these steps can actually be automated through the automation ability within Enterprise Architect and LLBLGen can be automated too to forward engineer the generated code. In this way we could go from a logical model to a generated database and then to an auto generated business object / data access layer automatically.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-4609532354845559042?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/4609532354845559042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=4609532354845559042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/4609532354845559042'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/4609532354845559042'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2007/01/design-transitioning-from-conceptual.html' title='Design - Transitioning from conceptual domain to physical data model'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-116497378693694792</id><published>2006-12-01T03:46:00.000-08:00</published><updated>2006-12-01T03:49:46.950-08:00</updated><title type='text'>Unit tests - Web applications</title><content type='html'>&lt;p&gt;&lt;br /&gt;We have had our unit test .NET assemblies up and running through Cruise Control for nearly a year now. This has worked very well in catching bugs early introduced by developers hastily checking in code without ensuring that ALL unit tests execute successfully. We use a main nant target which executes about a dozen testing assembly and any failures send an email to the development group so the whole team can see the user/s responsible for the checkins which broke the build. We name and shame them and this usually gets them, me quite a few times :(,  to fix the build promptly.&lt;br /&gt;&lt;br /&gt;However over the last year I noticed 90% of the defects we introduced related to the web application e.g. common script errors or simple page errors which should have been caught however because &lt;/p&gt;&lt;ol&gt;&lt;li&gt;The quality of testing performed by each developer was minimal&lt;/li&gt;&lt;li&gt;No developer ever regression tested many other potentially effected areas&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;We usually had a large number of issues which QA found come each major release. It was then a battle to fix them AND fix any other defects found from the new changes in the release. We barely had enough bandwidth to fix defects from the new changes let alone issues introduced in other areas. Since then I have had a strong motivation to enable a cruise control project which checks for changes in the web application and runs a unit test assembly with a selection of tests in the web app.&lt;br /&gt;&lt;br /&gt;The unit testing of the web application requires a new class I’ve created called InternetExplorerWrapper which provides a number of interesting features&lt;br /&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Managed access to the unmanaged internet explorer object to manipulate the object model of page contents when pages are navigated to. E.g. forms and their input fields, frames, anchors, images among many other elements.&lt;/li&gt;&lt;li&gt;Support to create unit test assertion with methods such as AssertFormFieldClassName which assert the class name of a specific form field e.g. used in test which specify a different class for fields which fail validation.&lt;/li&gt;&lt;li&gt;Internal auto reset event objects to ensure methods such as ClickAnchor only return back to the unit test code when the anchor has been clicked and the new page navigated too. The document complete event is used in this case, however this is made tricky because in some cases 3 or 4 document complete events maybe fired together because IE is loading multiple documents for a given request. &lt;/li&gt;&lt;li&gt;Methods to assist with viewing and manipulating the IE object model e.g. outputting the contents HTMLDocument object to the trace window. In this way you can see the elements you can access through your unit tests at specific points in time. Also other methods such as TraceDocsLoaded show you how many events are fired for a given request to help determine how many document complete events to wait for in requests such as ClickAnchor ( c) &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There were quite a few details which were problematic e.g. the creation of pop up windows e.g. these need to be wrapped by catching the NewWindow event, then create a new IE wrapper object around this and storing in a hash table within the original requested page. Client code can then access the new windows using methods off the main IE wrapper object such as GetNewIEWindow.&lt;br /&gt;&lt;br /&gt;Has anyone else had experience creating unit tests for web applications, I’d be interested to hear your thoughts. The framework should work regardless of the platform used to build the application e.g. ASP / ASP.NET and JSP.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-116497378693694792?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/116497378693694792/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=116497378693694792' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/116497378693694792'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/116497378693694792'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/12/unit-tests-web-applications.html' title='Unit tests - Web applications'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-115875603073373315</id><published>2006-09-20T05:38:00.000-07:00</published><updated>2006-09-20T05:40:30.743-07:00</updated><title type='text'>Unit tests - Pattern for testing localisable code</title><content type='html'>Currently we have a few unit tests, although this is sure to increase, which test code should work in any locale ( culture in .NET terms ). To test this we currently have an implementation such as&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;public AppVersionTest()&lt;br /&gt;{&lt;br /&gt;    // Set the current locale to French    Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;Assert.AreEqual(3.6,       Tranmit.Sprinter.Configuration.Database.TBConfig.ApplicationVersion,       "Failed to read the configuration ApplicationVersion");&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;}&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;br /&gt;We did this as we actually had a bug when the code was running on a french machine. I thought a better pattern would actually tests the code in all defined cultures e.g. changing the implementation to&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;// Obtain the current culture&lt;br /&gt;    CultureInfo oldCurrentCulture = Thread.CurrentThread.CurrentCulture;&lt;br /&gt;    try&lt;br /&gt;    {&lt;br /&gt;        foreach(CultureInfo cInfo in CultureInfo.GetCultures(CultureTypes.AllCultures)&lt;br /&gt;       {&lt;br /&gt;            Thread.CurrentThread.CurrentCulture = cInfo&lt;br /&gt;            // Perform test code&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    finally&lt;br /&gt;    {&lt;br /&gt;        // Restore the previous culture&lt;br /&gt;        Thread.CurrentThread.CurrentCulture = oldCurrentCulture;&lt;br /&gt;    }&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Any code which is locale independant should certainly work in any culture e.g. if monetary code was being tested the culture would allow the code to find thousand / decimal separators values, so this seems a sensible implementation. However this certainly strikes me as a pattern which NUnit could implement for test methods decorated with an attribute such as TestAllCultures which would reduce this to&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Test, TestAllCultures]&lt;br /&gt;public AppVersionTest()&lt;br /&gt;{&lt;br /&gt;    // Test code&lt;br /&gt;}&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;This would certainly reduce a lot of boilerplate code required for each test method and I'm sure useful to many other developers who have to write code which works across all cultures.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-115875603073373315?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/115875603073373315/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=115875603073373315' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115875603073373315'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115875603073373315'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/09/unit-tests-pattern-for-testing.html' title='Unit tests - Pattern for testing localisable code'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-115858477812567721</id><published>2006-09-18T06:03:00.000-07:00</published><updated>2006-09-18T06:06:18.136-07:00</updated><title type='text'>Unit tests - Pattern for time changing test methods</title><content type='html'>Some of our recent unit tests change the system time within the execution of the test method. e.g. testing components which escalate purchase orders to new users if the approvers don't respond within a configured time period. We test this by setting up configuration, such as the period of time which must elapse before escalation occurs, and then changing the system time to add this time period and call the component again. The assertion is usually a simple one e.g. a new user such as the approvers manager should now in the approval route for the order.&lt;br /&gt;&lt;br /&gt;We currently use a simple method of restoring the system time when the test method is executed by resetting it to the value captured when the test method is started. If the test method takes 2 seconds to elapsed and we have perhaps 10 test methods we can easily see that we lose 20 seconds of time every time the test fixture is called.&lt;br /&gt;&lt;br /&gt;I've thought of a better way to do this using a class such as RestoreTimeChangingCode. The class should be created as the first object which holds the following values&lt;br /&gt;&lt;br /&gt;a) StartTickCount&lt;br /&gt;b) StartTime&lt;br /&gt;&lt;br /&gt;The StartTickCount value is obtained using Environment.TickCount and StartTime from DateTime.Now. The Restore method should be called when the test method has finished executing, preferrably in a finally block so it's called even if an exception is raised. The Restore method simply adds the number of ticks which have elapsed since the object was created, which represents the elapsed time the test method took to execute, and adds this to the start time, and sets this as the current time.&lt;br /&gt;&lt;br /&gt;Whilst this class is useful it would be great if the NUnit framework provided perhaps an attribute called TestChangesSystemTime which could be added in addition to the standard Test attribute. The NUnit framework could then time the method and restore the time appropriately. It could also use a more accurate timer such as the performance counter timer.&lt;br /&gt;&lt;br /&gt;The TestChangesSystemTime attribute, in addition to reducing the amount of repeatable code you have to write in each test method, would also provide the ability to reflect on a testing assembly to see whether any test methods change the system time. This would be useful if changing the system time was a concern on any server e.g. we would not want to execute this test assembly on our source control server to avoid clients inadvertently checking in / checking out files with the incorrect date / time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-115858477812567721?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/115858477812567721/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=115858477812567721' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115858477812567721'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115858477812567721'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/09/unit-tests-pattern-for-time-changing.html' title='Unit tests - Pattern for time changing test methods'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-115821120481266490</id><published>2006-09-13T22:14:00.000-07:00</published><updated>2006-09-13T22:20:04.826-07:00</updated><title type='text'>Unit tests - Testing performance</title><content type='html'>We currently use a single performance unit test assembly which has all performance related times e.g. testing X invoices can be created in under Y seconds. If the tests fail it's usually because either&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Database changes have been applied such as indexes / triggers or modfications to stored procedures, to slow the time to perform the database access code&lt;/li&gt;&lt;li&gt;Business logic has been changed e.g. when saving the invoice additional validation has been added which slows the time to create an invoice.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;There are two important things to note about our implementation&lt;/p&gt;&lt;ol&gt;&lt;li&gt;The expected time periods for the test methods are obtained from the configuration file. This is required because of the differences in expected time from machine to machine. If the expected time is hard coded, the code would need to change when the test is executed on different machines. The key value is read from the configuration file using reflection to obtain the method name the test is executing in, e.g. a configuration key of SP_INVOICE_PERFM_1-MaxTime maybe used for a test method called SP_INVOICE_PERFM_1. The configuration file with all the expected timings can be managed in your source control repository and checked in when the unit test assembly is. We usually check in the configuration file with the timings working on our cruise control build machine. If anyone checks in some bad database code, or some ridiculous index which slows the whole process down, we soon know about it when the next build breaks because of the failing tests.&lt;/li&gt;&lt;li&gt;The actual time period tested is not the duration of the test method, it really starts and stops at specific points in the method e.g. an invoice creation performance test is fine to test the whole method because all the method does is created a number of invoices which should be complete in X seconds. However a second test which verifies X invoices can be updated in Y seconds firstly needs to create the X invoices, and only then start the timer when just before the first update occurs, and stops when the last invoice has been updated. And of course all the invoices have to be deleted when the test finishes which shouldn't be included in the expected time. The SetUp and TearDown methods can't be used here because the unit test class such as InvoicePerformanceTest has many different methods with different set up and tear down implementations, and SetUp and TearDown are common methods called by all test methods in a text fixture. On a side note perhaps it would be useful to extend NUnit one day to support multiple set up and tear down attributed methods which apply to specific test methods.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In terms of implementing this generically in NUnit an attribute such as TimedTest with an optional attribute to specify whether the time period is obtained from a configuration file using a similar scheme we've devised. Also to cope with b), the framework could have a Start and Stop timing event which the test method could raise to indicate when the timing should start and when it should stop. This behaviour could also be specified using another parameter in the TimedTest constructor, e.g. if set to false then the start and stop would be implicit as soon as the test method started and finished.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-115821120481266490?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/115821120481266490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=115821120481266490' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115821120481266490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115821120481266490'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/09/unit-tests-testing-performance.html' title='Unit tests - Testing performance'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-115459619367941326</id><published>2006-08-03T02:05:00.000-07:00</published><updated>2006-08-03T05:33:15.586-07:00</updated><title type='text'>Unit tests - Executing over multiple application versions</title><content type='html'>The main application I design and develop usually contains additional database schema with each new version e.g. a recent 3.6.1 release will no doubt have a few new tables / new stored procedures e.t.c. Currently all our automated unit tests execute against a single database using the latest schema. When we complete and release 3.6.1 the cruise control build will only execute tests against this schema. However I would like to be able to execute our unit tests against old versions at least one back if not more e.g. so we can execute tests against 3.6.0 and 3.6.1. We do put effort into the assemblies to ensure backwards compatibility so it would be very handy to test this within our continuous integration process. Even in cases where we haven’t added any specific backwards compatibility code it would be nice to know existing tests still worked on old databases as we will still apply database patches to them.&lt;br /&gt;&lt;br /&gt;The obvious issue with executing the most up to date unit test assemblies is some new features in 3.6.1 won't work on a 3.6.0 database. e.g. assuming a new calendar table was included in a feature in 3.6.1, any tests which required this table would fail if run on databases less than 3.6.1. A calendar class may typically exist in a common assembly which contains many other types which work in previous versions. There are essentially three types of modiciations we could be making to unit test assemblies in each new release&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Addition of schema which wouldn't work in previous versions e.g. using new table / sps / UDFs&lt;/li&gt;&lt;li&gt;Updates to existing unit tests. As we adapt existing code we may have to change tests in some cases slightly, although this should be quite rare&lt;/li&gt;&lt;li&gt;Addition of new tests for old schemas e.g. we may find some additional scenarios which haven't previously been tested.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;2 and 3 obviously don't pose any issues however when executing unit tests against old databases we clearly need to conditionally execute the tests in 1 only if the schema is valid. A solution to this could be to apply an optional attribute against any test method called something like ApplicationVersion which would take the version number of the schema the unit test can be executed on. The attribute could be applied on a class or method. If applied on a class all tests within the class would require this version number unless any test methods overrode this by specifying a different number. e.g. a CalendarTest class could be defined like this&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:courier new;"&gt;[TestFixture]&lt;br /&gt;[ApplicationVersion(3,6,1,0)]&lt;br /&gt;public class CalendarTest&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;However I thought whilst the attribute and use itself seemed quite generic, the actual implementation to retrieve the version number would not be. There are two ways in this case NUnit could be modified to incorporate this&lt;/p&gt;&lt;p&gt;&lt;span style="font-family:Courier New;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:0;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Use a plug in framework within NUnit. The plug in could have one method which allows the method to determine whether an actual method is executed or simply ignored. A Bottom line plug in could simply have knowledge about the custom attribute, read it using reflection at runtime, and then verify the version number against that stored in the database and decide whether or not to ignore the method.&lt;/li&gt;&lt;li&gt;Have specific knowledge of the ApplicationVersion attribute and perhaps allow a simple piece of configured embedded C# script which could evaluate what the application number would be at runtime e.g. for us we could read it from the data store from the a table which contains the schema version.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;If tests were ignored, the ignore reason could be added automatically e.g. "Test method ignored as version executing against is 3.6.0 and this method requires 3.6.1".&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;This feature would certainly be useful for us as we have a large number of clients using old versions and only a few at a time initially using the most up to date versions. I'm sure the solution would be useful to others too, thoughts?&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-115459619367941326?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/115459619367941326/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=115459619367941326' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115459619367941326'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115459619367941326'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/08/unit-tests-executing-over-multiple.html' title='Unit tests - Executing over multiple application versions'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-115452603507862111</id><published>2006-08-02T06:37:00.000-07:00</published><updated>2006-08-02T06:40:35.086-07:00</updated><title type='text'>Continuous Integration of database scripts</title><content type='html'>I've recently got Cruise Control working on our development server to get latest from source safe, build our .NET assemblies and execute all unit tests. I'm extremely pleased with this and has really proved it's worth recently to show complete visibility to the team of failed builds. Any broken builds which do occur get turned around very quickly; I would strongly encourage anyone who hasn't already integrated cruise control into their build process to do so now.&lt;br /&gt;&lt;br /&gt;I have also recently taken this further by integrating database script changes into the process. In source safe we keep all the creation scripts for tables / stored procedures / UDFs e.t.c. When any changes are detected on the VSS database the scripts are applied using a few nant tasks and then the unit tests are re executed. This has quickly caught a few issues recently when stored procedures weren't in sync with the .NET code e.g. wrong data types or too many parameters in the DB compared to the client code.&lt;br /&gt;&lt;br /&gt;Like most development teams we have to maintain a few versions of our application and upgrade databases from old version to new versions. The latest database script are rerunnable against old versions of the schema i.e. it will add columns / stored procedures if their not already there, Ideally I would like to execute the database scripts against a number of different versions of the database and then execute the unit tests against the newly updated database to ensure the tests still passed. This would find issues for clients upgrading very quickly. I'd be interested in hearing from anyone else who has tried to automatically integrate database changes within their continous integration process.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-115452603507862111?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/115452603507862111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=115452603507862111' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115452603507862111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115452603507862111'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/08/continuous-integration-of-database.html' title='Continuous Integration of database scripts'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-115346842085094699</id><published>2006-07-21T00:48:00.000-07:00</published><updated>2006-07-21T00:53:40.873-07:00</updated><title type='text'>Unit tests - Changing app.config values at runtime</title><content type='html'>It would be useful for a number of unit tests to change the configuration values used in the app.config file of a unit test DLL. Actually changing the value in the file is straightforward enough i.e.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Get access to the app.config file full path from the process using AppDomain.CurrentDomain.SetupInformation.ConfigurationFile&lt;/li&gt;&lt;li&gt; Load the file into an XmlDocument&lt;/li&gt;&lt;li&gt;Extract the relevant node using code such as  XmlNode node = xmlDocument.SelectSingleNode(@"/configuration/appSettings/add[@key='" + configurationName + "']");&lt;/li&gt;&lt;li&gt;Set the value of the “value” attribute using node.Attributes.GetNamedItem("value").Value =  configurationValue;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;However by default changes to the configuration file won’t be reflected at runtime i.e. code such as &lt;/p&gt;&lt;p&gt;&lt;em&gt;         String fromEmailAddress       = System.Configuration.ConfigurationSettings.AppSettings["EmailFromAddress"];&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;will not reflect the new value if EmailFromAddress is changed in the app.config file. The AppSettings class caches the values retrieved within the AppDomain and never refreshes them. ASP.NET as a CLR host actually does refresh the settings when the web.config file is changed however by default the standard CLR host won't.&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;Since there is no way to force the settings to be re loaded the simplest approach would be to ensure that all clients use the existing façade defined in Tranmit.Common.ConfigurationSupport. The GetValue method looks like this &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;&lt;em&gt;public static Object GetValue(      String key,&lt;br /&gt;                                                            Type typeOfObject,&lt;br /&gt;                                                            Object defaultValue)&lt;br /&gt;            {&lt;br /&gt;                  // Assign default value to object if no key found&lt;br /&gt;                  Object value = defaultValue;&lt;br /&gt;&lt;br /&gt;                  System.Configuration.AppSettingsReader appSettingsReader = new System.Configuration.AppSettingsReader();&lt;br /&gt;&lt;br /&gt;                  // Check value is present first to avoid exception&lt;br /&gt;                  // being thrown from AppSettingsReader.GetValue&lt;br /&gt;                  if(ConfigurationSettings.AppSettings.Get(key) != null)&lt;br /&gt;                  {&lt;br /&gt;                        value = appSettingsReader.GetValue(key, typeOfObject);&lt;br /&gt;                  }&lt;br /&gt;&lt;br /&gt;                  return value;&lt;br /&gt;            } // GetValue&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;em&gt;&lt;/em&gt; &lt;/p&gt;&lt;p&gt;This is fine for production code however when executing unit tests we need to make sure the value is loaded directly from the app.config file rather than through the AppSettings or AppSettingsReader class.  We could do this by&lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;ul&gt;&lt;li&gt;Set a value within the AppDomain to indicate a unit test is being executed e.g. AppDomain.CurrentDomain.SetData(“UnitTestExecuting”,true);&lt;/li&gt;&lt;li&gt;Modifying the existing GetValue method to check the app domain value UnitTestExecuting. If this is enabled then extract the configuration value using the steps 1 to 3 above directly from the file. Otherwise use the existing code which uses the AppSettings class&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; &lt;/p&gt;&lt;p&gt;There should only be a slight performance impact for unit test code which is fine, but production code should execute the same. This will obviously require that client code uses the GetValue method rather than the classes in the ConfigurationSettings namespace directly.&lt;br /&gt;&lt;br /&gt; &lt;/p&gt;&lt;p&gt;&lt;br /&gt; &lt;/p&gt;&lt;p&gt; &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-115346842085094699?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/115346842085094699/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=115346842085094699' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115346842085094699'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/115346842085094699'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/07/unit-tests-changing-appconfig-values.html' title='Unit tests - Changing app.config values at runtime'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-114079955483884622</id><published>2006-02-24T08:31:00.000-08:00</published><updated>2006-02-24T08:45:54.870-08:00</updated><title type='text'>VBScript plug ins for ASP applications</title><content type='html'>Recently one of the developers in my team was developing some custom code in a COM table rendering object we've built for an ASP web application. The object essentially takes source SQL with added meta data and creates a HTML table which is returned into the calling ASP application, and then written out using Response.Write.&lt;br /&gt;&lt;br /&gt;The design required some very custom presentation within one of the table cells. The table rendering object is quite generic ( knowing little about specific tables in the database schema ) and the custom presentation task required work on very specific tables. Custom work is essentially associated with each table cell using meta data tags such as "SubordinateList(%UserID%)". Assume the table object is rendering a list of users and if a user is a manager displaying a comma separate list of subordinate user names.&lt;br /&gt;&lt;br /&gt;Although this example is contrived (as our real example would require a lot more explanation) the design issue is the same. The obvious easy approach would be to simply add handling within the table rendering object in a switch statement to match on the start of the tag "SubordinateList" and then perform some custom processing in SQL to find the list of sub ordinates. The list would then be converted into a comma separate string which would be added to the table cell. This business logic ideally should not be contained within a generic table rendering engine.&lt;br /&gt;&lt;br /&gt;You may have seen plug in design patterns which support the extensiblilty we are trying to achieve here. Typically this would require the creation of a well defined interface e.g. IValueResolver which is defined and called in the table rendering object. The implementation of different IValueResolver objects could be created in one or many plug in components. The IValueResolver interface could only require one method such as GetValue which takes a row, column and table data.&lt;br /&gt;&lt;br /&gt;Although ASP, using VB script, doesn't support strongly typed interfaces we can still use the late bound IDispatch support in VBScript to implement this design. We could create a VB script class on the ASP page such as&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Class SubordinateListValueResolver&lt;br /&gt;    Dim UserColumn&lt;br /&gt;    &lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;    Public Function GetValue(row, col, tableData)&lt;br /&gt;        ' Work to retrieve the list of subordinates from the user specified&lt;br /&gt;        ' in the column UserColumn in the row from the tableData data source.&lt;br /&gt;    End Function&lt;br /&gt;End Class&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The plug in class could then be instantied on the ASP page and passed to the table rendering object using code such as&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Dim oValueResolver&lt;br /&gt;Set oValueResolver = New SubordinateListValueResolver&lt;br /&gt;oValueResolver.UserColumn = 4 ' Means the 4th column in the result&lt;/strong&gt;&lt;br /&gt;&lt;strong&gt;oTableRenderer.AddValueResolverPlugIn(oValueResolver, "SubordinateList")&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The table rendering object can then determine whether any plug ins exist using the meta data tag passed when the data source SQL is specified. e.g. if a matching plug in object is found for the tag SubordinateList the VBScript object of type SubordinateListValueResolver will be returned. The GetValue method can then be called directly passing the row, column and table data from within the table rendering object. i.e.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;oCellResolvedValue = plugin.GetValue(row, col, tableData)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Although designs which use well defined interfaces and contain the plug in code in compiled languages are preferrable to this approach, it does demonstrate how easy a simple plug in mechanism can be developed for a script based application.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-114079955483884622?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/114079955483884622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=114079955483884622' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/114079955483884622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/114079955483884622'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/02/vbscript-plug-ins-for-asp-applications.html' title='VBScript plug ins for ASP applications'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-113991701835559467</id><published>2006-02-14T03:20:00.000-08:00</published><updated>2006-02-14T03:39:18.170-08:00</updated><title type='text'>Remote debugging - Release build optimisations</title><content type='html'>I recently had to diagnose an issue which required remote debugging the application as no exception was raised and therefore no dump could be obtained and analysed. The issue was caused by an error code deep down in the call stack being returned and ignored a few levels up the call stack :(&lt;br /&gt;&lt;br /&gt;Whilst this was trivial to debug using the windbg client and dbgsvr on the server ( both part of the debugging tools package ) I found in some cases, particularly where the error code was being returned, that local variables couldn't be seen. The message &amp;lt;Memory access error&amp;gt; was displayed in the locals window for each variable.&lt;br /&gt;&lt;br /&gt;Our standard process is to generate debugging symbols with each release build by simply selecting the generate debugging symbols option (&lt;a href="http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp"&gt;http://msdn.microsoft.com/library/en-us/dnvc60/html/gendepdebug.asp&lt;/a&gt;). To accurately see variables in both the watch and locals windows you need to make sure you disable optimisations i.e. through Project Settings / C++ / Optimisations - Set this to Disable ( Debug ).&lt;br /&gt;&lt;br /&gt;Obviously this should only be disabled for ad hoc builds as you will most likely want to enable all optimisations in your standard builds you deploy. It's hard enough trying to get our applications to be as performant as possible without disabling optimisiations which the compiler gives us automatically :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-113991701835559467?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/113991701835559467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=113991701835559467' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/113991701835559467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/113991701835559467'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/02/remote-debugging-release-build.html' title='Remote debugging - Release build optimisations'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-113957064028648378</id><published>2006-02-10T03:18:00.000-08:00</published><updated>2006-02-10T03:42:16.753-08:00</updated><title type='text'>Database filtering of documents - performance issues</title><content type='html'>Our application has a requirement to filter the documents a user can see based on various criteria e.g. security / approval rights. A user may only wish to see documents which they can approve or have approved. This would seem to be a common pattern for a lot of business applications.&lt;br /&gt;&lt;br /&gt;To implement this our business objects create a list of document identifiers which are then appended to a SQL statement which selects the data and filters the documents returned. We used to use the IN clause to filter the documents returned using a pattern such as&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SELECT * FROM PurchaseOrders WHERE PurchaseOrderID IN ( CommaSeperatedListOfIDs )&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;where the list of order ids was generated from the business object. After usage of the application quickly increased we encountered a stack overflow exception issue http://support.microsoft.com/kb/q288095. To resolve this we changed our approach to use temporary tables i.e. insert all the IDs from the business object into a temporary table and then use this to filter the main query e.g.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;SELECT * FROM PurchaseOrders WHERE PurchaseOrderID IN ( SELECT ID FROM UniqueTempTableName &lt;uniquetemptablename&gt;)&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;The IDs are inserted into the temporary table using batch INSERTS e.g. in batches of 20 statements at a time. However when upwards of 10000 document identifiers of inserted into the table, it can take over 5 seconds to do this. E.g. an ASP screen which presents a list of invoices takes 15 seconds of which 11 seconds is attributed to the time to insert into the temporary table. Over the last day I've been exploring ways to minimise this.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Extended stored procedure&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;My first thoughts were creating an extended stored procedure which would create an in memory result set using a comma separated list of identifiers. The extended stored procedure would be called from a UDF which would return a table variable which could be used in a select statement e.g.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;CREATE FUNCTION dbo.Tfn_IDs(@listIdentifiers text)&lt;br /&gt;RETURNS @idTable TABLE (id int )&lt;br /&gt;AS&lt;br /&gt;BEGIN&lt;br /&gt;INSERT INTO @idTable&lt;br /&gt;EXEC master..xp_IDContainer(@listIdentifiers)&lt;br /&gt;RETURN&lt;br /&gt;END&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;However unfortunately EXEC cannot be used as the source for an INSERT INTO statement.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;OPENXML&lt;/span&gt;&lt;br /&gt;&lt;/strong&gt;I then realised I maybe able to generate an XML representation of the identifiers using the extended stored procedure e.g. in the format&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&amp;lt;values&amp;gt;&lt;br /&gt;&amp;lt;value id="84"&amp;gt;&lt;br /&gt;&amp;lt;value id="85"&amp;gt;&lt;br /&gt;&amp;lt;/values&amp;gt;&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;and then use the XML in a SQL OPENXML statement using&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;INSERT INTO @IDTable&lt;br /&gt;SELECT ID&lt;br /&gt;FROM OPENXML (@hDoc,'/Values/Value')&lt;br /&gt;WITH (ID int) &lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;UDF Only&lt;/span&gt;&lt;br /&gt;&lt;/strong&gt;I then went back to an approach without using an extended stored procedure and only using a UDF. The UDF could parse the comma separated list of values and insert into a table variable which would be returned. I won't outline the solution in detail but it basically encompasses using CHARINDEX to find the start and end positions of each identifiers using the comma as the delimmiter. It would be interesting to compare the timings of this and the OPENXML approach. The XML approach could be slower because of the more verbose structure of the data and the cost of creating the XML internally in SQL Server and performing XQuery expressions however it maybe offset by the improvement in speed of using a single INSERT INTO statement rather than multiple INSERT INTO statements for each identifier found and parsed in the UDF only approach.&lt;br /&gt;&lt;br /&gt;However after increasing the size of the input to this solution it quickly became apparent that CHARINDEX truncates text data passed to varchar(8000) and so won't work with long text types which contains 10000 identifiers with an average of 3 characters each.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:130%;"&gt;Back to a UDF + extended stored procedure&lt;/span&gt;&lt;br /&gt;&lt;/strong&gt;To overcome the issues faced in the UDF only solution an extended stored procedure would probably be the logical place to put all the parsing logic of the comma separated string into values used for an insert statement. However instead of using the resultset of an EXEC call as source to an INSERT INTO statement, which weve shown isn't possible, we could use an output parameter to get each identifier. Psuedo TSQL could look like&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;@sessionToken = xp_IDContainer_ParseValue('1,2,3')&lt;br /&gt;WHILE xp_IDContainer_EndOfResults(@sessionToken) &lt;&gt; 0&lt;br /&gt;BEGIN&lt;br /&gt;@ID = xp_IDContainer_GetNextID(@sessionToken)&lt;br /&gt;Insert id into table variable&lt;br /&gt;END&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;Has anyone solved this problem using the approaches I've highlighted or other approaches which are successful with large volumes of data.&lt;br /&gt;&lt;strong&gt;&lt;/strong&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-113957064028648378?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/113957064028648378/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=113957064028648378' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/113957064028648378'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/113957064028648378'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/02/database-filtering-of-documents.html' title='Database filtering of documents - performance issues'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-113708219480029164</id><published>2006-01-12T08:08:00.000-08:00</published><updated>2006-01-12T08:09:54.816-08:00</updated><title type='text'>Debugging - Data grid exceptions</title><content type='html'>I recently noticed an issue in one of our .NET controls which contains a Data grid which was causing values editted to be reverted back to their original values without any events being raised or any exceptions being raised to the client.&lt;br /&gt;&lt;br /&gt;However if you enable all CLR exceptions to break into the debugger you will see an exception e.g. in this case "1,444.66 is not a valid value for Decimal". You can then get the call stack at this point and determine where the code is failing.&lt;br /&gt;&lt;br /&gt;The data grid seems to handle quite a few exceptions silently which can cause confusion sometimes. If you are experiencing any odd behaviour with the Data Grid I strongly recommend you enable all exceptions to break into the debugger. To do this from Visual Studio .NET perform the following&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Select the Debug menu &lt;/li&gt;&lt;li&gt;Select Exceptions &lt;/li&gt;&lt;li&gt;Select Common Language Runtime Exception.&lt;/li&gt;&lt;li&gt;Change "When the exception is thrown" to "Break into the debugger". This will apply the setting to all exception types unless you've overridden this.&lt;br /&gt; &lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-113708219480029164?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/113708219480029164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=113708219480029164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/113708219480029164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/113708219480029164'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2006/01/debugging-data-grid-exceptions.html' title='Debugging - Data grid exceptions'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-112342379909058899</id><published>2005-08-07T07:00:00.000-07:00</published><updated>2005-08-07T21:50:27.553-07:00</updated><title type='text'>Visual Basic Production Debugging</title><content type='html'>A Visual Basic (VB) error is usually raised by either an explicit call to Err.Raise or by calling another COM object which raises an error. In both cases VB provides similar error handling to VB Script through the On Error Resume Next and On Error Goto statements. In &lt;a href="http://mattadamson.blogspot.com/2005/06/vbscript-production-debugging.html"&gt;VBScript production debugging&lt;/a&gt; I discussed how to generate dumps and obtain error information when VB Script errors occurred. Obtaining the same information when a VB error is raised is raised takes a bit more work.&lt;br /&gt;&lt;br /&gt;You may be using VB components from within an ASP web application to perform a lot of business logic and may find some errors are being raised but ignored by either the components or the ASP script. Trapping these errors in a production environment is therefore very useful.&lt;br /&gt;&lt;br /&gt;The main difference between VBScript and VB errors are VB errors are raised as true native exceptions (exception code c000008f ). To trap VB script errors break points had to be placed within the scripting runtime module. In this post I will walk you through the commands you need to execute on a live or full dump.After we’ve gone through the commands we’ll put together an adplus script to capture this information which you can use on production servers.&lt;br /&gt;&lt;br /&gt;When the dump is open switch to the VB thread - you can use ~*kb to see which threads have MSVBVM60. e.g.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:000&gt; ~20s &lt;/strong&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Determine the index of the EBTHREAD object in thread local storage (TLS).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; dd msvbvm60!g_itlsebthread l1&lt;br /&gt;6aae0ec0 0000001e &lt;/strong&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Find the location of this thread's TLS based on the thread environment block (TEB). If you want to dump the Err object for other VB threads just get the TEB for those threads.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; ~. 20&lt;br /&gt;Id: 758.5bc Suspend: 1 Teb: 7ffa8000 Unfrozen&lt;br /&gt;0:020&gt; ?7ffa8000 +0xe10 Evaluate expression: 2147126800 = 7ffa8e10&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;Get the location of our EBTHREAD object based on the index into TLS&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; ? 7ffa8e10 + 0000001e * 0x4&lt;br /&gt;Evaluate expression: 2147126920 = 7ffa8e88&lt;br /&gt;0:020&gt; dd 7ffa8e88 l1&lt;br /&gt;7ffa8e88 0977ef58&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;Get the address of the EXCEPINFOA member variable based on its offset into EBTHREAD&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; ?0977ef58+0x78&lt;br /&gt;Evaluate expression: 158855120 = 0977efd0&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;Now dump the EXCEPINFO data&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; dd 0977efd0 l8&lt;br /&gt;0977efd0 00000000 250613ec 250314da 00000000&lt;br /&gt;0977efe0 00000000 00000000 6aaa8bcf 80004005&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;At this point you have all of the information in the VB Error object. In this particular instance we have the bstrSource, bstrDescription, the pfnDeferredFillIn, and the scode. The pfnDeferredFillIn is simply a function in VB that is called as needed to get more information about the error object (ie. the description). This is called when the VB component tries to get the data (ie. access the Err.Description property) which is why the information may not be filled in sometimes.&lt;br /&gt;&lt;br /&gt;For this dump we can see the error source&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; du 250613ec&lt;br /&gt;250613ec "Microsoft OLE DB Provider for SQ"&lt;br /&gt;250613ec "L Server"&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;and the description&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; du 250314da&lt;br /&gt;250314da "[DBNETLIB][ConnectionOpen (Conne"&lt;br /&gt;250314da "ct()).]SQL Server does not exist"&lt;br /&gt;250314da " or access denied."&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;and the error number&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:020&gt; ? 80004005&lt;br /&gt;Evaluate expression: -2147467259 = 80004005&lt;br /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;br /&gt;As a full dump is required to access this information you can typically run into performance issues on the server if many exceptions are being generated due to the size of the files. It would be far more effective if we could use an adplus script to extract the error source, description, and number from a process at runtime. This avoids the need to create dump files and adds all the relevant information in the adplus log file. The script is shown below&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size:85%;"&gt;&amp;lt;ADPlus&amp;gt;&lt;br /&gt;&amp;lt;Settings&amp;gt;&lt;br /&gt;&amp;lt;RunMode&amp;gt; CRASH &amp;lt;/RunMode&amp;gt;&lt;br /&gt;&amp;lt;/Settings&amp;gt;&lt;br /&gt;&amp;lt;Exceptions&amp;gt;&lt;br /&gt;&amp;lt;NewException&amp;gt;&lt;br /&gt;&amp;lt;Code&amp;gt; c000008f &amp;lt;/Code&amp;gt;&lt;br /&gt;&amp;lt;Name&amp;gt; VBError &amp;lt;/Name&amp;gt;&lt;br /&gt;&amp;lt;/NewException&amp;gt;&lt;br /&gt;&amp;lt;Config&amp;gt;&lt;br /&gt;&amp;lt;Code&amp;gt;c000008f&amp;lt;/Code&amp;gt;&lt;br /&gt;&amp;lt;CustomActions1&amp;gt;&lt;br /&gt;.echo VB error occurred.;&lt;br /&gt;.echo ;&lt;br /&gt;r $t1 = poi($teb+0xe10+poi(MSVBVM60!g_itlsebthread)*4)+0x78;&lt;br /&gt;.echo Source ;&lt;br /&gt;.if poi($t1 + 0x4)=0 { .echo Unknown } .else { du poi($t1 + 0x4) };&lt;br /&gt;.echo Description ;&lt;br /&gt;.if poi($t1 + 0x8)=0 { .echo Unknown } .else { du poi($t1 + 0x8) };&lt;br /&gt;.echo Error number ;&lt;br /&gt;?poi($t1 + 0x1c);&lt;br /&gt;&amp;lt;/CustomActions1&amp;gt;&lt;br /&gt;&amp;lt;/Config&amp;gt;&lt;br /&gt;&amp;lt;/Exceptions&amp;gt;&lt;br /&gt;&amp;lt;/ADPlus&amp;gt; &lt;/span&gt;&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;The script uses some useful commands such as $teb to extract the TEB memory address and .if / .else to allow commands to be conditionally executed. It also sets a pseudo register $t1 to improve the performance of the error extraction, otherwise this data would have to be evaluated three times.&lt;br /&gt;&lt;br /&gt;For some VB errors where the description is not filled in you can open VB6 and in the immediate window just type 'error &lt;error&gt;’. If you don’t have access to debugging symbols on the server you can use the same techniques I discussed in &lt;a href="http://mattadamson.blogspot.com/2005/07/setting-breakpoints-when-production.html"&gt;Setting breakpoints without symbols&lt;/a&gt;. In this case you should find the memory address of the symbol MSVBVM60!g_itlsebthread and replace it with the memory address e.g. MSVBVM60 + 0x12345678.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-112342379909058899?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/112342379909058899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=112342379909058899' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112342379909058899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112342379909058899'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/08/visual-basic-production-debugging.html' title='Visual Basic Production Debugging'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-112074601808846647</id><published>2005-07-07T07:13:00.000-07:00</published><updated>2005-07-07T07:20:18.106-07:00</updated><title type='text'>Setting breakpoints when production servers have no access to symbols</title><content type='html'>In some cases a production server may not&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Have access to the internet to use the Microsoft symbol server.&lt;/li&gt;&lt;li&gt;Access to symbol files using a UNC path.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;In both cases it is impossible to set break points using symbolic names in either a live debug session or when using adplus. This is clearly a problem for the adplus configuration script I discussed in &lt;a href="http://mattadamson.blogspot.com/2005/06/vbscript-production-debugging.html"&gt;VB Script production debugging&lt;/a&gt;. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;If symbols aren’t available there is another solution by adding break points set using a memory address location. In the previous blog the adplus config file was setting a breakpoint on the function &lt;em&gt;vbscript!CScriptRuntime::RecordErrorContext&lt;/em&gt;. To find out the memory address for the breakpoint we need to determine what the offset to &lt;em&gt;vbscript!CScriptRuntime::RecordErrorContext&lt;/em&gt; is in vbscript.dll. &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;First we need to take a dump of the process on the production server and load it into windbg on a machine which does have access to a symbol store. Open the dump and enter the x command to find the address of the function&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:85%;"&gt;0:031&gt; x vbscript!CScriptRuntime::RecordErrorContext&lt;br /&gt;734753cf vbscript!CScriptRuntime::RecordErrorContext = &lt;no&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Then we need to find the module address for vbscript.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:031&gt; lmm vbscript&lt;br /&gt;start end module name&lt;br /&gt;73460000 734c5000 vbscript &lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Subtract the module start address from the symbol address&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:85%;"&gt;0:031&gt; ?734753cf - 73460000&lt;br /&gt;Evaluate expression: 86991 = 000153cf&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Now we have our offset we can use it to set a break point either during a live debug or in the adplus config file. The dump I used in the example above was using 5.6.0.8515 of vbscript.dll. The Address element of the adplus configuration file should be modified from &lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;/p&gt;&lt;/strong&gt;&lt;address&gt;vbscript!CScriptRuntime::RecordErrorContext&lt;/address&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;to&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:85%;"&gt;&lt;/p&gt;&lt;/span&gt;&lt;/strong&gt;&lt;address&gt;vbscript + 0x000153cf&lt;/address&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-112074601808846647?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/112074601808846647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=112074601808846647' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112074601808846647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112074601808846647'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/07/setting-breakpoints-when-production.html' title='Setting breakpoints when production servers have no access to symbols'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-112038431703614828</id><published>2005-07-03T02:43:00.000-07:00</published><updated>2005-07-03T02:51:57.043-07:00</updated><title type='text'>Effective Production Debugging MSDN Article</title><content type='html'>Following my recent production debugging MSDN article (&lt;a href="http://msdn.microsoft.com/msdnmag/issues/05/07/Debugging/default.aspx"&gt;http://msdn.microsoft.com/msdnmag/issues/05/07/Debugging/default.aspx&lt;/a&gt;.&lt;br /&gt;I've written a number of posts on techniques I wanted to cover in the article but couldn't as I ran out of space.&lt;br /&gt;&lt;br /&gt;I've already written on topics such as creating dumps through terminal services and VB Script debugging however If there's anything you'd especially like to see let me know and I'll try and cover it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-112038431703614828?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/112038431703614828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=112038431703614828' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112038431703614828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112038431703614828'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/07/effective-production-debugging-msdn.html' title='Effective Production Debugging MSDN Article'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-112008123756830527</id><published>2005-06-29T14:33:00.000-07:00</published><updated>2005-06-30T01:00:50.243-07:00</updated><title type='text'>VBScript Production Debugging</title><content type='html'>An error typically occurs in an ASP application running VB Script when either&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;An On Error Resume Next statement is called prior to executing some script. A number of method calls are then made which can potentially raise errors. After each statement is completed the Err.Number property is usually checked and action taken such as logging the error and providing user friendly messages.&lt;/li&gt;&lt;li&gt;No On Error Resume Next statement is called prior to executing some script . In this case any statements that follow will halt the processing of the script and return a runtime application error to the user.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Whilst the first case is the preferred approach to handle errors gracefully most developers typically do not check most statements for errors. If Err.Number is not checked errors can be silently ignored by the server side script, and then consequently cause other errors which are logged. It is therefore essential to be able to log information on the original error, namely the source, description and number.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Unlike languages such as C++ / VB or .NET exceptions aren’t raised to the debugger from scripting engines such as VBScript. Consequently we can’t use adplus to capture a dump file when a specific type of exception occurs. However when an error is raised a number of functions are called within the scripting runtime.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;vbscript!COleScript::OnScriptError. &lt;/strong&gt;This is called when a script occurs in the 2nd case above &lt;/li&gt;&lt;li&gt;&lt;strong&gt;vbscript!CScriptRuntime::RecordErrorContext. &lt;/strong&gt;This is called to record an error in the scripting runtime when On Error Resume Next has been called.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Although we can’t use adplus to create a dump file on an exception (because none is raised) we can use it to create a dump when a specific break point is reached. Opening the dump file shows the following call stack&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:78%;"&gt;0:023&amp;gt; kvn&lt;br /&gt;# ChildEBP RetAddr Args to Child&lt;br /&gt;00 0148f4a8 733183bf 0003aa70 000b5f48 00000000 vbscript!CScriptRuntime::RecordErrorContext&lt;br /&gt;01 0148f4c4 73318320 0003aa70 0148f5cc 00000010 vbscript!CSession::RecordExcepInfoAndClear&lt;br /&gt;02 0148f5b8 73304b01 0003a9c0 000b5f48 60030001 vbscript!InvokeDispatch&lt;/span&gt;&lt;/p&gt;&lt;p&gt;If we dump the first argument plus 8 we can see the EXCEPINFO structure which is passed to this method. EXCEPINFO is the automation structure which defines an error i.e.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;span style="font-size:85%;"&gt;struct EXCEPINFOA, 9 elements, 0x20 bytes&lt;br /&gt;+0x000 wCode : Uint2B&lt;br /&gt;+0x002 EXC_unused1 : UChar&lt;br /&gt;+0x004 bstrSource : Ptr32 to Void&lt;br /&gt;+0x008 bstrDescription : Ptr32 to Void&lt;br /&gt;+0x00c bstrHelpFile : Ptr32 to Void&lt;br /&gt;+0x010 dwHelpContext : Uint4B&lt;br /&gt;+0x014 EXC_unused2 : UChar&lt;br /&gt;+0x018 pfnDeferredFillIn : Ptr32 to Void&lt;br /&gt;+0x01c scode : Uint4B&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;Reviewing the dump we see&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:023&gt; dd 0003aa70 + 8&lt;br /&gt;0003aa78 00000000 000b85bc 00121254 00000000&lt;br /&gt;0003aa88 000f43e8 00000000 00000000 800a0063&lt;br /&gt;0003aa98 00000000 00000000 00000000 00000000&lt;br /&gt;0003aaa8 00000000 00000000 000a0004 0008012a&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;To find the source and description we can use the du command i.e.&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;0:023&gt; du 000b85bc&lt;br /&gt;000b85bc "MyVBClass"&lt;br /&gt;0:023&gt; du 00121254&lt;br /&gt;00121254 "Failed to get supplier invoice, "&lt;br /&gt;00121294 "Reason=Failed to open connection"&lt;br /&gt;001212d4 ", reason=Object required"&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:78%;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;However to get this information a full dump needs to be created. If many script errors occur this maybe unworkable in a production environment. A more elegant approach involves using a custom action in an adplus config file to extract the source, description and number and add to the log file adplus produces. i.e.&lt;/span&gt;&lt;/p&gt;&lt;span style="font-size:78%;"&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&amp;lt;ADPlus&amp;gt;&lt;br /&gt;&amp;lt;Settings&amp;gt;&lt;br /&gt;&amp;lt;RunMode&amp;gt;CRASH&amp;lt;/RunMode&amp;gt;&lt;br /&gt;&amp;lt;ProcessID&amp;gt;&amp;lt;Put process id in here&amp;gt;&amp;lt;/ProcessID&amp;gt;&lt;br /&gt;&amp;lt;/Settings&amp;gt;&lt;br /&gt;&amp;lt;Breakpoints&amp;gt;&lt;br /&gt;&amp;lt;NewBP&amp;gt;&lt;br /&gt;&amp;lt;Address&amp;gt;vbscript!CScriptRuntime::RecordErrorContext&amp;lt;/Address&amp;gt;&lt;br /&gt;&amp;lt;CustomActions&amp;gt;.echo -----;.echo VB Script On Error Resume Next error occurred.;.echo;.echo Source:;du poi(poi(esp+4)+c);.echo Description:;du&lt;br /&gt;poi(poi(esp+4)+10);.echo Code:;?poi(poi(esp+4)+24);g&amp;lt;/CustomActions&amp;gt;&lt;br /&gt;&amp;lt;Actions&amp;gt;Log;Stack;&amp;lt;/Actions&amp;gt;&lt;br /&gt;&amp;lt;ReturnAction&amp;gt;G&amp;lt;/ReturnAction&amp;gt;&lt;br /&gt;&amp;lt;/NewBP&amp;gt;&lt;br /&gt;&amp;lt;NewBP&amp;gt;&lt;br /&gt;&amp;lt;Address&amp;gt;vbscript!COleScript::OnScriptError &amp;lt;/Address&amp;gt;&lt;br /&gt;&amp;lt;CustomActions&amp;gt;.echo -----;.echo VB Script On Error Resume Next error occurred.;.echo;.echo Source:;du poi(poi(esp+4)+c);.echo Description:;du&lt;br /&gt;poi(poi(esp+4)+10);.echo Code:;?poi(poi(esp+4)+24);g&amp;lt;/CustomActions&amp;gt;&lt;br /&gt;&amp;lt;Actions&amp;gt;Log;Stack;&amp;lt;/Actions&amp;gt;&lt;br /&gt;&amp;lt;ReturnAction&amp;gt;G&amp;lt;/ReturnAction&amp;gt;&lt;br /&gt;&amp;lt;/NewBP&amp;gt;&lt;br /&gt;&amp;lt;/Breakpoints&amp;gt;&lt;br /&gt;&amp;lt;/ADPlus&amp;gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;The most interesting line in the config file is &lt;/span&gt;&lt;/p&gt;&lt;/span&gt;&lt;span style="font-size:78%;"&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;.echo Source:;du poi(poi(esp+4)+c);.echo Description:;du poi(poi(esp+4)+10);.echo Code:;?poi(poi(esp+4)+24);&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:100%;"&gt;The source and description are output as strings using the du command. From the parameter poi(poi(esp+4)+c), esp+4 is the stack pointer + 1 DWORD which equals the first parameter to the function were breaking on ( RecordErrorContext or OnScriptError ). This is dereferenced using the poi operator from which we then add 0xC to get to the offset of the Source member in the EXCEPINFO structure. The Source member is just a pointer to a string so poi is used again to dereference it. Description is handled the same and the error code is simply output using the ? evaluate expression command.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;&lt;/span&gt;&lt;p&gt;When a VB Script exception occurs you get all the relevant information provided in the log file along with any other exceptions which are raised i.e.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;span style="font-size:85%;"&gt;&lt;strong&gt;VB Script On Error Resume Next error occurred.&lt;br /&gt;&lt;br /&gt;Source:&lt;br /&gt;0017edf4 "MyVBClass"&lt;br /&gt;Description:&lt;br /&gt;0017eeac "Failed to get supplier invoice, "&lt;br /&gt;0017eeec "Reason=Failed to open connection"&lt;br /&gt;0017ef2c ", reason=Object required"&lt;br /&gt;Code:&lt;br /&gt;Evaluate expression: -2146828189 = 800a0063&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-112008123756830527?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/112008123756830527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=112008123756830527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112008123756830527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/112008123756830527'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/06/vbscript-production-debugging.html' title='VBScript Production Debugging'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-111891694293195837</id><published>2005-06-16T03:12:00.000-07:00</published><updated>2005-06-16T03:23:03.900-07:00</updated><title type='text'>Getting dumps for apps failing on start up using terminal services</title><content type='html'>In my previous post &lt;a href="http://mattadamson.blogspot.com/2005/05/getting-dumps-for-apps-failing-on.html"&gt;http://mattadamson.blogspot.com/2005/05/getting-dumps-for-apps-failing-on.html&lt;/a&gt; I discussed the use of gflags to invoke a debugger to start when a process starts and then sending debugger commands to create dumps when exceptions occur. However if your trying to debug against a process run in session 0, e.g. a web application or service, this technique will not work. As most support teams will probably be using terminal services to access production servers clearly we need a technique to get the dumps.&lt;br /&gt;&lt;br /&gt;Remote debugging is commonly used to debug across two machines i.e. setting up a debugger on the server and using a debugging client to connect to it using named pipes or tcp. However there is nothing stopping us using the same machine to host the debugging server and the client. We need to set up a debugger server which runs in session 0 and a debugger client which runs in the terminal services session i.e. 3 in our example.&lt;br /&gt;&lt;br /&gt;As before open gflags and specify the image module name you need to debug however instead of simply entering the path to the debugger you should specify some command line options to tell windbg to start as a debugging server. Enter the following in the debugger field&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;C:\Debuggers\windbg.exe -server tcp:port=123 –Q&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;The server option creates a debugging server and the tcp:port option specifies the port number. The –Q option suppresses the “Save workspace” dialog which is important if the debugger is running in session 0 and can’t interact with the user. Note the command line options are case sensitive so be sure to copy this exactly as it appears. As soon as the process your debugging starts the windbg debugee should be loaded in session 0 and broken in on the LdrpInitializeProcess method.&lt;br /&gt;&lt;br /&gt;To control the debugger server start a new instance of windbg as the debugging client. Press Ctrl+R to connect to a remote debugger session and enter the following&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;tcp:server=MACHINENAME,port=123&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;When you connect the windbg instance will connect to the remote debugger and allow you full control to enter commands e.g. you can enter&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Sxe *&lt;br /&gt;g&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;to break on all exceptions and then continue. You can also send the same commands to create dump files as mentioned in my previous post. Or you could simply use .dump to create a dump when a specific exception is raised e.g.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;.dump /ma c:\debugger\ExceptionDump.dmp&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;If you look at task manager you should also see two instances of windbg open. If you select the “Session ID” column you can see the different terminal services sessions used for each instance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-111891694293195837?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/111891694293195837/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=111891694293195837' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111891694293195837'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111891694293195837'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/06/getting-dumps-for-apps-failing-on.html' title='Getting dumps for apps failing on start up using terminal services'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-111729144183712697</id><published>2005-05-28T07:39:00.000-07:00</published><updated>2005-05-28T12:28:14.193-07:00</updated><title type='text'>Choosing between an ascending or descending index</title><content type='html'>&lt;p&gt;I was recently asked whether making an index ascending or descending would improve query performance in SQL Server. In almost all cases the direction would make absolutely no difference to the speed of retrieval. Performance of queries is usually best measured by examining the number of logical page reads required to find the data.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Searching a table for a specific row&lt;/strong&gt;&lt;br /&gt;Any search across a single non-clustered / clustered index to locate a specific row would always result in a similar number of pages read. In the non-clustered case the time to retrieve the row would be navigating the index pages through the binary trees root index page and then through the intermediate level index pages to find the leaf level index page which matches. Then if no clustered index existed on the table the index page would point to the data page which would then be read to obtain the data.&lt;br /&gt;&lt;br /&gt;If a clustered index existed on the table the leaf level non clustered index page would point to the clustered index key. The clustered index key would then be examined in a similar way to the non clustered index to find the leaf level index page. However for a clustered index the data exists on the leaf level index page so no further page reads would occur.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Searching for a range of rows&lt;/strong&gt;&lt;br /&gt;Even cases when searches are performed for a range of rows e.g. ID BETWEEN 100 AND 105 direction of the index would make no difference. A single column index can be scanned well in both directions because the index pages at a given level are linked by next and prior pointers pointing to the next and previous index pages at that level. The query optimiser may decide to search for the data either by starting at ID 105 and moving backwards through the index pages, or from 100 and working forwards.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;When does direction make a difference?&lt;/strong&gt;&lt;br /&gt;The direction you specify when creating an index is used to determine the order of the leaf level index pages. E.g. names Adamson, Bamber, Doherty, Roche would appear exactly in that order in an ascending index, and in a descending index they would appear as Roche, Doherty, Bamber and Adamson.&lt;br /&gt;&lt;br /&gt;The only case I can think of when the direction would have the most impact is a query where a composite index was used and a query was submitted which&lt;br /&gt;Covers all columns used in the index. This means all fields specified in the SELECT statement can be found in the index page.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Covers all columns used in the index. This means all fields specified in the SELECT statement can be found in the index page.&lt;/li&gt;&lt;li&gt;Specifies a different direction in the ORDER BY clause in the SELECT statement of the query to the direction the index was created in. &lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Consider a query&lt;/p&gt;&lt;p&gt;SELECT SupplierNo, CreatedDate&lt;br /&gt;FROM Invoices&lt;br /&gt;ORDER BY SupplierNo, CreatedDate DESC &lt;/p&gt;&lt;p&gt;WHERE CreatedDate BETWEEN ‘1/5/05’ AND ‘10/5/05’&lt;/p&gt;&lt;p&gt;If either two single non clustered indexes or a single composite index on SupplierNo ASC, CreatedDate ASC was created a Sort operator would still be used in the execution plan of the query. If we can remove the sort operator the query time should be reduced.&lt;/p&gt;&lt;p&gt;If you created a single composite non clustered index on SupplierNo ASC, CreatedDate DESC the index pages could be navigated without the sort operator being used and only an index scan performed. As the index is covered because all the columns requested existed on the index pages then no data pages would have to be navigated from the leaf level index pages.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;If you decided to change the query and add a column which didn’t exist on the index such as a reference number, the data page would have to be located for each matching row on the index page. Depending on the total number of index pages and data page scans required to get all the data, the query optimiser may even decide not to use an index and simply perform a table scan.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;This example cites the usefulness of the query execution plan to show you how slow a specific query is. This is the only effective method to diagnose potentially slow running queries and improve the performance in a methodical manner. You can either show an execution plan for a query directly in query analyser or capture the event from a SQL profiler trace in a production environment. Simply executing the query in the query analyser window and trying to time it manually will not yield good results unless the speed differences before and after are that noticeable.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-111729144183712697?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/111729144183712697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=111729144183712697' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111729144183712697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111729144183712697'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/05/choosing-between-ascending-or.html' title='Choosing between an ascending or descending index'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-111640290637260784</id><published>2005-05-18T00:55:00.000-07:00</published><updated>2005-05-23T09:00:21.410-07:00</updated><title type='text'>Getting dumps for apps failing on start up</title><content type='html'>&lt;br&gt;&lt;br /&gt;Applications such as services or out of process servers may generate errors on start up. Adplus provides a spawn option to launch processes and attach the debugger on startup. Unfortunately the spawn option cannot be used because the process is either started by the Service Control Manager (SCM) or the COM runtime loads the module. For these type of applications it is still possible to create dump files but the process is a little convoluted.&lt;br /&gt;&lt;br /&gt;What we need is some mechanism to attach to the process as soon as it launches but before the error is raised. The debugging tools package provides a tool called gflags which allows us to specify a number of debugging options both globally and for specific applications. One of the options allows us to configure a debugger which is attached as soon as the process starts.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://photos1.blogger.com/img/170/5838/640/GFLAGSScreenShot1.jpg"&gt;&lt;img style="BORDER-RIGHT: #000000 1px solid; BORDER-TOP: #000000 1px solid; MARGIN: 2px; BORDER-LEFT: #000000 1px solid; BORDER-BOTTOM: #000000 1px solid" src="http://photos1.blogger.com/img/170/5838/320/GFLAGSScreenShot1.jpg" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Enter the full image name in the image file page then press tab to enable all the other controls. Select the full path to the windbg debugger in the Debugger field which can either be cdb.exe or windbg.exe. Now start the failing application either by forcing the client to create the COM object or start the service. The debugger should then be launched ready to recieve commands.&lt;br /&gt;&lt;br /&gt;Now we've broken in the debugger we need to send all the commands adplus usually sends to configure specific exceptions to generate dump files. The debugger command "sxe" controls the action the debugger takes when an exception occurs in the application being debugged. When you use an Adplus XML config file to configure what exception codes generate dumps for 1st or 2nd chance exceptions Adplus sends a number of these commands to the console debugger (CDB) e.g. one is shown below with some detail omitted.&lt;br /&gt;&lt;br /&gt;sxe -c @"dump -u /mdi /c 1stchanceAVSCANmini.dmp; GN"&lt;br /&gt;-c2 @"dump -u /ma /c 2ndchanceAVSCANfull.dmp; GN" av&lt;br /&gt;&lt;br /&gt;The last parameter specifies the exception code ( access violation in this case ) and the -c and -c2 options specify the actions to take on first and second chance exceptions respectively. The /ma option effectively takes a mini dump with all additional options which is more commonly known as a full dump. However if you have a lot of different exception codes to configure this process can be very tedious and error prone. Fortunately when you run adplus it generates a file with a CFG extension in the Crash_.. folder. This file contains a list of all commands needed to be sent to CDB to configure all exception codes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;The most effective approach is to run adplus against any other process e.g. notepad, to generate a CFG file using the options you specify in an adplus XML config file. When the process is started and windbg breaks in you can use the "$&lt;" debugger command with the full path of the cfg file i.e.&lt;br /&gt;&lt;br /&gt;D:\Development\Debugging\Debugging Tools for Windows\DebuggerCommands.cfg&lt;br /&gt;&lt;br /&gt;This will send all the necessary commands in the CFG file to the debugger to create the dump files for first and second chance exceptions. It is worth editing the CFG file first to modify the application from notepad in this example to the name of your app. Then simply press F5 or enter the g command to allow the debugger to continue and the dump files should be created.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-111640290637260784?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/111640290637260784/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=111640290637260784' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111640290637260784'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111640290637260784'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/05/getting-dumps-for-apps-failing-on.html' title='Getting dumps for apps failing on start up'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-12773241.post-111614378434716582</id><published>2005-05-15T00:49:00.000-07:00</published><updated>2005-05-18T01:25:09.770-07:00</updated><title type='text'>Should the GAC always be avoided?</title><content type='html'>&lt;p&gt;Currently we use the Global Assembly Cache (GAC) to install shared assemblies which are called by a number of different applications; however articles such as the infamous “Avoid the GAC” &lt;a href="http://www.sellsbrothers.com/spout/#Avoid_the_GAC"&gt;http://www.sellsbrothers.com/spout/#Avoid_the_GAC&lt;/a&gt; article have made me question the usefulness of this approach.&lt;br /&gt;&lt;br /&gt;To summarise our deployment we have perhaps 40 or so assemblies which are referenced by a number of different applications namely.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;A windows service.&lt;/li&gt;&lt;li&gt;An ASP application.&lt;/li&gt;&lt;li&gt;A thick client windows application.&lt;/li&gt;&lt;li&gt;A .NET console application.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;All applications use the same set of core assemblies to perform most of the functions e.g. core invoicing and ordering components as well as components which are applicable across many different functional areas.&lt;/p&gt;&lt;p&gt;Every time we rebuild and deploy a new component e.g. assembly A which has upgraded from say 1.0.8.0 to 1.0.9.0 we ship a new publisher policy assembly which redirects 1.0.0.0 to 1.0.9.0 references to 1.0.9.0 and obviously also re installs the new updated assembly into the GAC. E.g. 1.0.9.0 may fix an issue in the database where a stored procedure is being used with an incorrect parameter order causing data integrity issues.&lt;br /&gt;&lt;br /&gt;This deployment works well in that components which are shared amongst all applications only need to be installed in one place. In the future we may provide breaking components with major functionality changes e.g. we introduce a new assembly A 2.0.0.0 version which may have breaking changes. In this case we envisage we may update the publisher policy with multiple redirections setup such as&lt;br /&gt;&lt;br /&gt;1.0.0.0 - 1.0.9.0 ---&gt; 1.0.9.0&lt;br /&gt;2.0.0.0 - 2.0.2.0 ---&gt; 2.0.2.0&lt;br /&gt;&lt;br /&gt;In this way we can support side by side versioning of both sets of assemblies. We make a statement with the publisher policy that version increments containing changes across 1.0.0.0 – 1.0.9.0 are compatible and are needed for all applications referenced assemblies in this range however applications which reference new assemblies in the range 2.0.0.0 + are breaking and should reference a different assembly.&lt;br /&gt;&lt;br /&gt;Currently we use the GAC to deploy all our assemblies and it seems to work well. The GAC was chosen because of the following benefits in order of importance:&lt;br /&gt;&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Ease of deployment.&lt;/strong&gt; When shared assemblies are updated they only have to be updated in one location as opposed to four directories namely system32, windows\system32\inetsrv, c:\program files\Tranmit\Transaction Engine and C:\program files\Tranmit\Products\SprintLog. Deploying the assemblies to more than one location is obviously more error prone and an additional burden on an administrator installing patches.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Performance.&lt;/strong&gt; When strongly named assembly files are loaded from a location other than the GAC the CLR compares hash values when the assembly is loaded. A hash of the file is performed every time an application executes. In addition any referenced assemblies in that assemblies manifest are also hashed and compared. This performance hit is required to ensure that the assembly file’s content hasn’t been tampered with.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Security.&lt;/strong&gt; The GAC is only accessible to those users with sufficient privilege.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Traced references.&lt;/strong&gt; Assemblies installed in the GAC can be added with a reference to the application. This prevents assemblies being removed accidentally and breaking client applications dependent on them. &lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Chris Sells author of the “Avoid the GAC” article actually agreed the GAC was the best choice in our case however I am keen to hear other peoples’ opinions on this interesting topic. I would certainly consider changing to XCOPY deployment if there is good reason.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/12773241-111614378434716582?l=mattadamson.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mattadamson.blogspot.com/feeds/111614378434716582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=12773241&amp;postID=111614378434716582' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111614378434716582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/12773241/posts/default/111614378434716582'/><link rel='alternate' type='text/html' href='http://mattadamson.blogspot.com/2005/05/should-gac-always-be-avoided_15.html' title='Should the GAC always be avoided?'/><author><name>Matt Adamson</name><uri>http://www.blogger.com/profile/12131418412061331395</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='20' src='http://2.bp.blogspot.com/_ijDVdKqddNs/Seo5zQgM1NI/AAAAAAAAACk/IZLDbAV4L-o/S220/GeorgeMe.JPG'/></author><thr:total>1</thr:total></entry></feed>
