tag:blogger.com,1999:blog-31358432590728918572024-03-13T16:16:48.209-07:00BettyBettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comBlogger27125tag:blogger.com,1999:blog-3135843259072891857.post-30867450389713196792016-09-22T03:15:00.000-07:002016-09-24T03:45:54.715-07:00Asymmetrical Signing with Google MacaroonsI'm a big fan of <a href="http://research.google.com/pubs/pub41892.html">Macaroons</a> but it's always bugged me a bit that if you want separate issuing/consuming services you need a shared secret between them. Main reason I didn't like this is that the consuming service then had the power to create new macaroons with different permissions. Of course the consuming service doesn't exactly need permission to access/modify its own resources so it's really only an issue if you don't use different shared secrets for each service. It also makes it a rather big pain to rotate secrets as you have to update it in multiple places.<br />
<br />
One of the things I really like about signed JWTs is that anyone can safely verify the token without accidentally allowing people to create new ones. So i've been pondering the idea of public private keys and macaroons for a while trying to figure out if they can work together nicely.<br />
<br />
Not sure how useful this is, but I haven't seen anyone else write about this topic (which could be a bad sign for security) so thought i'd do a brain dump.<br />
<br />
<b>Disclaimer: The following was a shower thought and has not been particularly well explored so it might not be particularly secure (I'm a security enthusiast but not an expert, I have revised this post at least once fixing a couple of silly mistakes.)</b><br />
<br />
Standard Method = Token + Secret => Hash then send the Token + Hash to relying party<br />
<br />
To verify the token you need to know the Secret.<br />
<br />
Adding PPK is really quite simple, you simply encrypt the secret + hash used as part of the macaroon signature using your private key and include the result as part of the token. This means anyone with the public key can verify the tokens authenticity and then that the chain afterwards is valid.<br />
<br />
Potential PPK Method = Token + Secret => Hash then send Token + Hash + Encrypted Secret to relying party - T + S => H, send T:H:E(S)<br />
<br />
To verify the token you first obtain the secret by decrypting it, then follow the standard Macaroon verification.<br />
<br />
Chaining after this point works the same as previously, the old hash is used as the secret for the new token. T + T1 + OldHash => New Hash, then send T + T1 + NewHash + Original Encrypted Secret.<br />
<br />
However, this isn't quite enough, anyone with the decryption key could change the token, create their own hash with the secret they decrypted and pass on the old encrypted secret with the message. For this reason the original hash also needs to be included in the encryption for verification. T:H:E(SH) or T:T1:H1:E(SH) for a chained message. It also needs to be included decrypted so that chaining works (can't chain without the previous hash).<br />
<br />
It does mean anyone with the public key can remove constraints that were added after the original server by rebuilding the entire chain without the offending parts, so you still don't want to give the public key to just anyone. But that's a limitation with Macaroons in the first place, the secret key is secret for a reason.<br />
<br />
I believe it still allows constraints to be added to the token by anyone it passes through, which still makes it more powerful than standard JWT PPK verification.<br />
<br />
What it appears to allow is the secret to be rotated or even randomized completely, that might not be a major benefit when you consider you have a new secret (being the 'public' decryption key) which is still hard to rotate as it's not really public (and could introduce problems due to people treating it too publically) but actually just asymmetrical encryption with different secrets at the issuer / consumer.<br />
<br />
So overall I think it's an improvement over standard Macaroons but still doesn't solve everything I was hoping for.<br />
<br />
<ul>
<li>Consuming services can't create new tokens</li>
<li>Still can't easily rotate keys</li>
</ul>
<div>
But maybe something like the ratcheting from Whisper could be used to improve that (<a href="https://whispersystems.org/blog/advanced-ratcheting/">https://whispersystems.org/blog/advanced-ratcheting/</a>)</div>
Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-56550287084594374992016-09-22T02:42:00.002-07:002016-09-22T02:43:04.079-07:00Dynamic Navigation via Claims-based Dependency Injection (website composition)It's not uncommon for websites to show/hide navigation based on what roles a user has. This become more problematic when the links being shown/hidden are links to other websites. Each site then needs to know about the others and any time you deploy a new site as part of the suite you need to update each app to add it, and maintain the logic based on roles for which items to show hide. A solution i've seen for this is to create a webservice and ask it what nav you should be showing, I'm not a huge fan of pull based services so this has always bugged me.<br />
<br />
I am however a big fan of Dependency Injection and while this issue isn't exactly all that related, it occurred to me that your login portal (WS-Fed, OAuth or whatever) can kind of be used like a DI Container to inject things into dependent apps. The change is extremely simple, instead of the IdP (just) telling apps what roles the user has, they also pass through a list of navigation items to display for that user. The nav then becomes a fairly dumb component that just reads the claims passed in and shows them. Thus centralising all the logic around what to show to what user, and considering the IdP normally has a list of relying parties anyway it's not exactly new information to it. Of course it doesn't really work for internal links or links to systems not controlled by the IdP.<br />
<br />
This is great when different roles have a different subset of apps they have access to, you can use this technique to create modular user portals that reuse common functionality/apps but still make it feel like a single portal (as long as look and feel is common). Where it becomes really neat is when you start looking into beta testing / A/B testing / slow rollouts where you can replace entire applications for specific user groups with a newer version instead of a big bang approach. Again not really suitable for in app features (especially if you have multiple different toggles) but for that you can fall back to roles.Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-85634498835997461092015-03-17T14:37:00.000-07:002015-03-17T23:48:08.733-07:00Simple Tfs Build MonitorI wanted a nice easy way to tell if there's a broken build and didn't find any of the build monitor tools available obvious enough while still being unobtrusive. So I wrote a little console app that changes the wallpaper colour which shows through the taskbar. I then scheduled the application to execute every 15 minutes. It's not at a level that I could roll out to the entire company (changing wallpaper is a tad mean) but it's a good proof of concept<br />
<br />
<br />
<script src="https://gist.github.com/bzbetty/f3f615c24cf27acb3fb8.js"></script>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-51176310088855785022014-01-30T01:39:00.000-08:002015-03-17T23:49:35.460-07:00Building Xamarin Applications on a TFS Build Server<h3>
<b>Enabling Android Builds
</b></h3>
<br />
<p>Update: Xamarin have done a bunch of work which makes it much easier to integrate with TFS, and this will only get easier with Build vNext as it uses actual visual studio to build instead of just msbuild</p>
<ul>
<li>Install the android SDK to a common path</li>
<li>Edit the TFS Build definition and in advanced settings find the "MSBuild Arguments" property and set it to "/p:AndroidSdkDirectory=E:\Android\android-sdk" obviously with the correct path</li>
<li>Edit the *.csproj file for the android project and change the first line so that DefaultTargets="Build" become DefaultTargets="SignAndroidPackage".</li>
<li>Queue a build in tfs - the APK should be put in the drop folder along with the other binaries.</li>
</ul>
<br />
<br />
<h3>
<b>Enabling iOS Builds</b></h3>
<ul type="disc">
<li>Open up the iPhone *.csproj file in a text editor, change the first line so that DefaultTargets="Build" become DefaultTargets="Build;_TfsRemoteBuild". And add a conditional propertygroup and targets</li>
</ul>
<PropertyGroup Condition=" '$(BuildingInsideVisualStudio)'!='true' "><br />
<ServerAddress>Name or IP of Mac Build Server</ServerAddress><br />
<BSAT>NjY3MjY5</BSAT><br />
<HttpPort>5000</HttpPort><br />
</PropertyGroup><br />
<Target Name="_TfsRemoteBuild" Condition=" '$(BuildingInsideVisualStudio)'!='true' " DependsOnTargets="_RemoteBuild"><br />
<br />
BSAT is the base64 encoded Pin you used to connect to the iOS build agent from Visual Studio<br />
<br />
<br />
<b><br /></b>
<b>The server committed a protocol violation. Section=ResponseStatusLine</b><br />
Unknown solution.<br />
<br />
http://forums.xamarin.com/discussion/3696/how-to-build-from-msbuild-command-line-trig-build-on-osx-from-windows<br />
<h4>
<b>Failed to fetch manifest from the build server</b></h4>
<ul>
<li>Ensure the build server and the Mac build server are running the same version of Xamarin </li>
</ul>
<br />
<b>Other Tips</b><br />
<br />
<ul>
<li>Remember to use build server tags to mark any build controller you setup to build Xamarin builds so that you can filter by just compatible build servers when creating a build definition</li>
<li>You will need to login to your build server setup your Xamarin license in visual studio - the licenses are stored in a common place so it shouldn't matter who you login as to set this up.</li>
</ul>
<div>
<br /></div>
Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-18110197979861075432013-09-13T04:47:00.000-07:002013-09-13T17:50:18.019-07:00Automatically create NuGet packages for TFS/SharePoint dlls<p>I write a number of TFS Plugins, meaning I end up referencing all sorts of TFS assemblies. This entails trawling through the various client and server installation directories trying to find the particular dll I'm looking for.</p>
<p>As I like my projects to build without needing to install any extra dependencies manually, this means either I include the files when I check into source control, or more recently I manually create a NuGet package for each dll and put it in my private repository.</p>
<p>Since I also have a habit of updating to the latest version of TFS often I also find that I need to repeat this process quite often - finding all these assemblies, creating NuGet packages, then updating my plugins and redeploying</p>
<p>I finally got sick of it enough to write a small powershell script to find any assembly starting with Microsoft.TeamFoundationServer.* and create packages, including package references to other packages.</p>
<p>This script should also work for other products like SharePoint with a few tweaks</p>
<script src="https://gist.github.com/bzbetty/6549585.js"></script>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-9804459220842851712013-06-23T01:22:00.000-07:002013-06-23T01:23:00.320-07:00Using Mvc 4 Display Modes for Feature TogglesIt occurred to me that it's possible to use the new Mvc 4 feature Display Mode (meant for switching views for mobile versions) as a complement for Feature Toggles.<br />
<br />
Obviously this can only switch out an entire view (or partial view) but it can be a nice alternative to putting lots of @if(featureEnabled) {} tags through your view.<br />
<br />
Add the following code to your global.asax Application_Start (or create an App_Start module).<br />
<br />
DisplayModeProvider.Instance.Modes.Insert(0, new DefaultDisplayMode("{NameOfFeature}")<br />
{<br />
ContextCondition = (context => {true/false logic})<br />
});<br />
<br />
Then create 2 views - one for the feature being disabled and one for it being enabled - eg Index.cshtml and Index.{NameOfFeature}.cshtml.<br />
<br />
This could also be used for similar concepts like permissions and a/b testing.Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-14858540942469748862013-06-20T21:32:00.001-07:002013-06-21T03:40:55.552-07:00Tfs Extensibility - Automatically Create Code Reviews on Checkin<p> I created a small plugin that has a percentage chance to create code review requests on checkin. You could enhance this pretty easily to create reviews using a more complex condition (based on how long its been since they last had a review, or the size of the checkin etc) however I've found the 5% rule to be fairly successful mainly because people have gotten used to the review feature and have started requesting code reviews manually for things they feel are important.</p>
<p>The major gotcha I found while coding this was the need to impersonate the user performing the checkin as the creator is the only user who can close the review (which isn't very useful when its the service account).</p>
<script src="https://gist.github.com/anonymous/5828803.js"></script>
Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-41533958228411521762013-02-15T01:59:00.002-08:002013-02-15T02:13:00.799-08:00Tfs Extensibility - Filtering Lab Management Test Agents by Test Configuration<b>Original Problem</b><br />
As previously mentioned there's <a href="http://bzbetty.blogspot.co.nz/2013/02/microsoft-test-manager-lab-management.html">no built-in way to pick a test agent automatically based on the selected test configuration</a>, after much digging I have found a partial work around.<br />
<br />
<b>Theory</b><br />
It turns out that like a lot of tfs components the test controller supports plugins. These inherit from <span style="background-color: white; color: #2b91af; font-family: Consolas; font-size: 13px;">TcmRunControllerPlugin </span>and have 3 methods - Init, TestRunStarting and TestRunCompleted. Unlike other TFS Plugins they are not automatically detected and need to be manually added to the qtcontroller.config (in c:\program files (x86)\microsoft visual studio 11.0\common7\ide).<br />
<br />
I found that on the TestRunConfiguration object there is a StringDictionary called AgentProperties, upon further inspection I noticed that it appeared to be used to filter test agents to find a suitable one to run the tests on. By default it has a filter for environment name, as a small test I added another hardcoded filter by overriding the Init method in a very simple plugin. To my surprise whenever tests were run they would now complain that no suitable agent could be found, by changing my filter it quickly came apparent that this method worked for machine tags.<br />
<br />
By overriding the Init method and a bit more digging I managed to get a list of properties from the Test Configurations and put them as filters for the agent selected.<br />
<br />
<b>Limitations/Issues</b><br />
I created a Test Configuration with values "IE:9" and another with "IE:10" and respectively labeled the web client machines with the same tags. Running the IE9 tests from MTM would always pick the machine tagged IE:9 and the IE10 ones would pick the machine tagged IE:10. Running both together would look for a machine labelled IE:9,10 which it wouldn't find and would fail. Unfortunately I have no way around this limitation currently.<br />
<br />
When running coded ui tests via a lab build you can only select one Test Configuration anyway so this limitation is only a problem when manually running the tests in MTM.<br />
<br />
The test controller plugins don't appear to be documented, which may mean this breaks in a future update.<br />
<br />
<b>Cross Browser Support</b><br />
This idea can be extended to apply to other browsers too using the <a href="http://blogs.msdn.com/b/visualstudioalm/archive/2012/10/30/introducing-cross-browser-testing-with-coded-ui-tests.aspx">cross browser feature from update 1</a> simply create an extra machine for each browser you wish to test and label correctly. I'd probably change my labelling scheme from IE:9 to Browser:IE9 to be bit more consistant. On each machine add a system environment variable called browser set to the correct name, then in your coded UI test make sure you always grab this value and set BrowserWindow.CurrentBrowser to its value.<br />
<br />
<b>Advantages over other methods</b><br />
<ul>
<li>Tests can be run from MTM without needing to manually select a different environment to run it in (as long as you only run one Test Configuration at a time)</li>
<li>Machines other than the test agents can be reused (eg database/webserver) meaning less hyper-v resources are needed</li>
<li>Works fine with TFS2012's auto config of test clients which causes issues for the<a href="http://blogs.msdn.com/b/lab_management/archive/2011/05/26/configuration-matrix-testing-using-visual-studio-lab-management.aspx"> multiple test client role method</a></li>
</ul>
<div>
<b><br /></b>
<b>Potential Extensions (not sure if they're possible)</b></div>
<div>
<ul>
<li>A way to disable/enable this filtering (an extra property in a test configuration would easily do it)</li>
<li>I'm still looking for ways to allow multiple Test Configurations to be run in one test run from MTM.</li>
<li>Overriding the browser environment variable automatically so I can use the same virtual machine for IE, Chrome and Firefox (obviously still needing a second machine for IE9 vs IE10).</li>
<li>Check if any other types of filters are available, I did see some xml floating around suggesting you may be able to filter based on Ram available.</li>
</ul>
<div>
<br /></div>
</div>
<br />
<script src="https://gist.github.com/bzbetty/4959374.js"></script>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-72964668781203445842013-02-12T01:12:00.000-08:002013-02-15T02:09:21.003-08:00Microsoft Test Manager / Lab Management MisconceptionsAs we were not lucky enough to have Visual Studio 2010 Ultimate my knowledge of MTM and LM were fairly piecemeal, this meant when I finally got to install it as part of 2012 (available to Premium as of 2012) I found out a lot of things didn't work like I had expected or were simply completely missing. <br />
<br />
<b>Test Configurations and Machine Tags are not related</b><br />
While at first glance it appeared I could label a machine with "OS: WindowsXP" and create a respective test configuration with the same key value pair, MTM doesn't seem to actually do anything with them.<br />
<br />
Machine Tags appear to have no function at all, except to help organize machines.<br />
<br />
Test Configurations seem mainly for manual testing, so you can manually test each software configuration you feel is important. If you record your manual test it seems to be available to every configuration and can therefore be overwritten. I'm presuming this to make it easy to rerun the same test on different machines which means you can use it to manually test a windows app in different versions of windows, or multiple versions of IE. The same restriction applies to coded ui tests, you can only apply one coded ui test to a test case which must apply for all test configurations.<br />
<br />
It should be possible to specify that the machine in the environment that the test is run must have x, y and z machine tags letting you test all sorts of combinations like Windows XP + IE 7 + No Flash or Windows 8 with UAC enabled. Instead it appears that tests are split into groups of about 100 and dished out between the available test agents in the environment.<br />
<br />
<a href="http://visualstudio.uservoice.com/forums/121579-visual-studio/suggestions/2431738-let-mtm-test-configuration-os-and-browser-paramete">UserVoice Suggestion</a><br />
<br />
<a href="http://blogs.msdn.com/b/lab_management/archive/2011/05/26/configuration-matrix-testing-using-visual-studio-lab-management.aspx">Microsoft recommended Work Around - Configuration matrix testing using Visual Studio Lab Management</a> although it's limited to 2 configs (eg IE / Firefox) and would need to be manually extended to support more and would need to be upgraded to 2012. It also means you need extra capacity for virtual machines as you can't have IE and Firefox on the same machine. There are issues with this approach in 2012 as the environments will have their agents automatically deployed (or removed) depending on their roles. Basically you can't use MTM to update the environment, or use snapshots if you want to use this approach.<br />
<br />
<span style="color: red;">Another potential work around that I've come up with is to use a <a href="http://bzbetty.blogspot.co.nz/2013/02/tfs-extensibility-filtering-lab.html">Test Controller plugin to filter available test agents</a>.</span><br />
<br />
<b>Test Playback in browsers other than IE is only supported for Visual Studio Coded UI Tests</b><br />
Ok, no big deal, I'll just convert my test to a Coded UI one (which seem to be more reliable anyway) then associate it back to the testcase.<br />
<br />
<br />
<b>MTM Recorded Tests don't support assertions</b><br />
Unless you convert to VS CUIT you can't automatically perform checks at the end to ensure the desired behaviour occurred. Again no big deal, CUIT seem the better option in the long run anyway.<br />
<br />
<br />
<b>Coded UI Tests aren't passed the Test Configuration</b><br />
While it's easily possible to switch between IE/Firefox/Chrome in code, you can't seem to do this based on the Test Configuration. You can use a csv DataSource attribute to run an automated test multiple times and switch the browser for each run, but that doesn't seem as nice as simply adding a new Test Configuration.<br />
<br />
Now I'm confused as to what the point is of test configurations is for automated tests, as it appears to basically just run the same test 4 times in the same environment on the same test agent.<br />
<br />
<b>The Lab Management Build Template can only run one configuration</b><br />
If you want to run the tests in multiple configurations it appears you need to setup multiple lab builds, an advantage of this does mean you can set a different environment per build which does mean you can test different versions of IE.<br />
<br />
<b>Lab Environments cannot have machines added (or removed)</b><br />
You can add/remove machines from templates, but not environments once they've been deployed. This just means you need to be careful that you don't need to customise machines heavily after deploy to get your environment up as you may need to redeploy on occasion.<br />
<br />
<br />
<b>Auto running tests on build in VS starts coded ui tests</b><br />
<div>
Couldn't find a way to disable this, although I heart the latest CTP (2012.2) may be improving something in this area.</div>
<br />
<br />
<b>Conclusion</b><br />
I don't mean for this to be an overly negative post, MTM & LM do seem to be very powerful but I am struggling to figure out how to best utilize them for my needs.Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-58368519248902835112013-02-07T13:18:00.001-08:002013-02-07T18:49:27.364-08:00Tfs Automation - keep user images in sync with active directoryIn a previous post I shows how to <a href="http://bzbetty.blogspot.co.nz/2012/09/tfs-2012-user-image-api.html">set user images to be same as active directory</a> in a console application.<br />
<br />
I have updated this code to run as a recurring <a href="http://msdn.microsoft.com/en-us/library/microsoft.teamfoundation.framework.server.iteamfoundationjobextension.aspx">ITeamFoundationJobExtension </a>.
<br />
The first file creates the job in TFS to run every 24 hours, and runs it once right now.<br />
<br />
The second file is the updated code that is now a TFS Agent Job, this required a few changes to the code to run against the server api instead of the client one. They're fairly similar but the client api tends to be a bit more friendly.<br />
<script src="https://gist.github.com/bzbetty/4734222.js"></script>
<b>Installation</b><br />
Copy the compiled job to c:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\TFSJobAgent\plugins and restart the agent service. Then run the console application to register the job. Finally check the state of the job by looking in the tfs database<br />
<br />
select * from tfs_configuration.dbo.tbl_JobHistory where jobid = 'fa60c04e-c996-413e-8151-15933f5a2bac'Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-27099561967560907472012-12-19T12:53:00.002-08:002013-02-22T13:33:45.603-08:00Tfs Automation - Automatically creating queries when new areas are createdOur testers got sick of setting up new queries whenever they created a new area in TFS so asked me if I could automate it.
<br />
The solution is broken into 2 parts:<br />
<h3>
AreaCreatedSubscriber</h3>
This is ISubscriber that watches for StructureChangedNotification events and queues a one time job to create the queries.<br />
The reason I queued a job instead of just doing the work in this plugin was that when creating the query TFS was throwing an exception on validation (TF51011: The specified area path does not exist.) It seems that there is a slight delay between adding areas and them becoming valid for use in queries. I thought it was a caching issue but even when explicitly clearing the cache on the workitemstore it still happens, I found a post (<a href="http://sstjean.blogspot.co.nz/2011/02/tfs-2008new-area-path-values-are-not.html">New Area Path values are not available in work items</a>) that suggested that tfs subscribes to its own events which then triggers a process of making the area available. This meant I needed to delay the creation of the queries until after all the events had completed, hence the job queue.<br />
Also it is fairly good practice to push any event semi long running tasks into a job as it can delay actions for end users.<br />
This gets installed to <b>c:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\Web Services\bin\Plugins</b><br />
<script src="https://gist.github.com/4340032.js"></script>
<br />
<h3>
CreateDefaultQueriesJob</h3>
The second part is the actual job, its also fairly simple (although crudely written). It reads the Area path out of the event data and creates a folder hierarchy for the queries to live in. It then checks if the queries already exist and if not creates them.<br />
This job should probably be extended/cleanedup to read the queries from an external source, whether it be a WIQL file on the disk, some metadata stored on the team project, or just a special folder in source control.<br />
This is installed into <b>c:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\TFSJobAgent\plugins</b><br />
<script src="https://gist.github.com/4340037.js"></script>
<br />
<h2>
Debugging</h2>
I had a bunch of issues trying to get this to work.<br />
Firstly the TF51011 error - folders were appearing in the shared queries so I knew the plugin was doing something, luckily the exception was being logged to the event logs so it was really easy to find.<br />
After moving the logic to a one time job I tried testing it only to find nothing happened. No folders created and nothing logged in the event logs. I figured that the event was still being fired so it was probably queueing the job, after a quick google I came across a blog article from <a href="https://twitter.com/MrHinsh">Martin Hinshelwood</a> <a href="http://blog.hinshelwood.com/active-directory-groups-not-syncing-with-team-foundation-server-2010/">debugging the TFS Active directory sync job</a> this gave me a bunch of helpful debugging tips.<br />
This lead me to the tfs project collection database<br />
SELECT *
FROM [Tfs_Enlighten].[dbo].[tbl_JobDefinition]
where ExtensionName like '%CreateDefaultQueriesJob'<br />
Returned rows but they weren't much help, jobs were being queued but I had no idea about if they were successful or not. I eventually discovered another table in the tfs_configuration database which contained the jobHistory<br />
select * from tfs_configuration.dbo.tbl_JobHistory
where jobid in (SELECT [JobId]
FROM [Tfs_Enlighten].[dbo].[tbl_JobDefinition]
where ExtensionName like '%CreateDefaultQueriesJob')<br />
Also had one row for every time I queued the job, with the status result of 6, this time I needed to do some diving with ILSpy, which lead me to this enum<br />
<script src="https://gist.github.com/4340211.js"></script>
<br />
ExtensionNotFound = 6 - TFS couldn't find my job! I double and triple checked all my code, and started diving through the JobRunner code in TFS trying to figure out why it wasn't loading. I noticed a few hints of MEF in the code so tried adding an [Export] attribute to the class, still no luck. Enabling the trace log by editing c:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\TFSJobAgent\TfsJobAgent.exe.config I started seeing a curious exception about a plugin being added to a dictionary twice.<br />
<script src="https://gist.github.com/4340255.js"></script>
<br />
Especially interesting as it appears to check if the plugin is already registered in the dictionary before adding it, which makes me think they have a threading bug.<br />
After removing the [Export] attribute and restarting the tfs job service a few times it seemed to come right.<br />
<br />
Update: Apparently there's some new <a href="http://blogs.msdn.com/b/granth/archive/2013/02/13/tfs2012-new-tools-for-tfs-administrators.aspx">web access interfaces to view the status of TFS Jobs</a> (and more), may have meant less database diving had I known at the timeBettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-51340966883422465602012-12-07T17:18:00.004-08:002012-12-19T22:44:09.492-08:00Tfs Automation - Create Builds Automatically for New SolutionsI recently wrote a tfs server plugin that creates new builds automatically whenever you add or branch a solution file. It's fairly simple, but worth sharing.<script src="https://gist.github.com/4238011.js"> </script><br />
<br />
It takes advantage of another piece of code I had previously written (or perhaps found online, I honestly can't remember now) to <a href="http://bzbetty.blogspot.co.nz/2012/12/creating-build-using-tfs-api.html">create builds using the TFS api</a>.<br />
<br />
Installing it is very simple, just build the class into an assembly and copy it to c:\Program Files\Microsoft Team Foundation Server 11.0\Application Tier\Web Services\bin\Plugins you may also need to copy a couple of the referenced dlls to the same folder.<br />
Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-74379670343539933532012-12-07T17:14:00.000-08:002012-12-07T17:14:05.099-08:00Creating a build using the Tfs APIHere is a snippet of code to create tfs builds using the API with a few sensible default settings.<script src="https://gist.github.com/4237978.js"> </script>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-27147992111502788782012-11-14T23:49:00.001-08:002012-11-15T01:37:15.832-08:00Web Code Coverage for Manual TestsFound a great little tool which I think may be new in VS/TFS 2012 (it was possible in previous versions but seemed much harder to setup)<br />
<br />
<b> C:\Program Files (x86)\Microsoft Visual Studio 11.0\Team Tools\Dynamic Code Coverage Tools\CodeCoverage.exe collect /iis /output:c:\outputfile.coverage</b><br />
<br />
It will restart IIS and record a coverage file which can be later opened in visual studio. Great to set going when testers are doing any manual testing in a development environmentBettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-64889037214148715942012-11-14T14:57:00.000-08:002012-11-15T00:53:00.535-08:00Very Simple TFS 2012 Web Access PluginMade a very basic tfs plugin to make the tfs logo a link back to the homepage.<br />
<br />
<strong>Manifest.xml</strong>
<br />
<script src="https://gist.github.com/4077481.js"> </script>
<strong>clickable.min.js</strong>
<br />
<script src="https://gist.github.com/4077478.js"> </script>
Then zip them up together and upload it in the tfs admin section.<br />
<br />
Obviously not exactly the best plugin in the world, considering we actually bypass the whole plugin system, but it works and may be of help to someone.Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-17987043887020389142012-11-10T15:21:00.000-08:002013-02-18T00:10:12.806-08:00TFS ExtensibilityIn this post I hope to outline all the extensibility points in TFS 2012 and come up with a reason I might use it for the company I work for. I would define this as both a major strength and weakness in TFS, there's a lot of powerful stuff exposed to developers but there's not a lot of documentation and a fair bit of it seems half complete which all results in very little adoption. The community around customizing TFS seems fairly small in my opinion, but could be a major win for Microsoft.<br />
<br />
<b>Tfs Client API - .NET</b><br />
A set of .NET classes to interact with the various webservices exposed by TFS, this is the main interaction point from which Visual studio and all components that don't need to be installed on the TFS server directly, for this reason it is extremely powerful.<br />
<br />
We mainly use it to build a custom TFS web frontend for our clients for logging bugs which is a bit more cut down than the TFS web access. The need for this has reduced drastically with the release of TFS 2012 however it does mean we can integrate other systems giving our clients a one stop site for all their needs (rather than requiring them to login to 3-4 different systems). We are careful that users can only see any work items that they create so that they don't require a special TFS CAL. The built in boards and backlog in TFS 2012 require a higher level CAL, but you can build your own backlog/board that works under the limited CAL.<br />
<br />
We also make use of the API in a few ways to help manage the TFS Server. For example automatically granting permissions to TFS teams for any areas/iterations they're associated with, that way I can just assign people to project teams and they'll have the permissions they need. Another example is a set of sanity checks which do things like making sure every solution in source control has an associated build.<br />
<br />
<a href="http://geekswithblogs.net/TarunArora/category/12804.aspx">Tarun Arora</a>, <a href="http://msmvps.com/blogs/vstsblog/archive/tags/Tools+and+Utilities/default.aspx">Neno Loje</a>, and <a href="http://blogs.microsoft.co.il/blogs/shair/archive/tags/TFS+API/default.aspx">Shai Raiten</a> all blog extensively on this subject.<br />
<br />
<b>TFS Build Templates - XAML, .NET</b><br />
TFS Builds in 2010 and higher are controlled by .NET Workflows, this includes a lot of the Lab management functionality. There are lots of builtin activities you can add to your templates and you can write your own activities in Visual studio and include you (or use one of the many activities that are part of the <a href="http://tfsbuildextensions.codeplex.com/">community tfs build extensions</a>).<br />
<br />
I'm not a fan of the editor and using custom assemblies causes all kinds of pain just to <a href="http://tfsbuildextensions.codeplex.com/wikipage?title=How%20to%20integrate%20the%20extensions%20into%20a%20build%20template&referringTitle=Documentation">get the custom activities into Visual Studio</a> so you can add them. You can't easily just grab a component off someones blog, add it to your template, test it and deploy it. This gets even more complex when you've already customized your template so can't just replace the entire template and have to add their changes manually.<br />
<br />
For the above reasons I typically try keep template customizations to a minimum. I believe the only customization I have currently is to set the default build quality of a successful build so that I can make use of <a href="http://tfsdeployer.codeplex.com/">TFS Deployer</a> to deploy the same binaries in turn to each environment for testing. TFS Deployer then makes use of powershell scripts, which I find much easier to customise and test.<br />
<br />
<b>TFS Soap Subscriptions - SOAP</b><br />
The tfs api (mentioned above) <a href="http://msdn.microsoft.com/en-us/magazine/cc507647.aspx">allows you to subscribe to a number of events via soap webservices</a>, this allows your app to get notified when any of the following events occurs in TFS.<br />
<ul>
<li>Work item changes</li>
<li>Check ins</li>
<li>Build completes</li>
<li>Build quality changes (this is what TFS Deployer uses)</li>
<li>Project is created or deleted</li>
<li>Branch moved</li>
<li>Security Acl changes</li>
<li>Iteration/Area changes</li>
</ul>
<div>
Note: The last 4 may be client events only, meaning only the client that triggers the event gets notified.</div>
<div>
<br /></div>
<div>
Back in 2005/2008 we used to use this notification service to send out emails when a workitem was assigned (instead of getting every developer to create a subscription themselves), in 2010 we migrated this to use the server events instead and finally replaced it with a single out of the box team subscription in tfs 2012.</div>
<div>
<br /></div>
<div>
These days I don't make use of any of these events myself (except obviously build quality change). I can imagine subscribing to area/iteration changes to automatically create folders in SharePoint, much like the proposed <a href="http://blog.hinshelwood.com/what-is-the-tfs-automation-platform/">TFS Automation Platform</a> from <a href="http://blog.hinshelwood.com/">Martin Hishelwood</a>, sadly this project never seemed to get off the ground.</div>
<div>
<br /></div>
<div>
<b>TFS Server-side Event Handlers - .NET</b><br />
Location: %Program Files%\Microsoft Team Foundation Server 11.0\Application Tier\Web Services\bin\Plugins<br />
<b><br /></b></div>
<div>
TFS 2010 introduced the ability to create <a href="http://blog.hinshelwood.com/team-foundation-server-2010-event-handling-with-subscribers/">server side event subscribers</a> by implementing the <i>ISubscriber </i>interface and dropping the resulting assembly into the plugin directory and access the same events as the soap subscriptions.</div>
<div>
<br /></div>
<div>
These seemed a lot more reliable than the soap subscriptions, but had to process fairly quickly as it blocked TFS from finishing what it was doing. As mentioned earlier we used this to send email alerts for assigned work items, if you ever did a bulk update (100 work items) TFS would lock up and not respond for up to a minute. The solution was either to spin up a background thread (which I believe had a chance to be killed) or queue a custom TFS Job.</div>
<div>
<br /></div>
<div>
Because TFS waits for you to process it means you can use events as Decision Points to allow or deny certain actions from occurring. This means you can add extra custom validation to workitems and checkins, there are better ways to do both but sometimes you need access to code to do more advanced checks.</div>
<div>
<br /></div>
<div>
Apart from emailing notifications, I've seen a plugin that can <a href="http://embeddedworkitems.codeplex.com/">associate workitems to checkins based on the comments</a> (and heard of someone doing the reverse - setting comments based on the associated workitems).<br />
<br />
Update: I created a few sample server side event plugins that <a href="http://bzbetty.blogspot.co.nz/2012/12/tfs-automation-create-builds.html">automatically creates builds for new solution files</a>, <a href="http://bzbetty.blogspot.co.nz/2012/12/tfs-automation-automatically-creating.html">automatically creates workitem queries for new areas</a><br />
<br />
<a href="http://blogs.msdn.com/b/aseemb/archive/2012/08/11/which-test-management-notifications-are-available.aspx">MTM/TestCase server notifications</a> are also available in 2012.</div>
<div>
<br /></div>
<div>
<b>Check In Policies - .NET</b><br />
Location: Developer machines<br />
<b><br /></b></div>
<div>
Code that can ensure particular requirements are met before a checkin can occur, examples:</div>
<div>
<ul>
<li>Project Compiles</li>
<li>Tests pass</li>
<li>Comments added</li>
<li>WorkItem associated</li>
<li>Passes StyleCop checks</li>
<li>WorkItems associated are in particular areas/queries</li>
<li>Regex patterns on filenames/contents</li>
</ul>
<div>
New policies can be created by extending the <span style="background-color: white; color: #333333; line-height: 20.75px;"><i>PolicyBase </i>class, and deploying them to your development machines.</span></div>
</div>
<div>
<br /></div>
<div>
These are annoying to deploy as they get installed on each developers machine, not the TFS server. They became easier in VS2010 with the <a href="http://blogs.msdn.com/b/jimlamb/archive/2010/03/31/how-to-implement-package-and-deploy-custom-check-in-policy-for-tfs-2010.aspx">ability to install using a vsix</a>, in Visual Studio 2012 it became possible to create <a href="http://msdn.microsoft.com/en-us/library/hh266746.aspx">private extension galleries</a> to <a href="http://blogs.msdn.com/b/visualstudio/archive/2011/10/03/private-extension-galleries-for-the-enterprise.aspx">help deploy extensions within your enterprise</a>. However as far as I'm aware there is still no automated way to deploy one of these when your developers connect to a TFS server.</div>
<div>
<br /></div>
<div>
I try not discourage my developers from checking in so I keep the policies fairly light. We currently require a comment, but encourage other practices just by word of mouth. I think it would be possible to prompt the user if they want to create a code review request in 2012 on checkin, which may be a good way to introduce users to code review, however it would likely be annoying fast and probably still harder than just informing developers manually.</div>
<div>
<br /></div>
<div>
<b>TFS Job Agent - .NET</b><br />
Location: %ProgramFiles%\Microsoft Team Foundation Server 11.0\Application Tier\TFSJobAgent\plugins\<br />
<b><br /></b></div>
<div>
TFS runs a number of jobs in the background using its <a href="http://blogs.msdn.com/b/chrisid/archive/2010/02/15/introducing-the-tfs-background-job-agent-and-service.aspx">job agent and service</a> (Processing the cube, email subscriptions, AD sync). You can either write your own custom tasks by implementing the <i>ITeamFoundationJobExtension </i>interface, or fire off existing tasks when you feel like it.<br />
<br />
Custom Jobs are a good choice when you need to do a lot of work in the background, the problem I mentioned earlier when TFS hanging when trying to update 100+ workitems due to the email plugin could be solved by writing an <a href="http://blogs.microsoft.co.il/blogs/assafstone/archive/2011/07/29/how-to-write-a-robust-tfs-server-plugin-with-job-extensions.aspx">event handler that queues a custom job</a>.<br />
Update: I created a sample server side job plugin that <a href="http://bzbetty.blogspot.co.nz/2012/12/tfs-automation-automatically-creating.html">automatically creates workitem queries for new areas</a><br />
<br />
<b>Warehouse/Cube Customization - .NET</b><br />
Location: %ProgramFiles%\Microsoft Team Foundation Server 11.0\Application Tier\TFSJobAgent\plugins\<br />
<b><br /></b>
TFS builds its own data warehouse from scratch, this is likely because work item fields can be <a href="http://www.blogger.com/"><span id="goog_1678816215"></span>configured to push information through to the warehouse/cube as either a dimension or measure<span id="goog_1678816216"></span></a>. TFS supports the interface <i>IWarehouseAdapter </i>which allows the various parts of TFS to add fields to the warehouse as it is getting built. Developers can also take advantage of this interface and write their own <a href="http://consultingblogs.emc.com/stevewright/archive/2008/07/11/how-i-built-a-team-foundation-server-custom-data-warehouse-adapter.aspx">custom data warehouse adapter</a>.<br />
<br />
The above example is regarding TFS 2008 which I have heard does not work in 2010, unfortunately there seems to be no real documentation from Microsoft and very few people trying to build a custom adapter. I would suggest that maybe a tool like <a href="http://ilspy.net/">ILSpy</a> and looking at the built in adapters would be the way to go.<br />
<br />
In 2010 it looks like the warehouse processing was merged into the job service, and any <i>IWarehouseAdapter</i> have been converted to extend the abstract class<i> WarehouseAdapter. </i>There's also a notion of <i>WebhouseJobExtension </i>which are the <i>ITeamFoundationJobExtension </i>jobs that presumably kick off the schema and data updates int the adapters.<br />
<br />
Microsoft.TeamFoundation.WorkItemTracking.Adapter.WorkItemTrackingWarehouseAdapter looks to be a good example of a warehouse adapter.<br />
<br />
<b>Deployment Services - REST, .NET</b><br />
TFS 2012 update 1 adds in a new build definition and services that allow you to <a href="http://www.windowsazure.com/en-us/develop/net/common-tasks/publishing-with-tfs/">deploy websites to azure</a>. The code behind this actually looks a lot more powerful and gives me the impression that they're going to open it up for others to start publishing not only deployment methods but other services that can interact with TFS using OAuth.<br />
<br />
Using <a href="http://www.wcfstorm.com/wcf/getting-started.aspx">WCF Storm</a> I discovered the following webservices.<br />
<br />
http://tfs:8080/tfs/{TeamProjectCollection}/services/v1.0/ConnectedServicesService.asmx<br />
<br />
<ul>
<li>CreateConnectedService</li>
<li>QueryConnectedServices</li>
<li>GetConnectedService</li>
</ul>
<br />
http://tfs:8080/tfs/{TeamProjectCollection}/Build/v4.0/BuildDeploymentService.asmx<br />
<br />
<ul>
<li>CreateDeploymentEnvironment</li>
<li>GetDeploymentEnvironments</li>
</ul>
<br />
http://tfs:8080/tfs/{TeamProjectCollection}/services/v1.0/StrongBoxService.asmx<br />
<br />
<ul>
<li>GetDrawerContents</li>
<li>GetString</li>
</ul>
<br />
Once you register a deployment service (eg Azure, or a custom built one) you can add environments to it with a custom set of properties (any keyvalue pair). You can then query all enviroments for a given service and pull properties out of its strong box drawer.<br />
<br />
I haven't looked at the workflow activities at all to see if they would support calling a custom service.<br />
<br />
<br />
<b>Custom WorkItem Controls - .NET, Javascript</b><br />
It's fairly well known that you can customize the fields for any workitem, however you can also write your own custom controls to display on workitems. <br />
<br />
With the totally new Web Acess in TFS 2012 there's a <a href="http://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-development.aspx">new way </a>to <a href="http://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-deployment.aspx">write custom controls</a>.<br />
<br />
<br />
There's a codeplex project that contains many <a href="http://witcustomcontrols.codeplex.com/">work item tracking custom controls</a> along with their source, and look like they may be updated for TFS 2012 (the visual studio integration side anyway).<br />
<br />
<b>Web Access Extensibility - Javascript</b><br />
The Web access allows you to upload new <a href="http://bzbetty.blogspot.com/2012/09/tfs-2012-web-access-plugins.html">javascript based plugins</a>, apparently the team were not happy with the state of this at the time of release and are currently reworking them before they make many details public.<br />
<br />
It also appears that the different sections of Web Access are built using the above plugins, two controllers (one for the view, one for json) and an AreaRegistration to register them. It may be possible to create new sections just by creating a new AreaRegistration and dropping it in the bin directory.<br />
<br />
<br />
<b>Update - </b>below are some extensibility points I was either unaware of at the time of writing, or didn't think worth mentioning (visual studio extensions) as everyone already knows about them.<br />
<br />
<b>Test Controller Plugins</b><br />
<div>
I've never seen anyone else use one of these, but they appear to exist and work well. I've written one to help <a href="http://bzbetty.blogspot.co.nz/2013/02/tfs-extensibility-filtering-lab.html">filter available test agents by their machine tags for the current test config</a>.</div>
<br />
<br />
<b>Diagnostic Data Adapters</b><br />
<a href="http://blogs.microsoft.co.il/blogs/shair/archive/2010/04/19/how-to-create-custom-datacollector-in-visual-studio-2010-part-1.aspx">Custom Adapter – Part 1</a><br />
<br />
<br />
<b>MTM Extensions</b><br />
Example Extension <a href="http://visualstudiogallery.msdn.microsoft.com/e79e4a0f-f670-47c2-9b8a-3b6f664bf4ae/">TestScribe for MTM</a><br />
<br />
<b>Visual Studio Extensions</b><br />
<a href="http://msdn.microsoft.com/en-us/library/dd885119.aspx">Developing Visual Studio Extensions</a><br />
<br /></div>
<div>
<b>Summary</b><br />
There's lots of extensibility points in TFS but a number of them seem half finished, or not documented. It could be that most of them are only designed for internal Microsoft use, but it wouldn't take too much to make them very useful for other developers.<br />
<b><br /></b></div>
<div>
<ul>
</ul>
</div>
Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-79412954349296110422012-10-03T21:02:00.005-07:002012-11-15T01:12:26.768-08:00TFS Deployer - Marking builds as deployed in tfs 2012TFS2012 allows you to mark builds as deployed, this is meant to work hand in hand with the azure deployment but I figured it should work with whatever TfsDeployer does too.
<br />
<br />
<script src="https://gist.github.com/4077550.js"> </script>
TFS always seems to throw an error afterwards which i haven't figured out quite yet, so i'm just wrapping it in a try/catch. Even if it didn't throw this exception, I think it will throw another one if you ever try mark the same build as deployed
<br />
<br />
<script src="https://gist.github.com/4077555.js"> </script>
This adds a new row in the "deployed" tab under builds in TFS 2012 web access (looks like visual studio doesn't support this quite yet).
<br />
<br />
It has a redeploy button which just triggers a new build, so it won't actually set the correct build quality to be auto deployed by tfs deployer.
<br />
<br />
Added a discussion to TFS Deployers discussion tab <a href="http://tfsdeployer.codeplex.com/discussions/397983">http://tfsdeployer.codeplex.com/discussions/397983</a><br />
<br />Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-72843586575368304852012-09-28T02:38:00.001-07:002012-11-15T01:14:25.463-08:00TFS 2012 - set user images to be same as active directoryI posted a question on Stackoverflow hoping that someone has an idea of how to use the user image api in tfs 2012.<br />
<br />
<a href="http://stackoverflow.com/questions/12633732/api-to-update-users-image-identity-extended-properties-not-saving">http://stackoverflow.com/questions/12633732/api-to-update-users-image-identity-extended-properties-not-saving</a><br />
<br />
<b>Update</b><br />
Figured it out myself<br />
<br />
<script src="https://gist.github.com/4077563.js"> </script>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-4367706525315931292012-09-24T22:06:00.000-07:002012-12-19T22:34:10.947-08:00TFS 2012 - Groups ReviewedWhen the company I work at first started using TFS 2005 we decided to have only one Team Project<a href="http://msdn.microsoft.com/en-us/library/aa974183(VS.80).aspx"> due to the limit of ~250 Team Projects</a>. Today our root source folder for our main Team Project has a few hundred folders (clients) in it, so do our areas and iteration trees. While it is a bit annoying to maintain, I am certainly thankful of that decision when it comes to upgrading versions of TFS.<br />
<br />
So understandably when I heard about the new Team concept in TFS 2012 I got rather excited. After playing with Teams for a little while in 2012 they are nice, but don't help with management as much as I was hoping for.<br />
<br />
<b>Things I think should be tweaked</b><br />
<br />
<ul>
<li>Work Items - "Assigned To Me" should filter by current team</li>
<li>When creating an alert in a team, I should be able to filter work items by my team iteration or areas rather than selecting it manually</li>
<li>Alerts that can be reused between teams (Email all team members when a work item is created in an area their team is associated to)</li>
<li>Iteration/Area tree views in the admin section should default to filtered to the default area/iteration and what is below it</li>
<li>Source view should select the first team favourite</li>
<li>Builds should filter queued/completed by team favourites</li>
<li>Easier way to assign security to areas based on groups (eg if a group is assocated to an area then allow the group a particular access level)</li>
<li>Allow personal favourites per team</li>
<li>At least some level of integration with reports</li>
<li>Way to change the path of the area that is automatically created for a team</li>
</ul>
<div>
Obviously the extended view is required to setup favourites in the first place, but this can be a toggle on all views. Nothing major, i just feel that it might be nice to restrict my default view a bit more when I'm meant to be looking at a team.</div>
<div>
<br /></div>
<div>
Maybe i'll look into the plugin framework a bit more and see what I can do.</div>
<br />
<br />
<br />Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-27269752697525098462012-09-24T03:26:00.001-07:002013-03-10T11:16:59.959-07:00TFS 2012 - Web Access Plugins<div style="border: 1px solid red; color: red; margin: 5px; padding: 5px;">
<h4 style="margin: 0;">
Update 1</h4>
Found a blog series on how to write custom work item controls (plugins) in javascript (which is quite old, oops). Custom controls don't seem all that exciting to me, but there may be enough information there to develop something else with the information.
<br />
<ol>
<li><span style="color: red;"><a href="http://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-development.aspx">http://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-development.aspx</a></span></li>
<li><span style="color: red;"><a href="http://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-deployment.aspx">http://blogs.msdn.com/b/serkani/archive/2012/06/22/work-item-custom-control-development-in-tf-web-access-2012-deployment.aspx</a></span></li>
<li><span style="color: red;"><a href="http://blogs.msdn.com/b/serkani/archive/2012/07/12/adding-content-files-to-work-item-custom-control-extension-package.aspx">http://blogs.msdn.com/b/serkani/archive/2012/07/12/adding-content-files-to-work-item-custom-control-extension-package.aspx</a></span></li>
</ol>
</div>
<div style="border: 1px solid red; color: red; margin: 5px; padding: 5px;">
<h4 style="margin: 0;">
Update 2</h4>
<br />
<span style="color: red;">Tiago Pascoal has released a Plugin that enhances the Task Board<br />
<a href="http://pascoal.net/2012/09/team-foundation-task-board-enhancer-version-0-3-released">http://pascoal.net/2012/09/team-foundation-task-board-enhancer-version-0-3-released</a><br />
</span></div>
<div style="border: 1px solid red; color: red; margin: 5px; padding: 5px;">
<h4 style="margin: 0;">
Update 3</h4>
<br />
Wrote my own very basic plugin to make the logo a clickable link<br />
<a href="http://bzbetty.blogspot.co.nz/2012/11/very-simple-tfs-2012-web-access-plugin.html">http://bzbetty.blogspot.co.nz/2012/11/very-simple-tfs-2012-web-access-plugin.html</a></div>
<b>Introduction</b><br />
While using the new WebAccess for TFS 2012 I noticed an interesting tab in the administration section named extensions, but it appears Microsoft haven't made the API public yet (1) so I thought I might have a quick dig to see what I could figure out. Because the information has not been made public by Microsoft there's a good chance it will all change in upcoming TFS builds. <br />
<br />
<b>The Plugins</b><br />
Plugins appear to be uploaded as a zip file containing an xml manifest file which defines its name, version, vendor and a few other properties. The author can also specify which other modules it loads after suggesting it has some form of dependency management. <br />
<br />
<script src="https://gist.github.com/4077566.js"> </script>
All files included in the archive appear to be uploaded to a filestore somewhere, but the only required file that I could see was the manifest.xml. Unfortunately whenever I tried making a extension I got the error message "<b>TF400900: Invalid zip archive file : manifest.zip</b>" upon upload, no resolution as of yet.<br />
<br />
Registered plugins are added to a common xml file and serialized to a database or other persistent storage. Neither my TFS_Configuration nor Team Collection databases appeared to contain this file, more than likely it is created when the first plugin is uploaded.<br />
<br />
There's a couple of properties and an ActionFilter that make it look like javascript plays a big part of these plugins. The website itself does reference a file named builtin-plugins.js, which then references a bunch of other javascript files by name.<br />
<br />
<script src="https://gist.github.com/4077568.js"> </script>
The builtin javascript plugins align very nicely with the areas defined earlier, although not a 1 to 1 mapping.<br />
<br />
I curious to see a lack of NuGet, it would have made a great plugin repository as seen in a number of projects now and would have provided a few major benefits such as better dependency management and a distribution channel. Although given Microsoft's recent announcements of other App Stores maybe they plan to take the same route with TFS. <br />
<br />
Another point of interest is that TFSPreview does not appear to have this tab, which would be a curious ommision if they are just javascript scripts.<br />
<br />
<b>Portable Areas</b><br />
<br />
TFS 2012 also seems to make heavy use of MVC areas, each area defined seems to be separated into its own assembly file containing the relevant controllers, viewmodels and other relevant code. Some form of portable area code must have been developed, although i'm guessing nothing was taken from either MvcContrib nor Orchard.<br />
<br />
Interestingly they don't appear to take advantage of the new WebAPI, nor do they use razor for their view engine. But they do typically contain a basic controller for serving views with little logic and an api controller to query via json.<br />
<br />
<br />
While i haven't had the time to dig into this whole thing properly it looks like it should be possible to create complete new tabs/areas using MVC in the new webaccess, or to augment the existing ones using javascript plugins. Considering how much of the UI appears to be created on the clientside this could be a very powerful little framework. I hope Microsoft start releasing information about it soon, if not I'm sure a blogger will.<br />
<br />
<b>References</b><br />
(1) <a href="http://social.msdn.microsoft.com/Forums/en-US/TFSvnext/thread/7696732e-767a-43c7-81d2-c318aeff41ed/">http://social.msdn.microsoft.com/Forums/en-US/TFSvnext/thread/7696732e-767a-43c7-81d2-c318aeff41ed/</a>
<br />
<br />Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-42950187171629312442012-06-03T15:13:00.000-07:002012-12-19T23:08:38.004-08:00Using AutoMapper to copy Metadata from Entities to ViewModels<br />
On my crusade to eliminate common mistakes causing bugs in my projects I found was that my metadata on my entities didn’t always match my viewmodels. I wrote 2 fairly simple providers to copy the metadata from the entity to the ViewModel at runtime which leverages my AutoMapper configuration so it supports field names that are renamed.<br />
<br />
<br />
I use the approach below to automatically copy data annotations from my entities to my view model. This ensures that things like StringLength and Required values are always the same for entity/viewmodel.<br />
<br />
It works using the Automapper configuration, so works if the properties are named differently on the viewmodel as long as AutoMapper is setup correctly.<br />
<br />
You need to create a custom ModelValidatorProvider and custom ModelMetadataProvider to get this to work. My memory on why is a little foggy, but I believe it's so both server and client side validation work, as well as any other formatting you do based on the metadata (eg an asterix next to required fields).<br />
<br />
Note: I have simplified my code slightly as I added it below, so there may be a few small issues.<br />
<br />
<b>Metadata Provider</b><br />
<br />
<script src="https://gist.github.com/4343462.js"></script>
<b>Validator Provivder</b>
<br />
<script src="https://gist.github.com/4343463.js"></script>
<br />
<b>Helper Method Referenced in above 2 classes</b><br />
<br />
<script src="https://gist.github.com/4077599.js"> </script>
<b>Other Notes</b><br />
If you're using dependency injection, make sure your container isn't already replacing the built in metadata provider or validator provider. In my case I was using the Ninject.MVC3 package which bound one of them after creating the kernel, I then had to rebind it afterwards so my class was actually used. I was getting exceptions about Required only being allowed to be added once, took most of a day to track it down.<br />
<br />
<br />
My StackOverflow Post: <a href="http://stackoverflow.com/questions/9989785/technique-for-carrying-metadata-to-view-models-with-automapper/10100042#10100042">http://stackoverflow.com/questions/9989785/technique-for-carrying-metadata-to-view-models-with-automapper/10100042#10100042</a>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-68929239440687169822012-06-03T15:10:00.000-07:002012-12-19T22:47:12.099-08:00Dependency Injection for RouteConstraints<br />
Often I've wanted to check whether something exists in the database in a route constraint, unfortunately MVC doesn't support dependency injection for RouteConstraints out of the box, and due to them being alive for the entire life of the application it isn't that easy. If the scope of the dependency is in request scope, for example, then it will work for the first request then not for every request after that.<br />
<br />
You can get around this by using a very simple DI wrapper for your route constraints.<br />
<br />
<script src="https://gist.github.com/4077607.js"> </script>
then create your routes like this
<script src="https://gist.github.com/4077612.js"> </script>
<br />
<script src="https://gist.github.com/383159e70fa7bab6d056.js"></script>
<p><a href="http://stackoverflow.com/questions/8308642/asp-net-mvc-custom-route-constraints-and-dependency-injection/10692684#10692684">My StackOverflow Post</a></p>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-21257342956028567402012-06-03T15:05:00.000-07:002012-12-19T23:28:41.695-08:00Pagination with AutoMapperI recently posted a method of using AutoMapper in an ActionResult (<a href="http://bzbetty.blogspot.co.nz/2012/06/thoughts-on-actionfilters.html">http://bzbetty.blogspot.co.nz/2012/06/thoughts-on-actionfilters.html</a>). This became an issue when I was trying to return a paginated model to the view, as I wanted to do pagination in the database (on the entities) but AutoMapper had no idea how to map the IPagination result to the ViewModel.<br />
<br />
Result - Build a custom IObjectMapper to do the mapping<br />
<br />
<br />
<b>Resulting Action</b><br />
<br />
<script src="https://gist.github.com/4343542.js"></script>
<b>IObjectMapper</b><br />
<script src="https://gist.github.com/4343545.js"></script>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-68789396701128993922012-06-03T14:59:00.001-07:002016-09-22T03:16:37.851-07:00Updating collections using AutoMapper<br />
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; text-align: left; vertical-align: baseline; word-wrap: break-word;">
By default AutoMapper replaces child lists with a completely new instance only containing the items in the original list. Because of the way EF works you need to change the existing items in the list for it to track changes as updates instead of adds. This method also means deletes can be tracked succesfully.
</div>
<div style="background-color: white; border: 0px; clear: both; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; margin-bottom: 1em; padding: 0px; text-align: left; vertical-align: baseline; word-wrap: break-word;">
<b style="background-color: white;">Basic steps were</b>
</div>
<div style="background-color: white; border: 0px; clear: both; margin-bottom: 1em; padding: 0px; text-align: left; vertical-align: baseline; word-wrap: break-word;">
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif; font-size: 14px; line-height: 18px;">Ensure the destination collection is loaded from db and attached to the object graph for change tracking</span>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;"> .ForMember(dest => dest.Categories, opt => opt.UseDestinationValue())</span></span>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;">Then create a custom IObjectMapper for mapping IList<> to IList<T> where T : Entity</span></span>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;">The custom IObject mapper used some code from http://groups.google.com/group/automapper-users/browse_thread/thread/8c7896fbc3f72514</span></span>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<script src="https://gist.github.com/4343557.js"></script>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;">Finally one last piece of logic to check all Id's in targetCollection exist in sourceCollection and delete them if they don't.</span></span>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;"></span></span>
</div>
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<div style="border: 0px; clear: both; margin-bottom: 1em; padding: 0px; vertical-align: baseline; word-wrap: break-word;">
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;">It wasn't all that much code in the end and is reusable in other actions.</span></span><br />
<span style="font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif;"><span style="font-size: 14px; line-height: 18px;">
<br />
</span></span>
<span style="background-color: white; font-family: "arial" , "liberation sans" , "dejavu sans" , sans-serif; font-size: 14px; line-height: 18px; text-align: left;">My Stackoverflow Post: </span><a href="http://stackoverflow.com/questions/9739568/when-using-dtos-automapper-nhibernate-reflecting-changes-in-child-collections/9856360#9856360" style="background-color: white; font-family: Arial, 'Liberation Sans', 'DejaVu Sans', sans-serif; font-size: 14px; line-height: 18px; text-align: left;">http://stackoverflow.com/questions/9739568/when-using-dtos-automapper-nhibernate-reflecting-changes-in-child-collections/9856360#9856360</a>
</div>
Recently found a library that does just this - <a href="https://github.com/TylerCarlson1/Automapper.Collection">https://github.com/TylerCarlson1/Automapper.Collection </a></div>
Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.comtag:blogger.com,1999:blog-3135843259072891857.post-38850772118002664212012-06-03T14:50:00.001-07:002012-12-19T23:27:22.981-08:00Thoughts on ModelBinders<br />
<b>Validation</b><br />
Source: <a href="http://www.markeverard.com/blog/2011/07/18/creating-a-custom-modelbinder-allowing-validation-of-injected-composite-models/">http://www.markeverard.com/blog/2011/07/18/creating-a-custom-modelbinder-allowing-validation-of-injected-composite-models/</a><br />
<br />
Custom ModelBinders don’t seem to run validation on the newly created model automatically, so while you may add validation attributes to your model you need to add in some extra code to force validation to occur.<br />
<br />
<script src="https://gist.github.com/4077643.js"> </script>
There may be a class you can override to get this automatically but I haven’t found it yet.<br />
<br />
<b>Entities </b><br />
Source: <a href="http://lostechies.com/jimmybogard/2011/07/07/intelligent-model-binding-with-model-binder-providers/">http://lostechies.com/jimmybogard/2011/07/07/intelligent-model-binding-with-model-binder-providers/</a><br />
<br />
An interesting technique I’ve seen used is using modelbinding to automatically load an entity based on the id passed in. So your actions ask for an entity instead of an Id.<br />
<br />
<script src="https://gist.github.com/4343539.js"></script>
Doesn’t seem like much but it should remove 1 line from most actions (loading the entity from the database). However it requires you to never use your entities as edit models (which you shouldn’t be doing anyway). It also doesn’t allow extra filtering/including of data that I can tell.<br />
<br />
This idea could be extended to work on list pages by creating a filter criteria from all route values (page, sort, search)<br />
<br />
<b>Dependency Injecting Model Binders</b><br />
Source: <a href="http://iridescence.no/post/Constructor-Injection-for-ASPNET-MVC-Model-Binders.aspx">http://iridescence.no/post/Constructor-Injection-for-ASPNET-MVC-Model-Binders.aspx</a><br />
<br />
Out of the box you can’t use dependency injection with ModelBinders, you can however pass objects in when you create them at registration time. If your ModelBinders only take singletons then that approach works, otherwise create a fairly basic modelbinder that takes your kernel as a parameter and when binding method is called use the kernel to create your real model binder complete with full dependency injection.<br />
<br />
<b>DateTimes</b><br />
For a recent projet I didn’t want to use a javascript datetime picker as it was meant to be used on a horrible android tablet, but I still wanted something a bit friendlier than a textbox. I chose to split dates into day/month/year fields, which would be a lot of effort to do to every date manually.<br />
<br />
Instead I made an Editor Template for DateTimes which outputs 3 fields, and a custom ModelBinder that when binding dates looks for 3 fields instead of just 1.<br />
<div>
<br /></div>Bettyhttp://www.blogger.com/profile/08211770157752591198noreply@blogger.com