Dirty Words
Copy/paste internet code kills. Runtime comments on .net development, SharePoint WCM, and software engineering
Thursday, 25 October 2012
SharePoint 2013 RTM on MSDN
Monday, 2 July 2012
Fixing broken Office 2010 icons
Wednesday, 9 March 2011
VS Remote Debugger: Invalid access to memory location
I've been running my Visual Studio 2010 remote debugger as a service for a while now and found the experience to be generally seamless. Every so often, however, things go pear-shaped and Visual Studio throws up it arms when attempting to connect to the remote machine:
Unable to connect to the Microsoft Visual Studio Remote Debugging Monitor named 'my-dev-env'. Invalid access to memory location.
I've found the only way to correct this is by restarting Visual Studio.
Thursday, 3 March 2011
How to determine where an Active Directory object lives
Active Directory's Find… function is pretty handy: by searching from the directory root or any OU, you can search for specific objects by name, etc.
Unfortunately the search results display is a bit barebones and it's never obvious to a non-AD admin like me how to determine where the object actually lives in the hierarchy. Luckily you can drill into a search result item to view an object's properties but unless you're a real AD keener, you still might know how to find the object's location.
To rectify this situation, you'll need to turn on the Advanced Features setting from the Active Directory Users and Computers snap-in's View menu:
The object properties display will now include an Object tab which contains the Canonical name of object field (in other words, the path to the object within the directory):
Tuesday, 15 February 2011
How to reference a user control deployed to the GAC
Warning: I don't consider myself a control developer in the classic sense (although I frequently write web parts for deployment within a SharePoint environment, the scope of that deployment is fairly small by default).
A lot of the functionality I build these days runs client-side, powered by my all-time best friend jQuery. Because of this, I find I'm most productive when I first establish the HTML structure in a static HTML file before moving the mark-up to a control. In the bad old days of complete ignorance, I would have had refactor this HTML and build it programmatically within a custom control—an approach I despise (HTML belongs in mark-up).
To overcome many of the drawbacks to custom control development, I prefer migrating my prototype to a user control (which has a front-end .ascx file) and then loading that control in my web part code-behind or custom field control. Check out the LoadControl documentation for information about how load a user control programmatically.
This works beautifully when the control's code behind is compiled to an assembly destined for deployment to the private bin directory. The user control can be built in isolation with the ascx file and code behind remaining wired up for easy access to Intellisense, etc. At build time, the .ascx file is copied somewhere and deployed somewhere useful (the CONTROLTEMPLATES virtual directory, if you like).
Things get trickier when that assembly is to be deployed to the global assembly cache (aka the GAC). In my case I wanted to do this for a custom field control; although most of the code for that control was already being deployed to the GAC, it made sense to keep these artefacts together in the same project. For my non-SharePoint readers, any assembly going into the GAC has to be strong named and signed (via the project's properties sheet > Signing tab); to add the assembly to the GAC, call gacutil:
gacutil –i "MyAsemblyName.dll"
With that out of the way, assume we've got two projects: the first (MyControls) is a class library outputting a signed assembly intended for the GAC; the second is a simple web site (Web).
The MyControls project contains our user control (for information about how to set this up, refer to my post How to add a web project item to a class library). The MyControls assembly is deployed to the GAC.
The web site project contains a copy of the .ascx user control file from the MyControls project and a web page with a @ Register directive pointing to the project-local .ascx file. The Web project doesn't reference the MyControls project because we want it to load the assembly it depends on from the GAC. The .ascx copy can be done manually but you'll likely want to automate this as a pre-build task.
While the MyControls project will now compile, the Web site project will fail to compile with the error: Could not load type 'MyControls.MyUserControl'. If you're in a SharePoint environment, you'll likely see get this as a parser error when the page is dynamically compiled at first request.
To fix this, you need to add an @ Assembly directive to the top of the .ascx file to reference the MyControls assembly deployed to the GAC. You'll need the assembly name and public key token to flesh out this directive. The assembly name can be retrieved from the project properties sheet (normally it's the same as the project anyway). Then extract the public key token using the strong name application (it's the short value):
sn –Tp "MyControls.dll"
If your AssemblyInfo.cs specifies a version number of 1.0.0.0, your @ Assembly directive should look something like this:
<%@ Assembly Name="MyControls, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=b3de351d91c5d4d2"%>
If you version numbers are automatically updated by some kind of policy or build event, beware you'll also need to update this directive as well, which may prove cumbersome.
This directive can be added to both copies of the .ascx file without impacting the MyControls build or edit-time experience.
Both projects will now compile and run, successfully loading the user control base type (i.e. the code behind) from the GAC.
You can download this solution here.
Wednesday, 9 February 2011
Cannot open a TFS query in Excel
After successfully upgrading from VS2008/TFS2008 to VS2010/TFS2010 in the last few months, I today realised my machine still had an outstanding issue opening TFS queries from Visual Studio in Excel . After running the query in VS and clicking Open in Microsoft Office –> Open Query in Microsoft Excel, I was the reluctant recipient of this error message and no Excel openage:
Team Foundation Error
TF80012: The document cannot be opened because there is a problem with the installation of the Microsoft Visual Studio v10.0 Team Foundation Office integration components. Please see the Team Foundation Installation Guide for more information.
While a number of solutions were offered, what follows is the complete set of steps I followed to fix the problem in my workstation environment (Windows Server 2008 R2 x64 with Office 2010 x86 and VS2010 RTM + TFS bits):
1. I first repaired Microsoft Visual Studio 2010 Ultimate from Control Panel. This took a while and required a restart of my workstation. All of my extensions and settings were retained (I think). On its own, this didn't fix the problem but others have reported is did for them.
2. From a command prompt running as administrator (I'm in the local administrators on my machine but that's not good enough), I re-registered the TFSOfficeAdd-in.dll. I only ran the x86 command because VS2010 is a 32-bit app and I'm running the 32-bit version of Office on Windows x64; while the same assembly exists in the 64-bit Program Files directory, I'm assuming it's for the 64-bit version of Office 2010 (just guessing):
regsvr32 "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\TFSOfficeAdd-in.dll"
3. Starting Excel from that same command window to ensure Excel started as an admin, I removed the v9.0 Team Foundation Add-In since I noticed it was showing alongside the v10.0 add-in and I wasn't sure if it was wreaking havoc. At this point, the Team menu was visible in Excel when running as admin but not when running as myself. In Excel 2010, you can manage add-ins from the File –> Options menu; click the Add-Ins tab and then choose COM Add-Ins from the Manage drop down.
4. I finally opened Excel again as myself and enabled the Team Foundation Add-In (v10.0). The Team menu now appeared in Excel.
At this point I can now open a TFS query in Excel.
Note, others have suggested deleting their Windows profile solved the problem for them, at the cost of deleting all of their settings, My Documents, etc. If you go down that path, be careful!
Tuesday, 8 February 2011
Windows Server 2003 x64 on Hyper-V Driver Issues
Installing the 64-bit version of Windows Server 2003 requires service pack 2 and installation of the Hyper-V Integration Services.
Before upgrading RTM and installing the integration services, one of guys was having a bear of a time getting the network card to appear in the guest.
Inspecting video and audio files
I've been using a handy little tool called MediaInfo to inspect some of the .flv files we display in the westernaustralia.com banner space and diagnose encoding differences.
The free tool displays all sorts of information about the audio and video streams:
Wednesday, 19 January 2011
Centralising global TFS alerts/notifications
TFS email alerts are critical to keeping your team informed about changes in the TFS projects they care about. At the very least, most users probably want to know when they've been assigned a work item.
Although Visual Studio 2010 includes the Alerts Explorer (Team –> Alerts Explorer) for signing yourself up for alerts, there's no obvious way to do the same thing for a group of users. Adding custom business logic into the mix really means you'll need to find a better alternative.
Behold! My latest Codeplex project is live, I call it TFS Global Alerts:
http://tfsalerts.codeplex.com/
When we last faced this problem with Visual Studio Team System 2008, we landed on a solution from vertigo.com--I'd link to the original blog post but it's been removed from the site. Moving forward a few years, it was recently time to upgrade our TFS 2008 install to TFS 2010 and the question naturally arose about what we do with alerts: continue using the Vertigo web service or not?
The custom logic originally added to the Vertigo solution was flailing a bit due to the kludge of time so we decided to refactor the current solution to better meet our needs and keep everything working with TFS 2010. I've uploaded a generalised version of the end result for your alerting enjoyment as an example of handling TFS events in a web service (you may want to follow the links below for alternatives based on Windows services and event listeners).
The Solution
TFS Global Alerts is, at its core, a web service containing a single public method:
[WebMethod]
public void Notify (string eventXml)
Notify() accepts a single parameter, a string containing XML detailing the change that occurred and some information about the work item itself. The Notify() method signature changed slightly from TFS 2008: it previously included a second string parameter, tfsIdentityXml. I removed this parameter to get things wired up successfully with TFS 2010.
Most elements in the eventXml look a bit like this—note the OldValue and NewValue child elements:
<Field>
<Name>State</Name>
<ReferenceName>System.State</ReferenceName>
<OldValue>Active</OldValue>
<NewValue>Resolved</NewValue>
</Field>
With the Notify() method called and most of the data you need at hand, sending an email to the relevant parties is then quite simple. TFS Global Alerts does some additional work to exclude the person who made the change from receiving a notification about that change (presumably they know what they've just done!) and avoid sending notifications about code check-ins linked to a work item.
The only real complexity in this code is retrieving an email address for each user from Active Directory. In our production environment I found TFS listed users by display name however in development, with TFS running as a service account in the dev domain, users were returned as domain\username. In production, if a user had multiple accounts (some of our admins), their name was returned as "First Last (domain\username)".
In terms of deployment, I simply deploy the web service to the web server hosting TFS itself and TFS web access.
The notification system hangs off TFS' own event subscription tool, bissubscribe.exe (you'll find it at C:\Program Files\Microsoft Team Foundation Server 2010\Tools\bissubscribe.exe). TFS raises events for all sorts of different happenings and bissubscribe.exe allows you to subscribe an email address or SOAP web service to handle those events.
Since I had some problems creating a server-level subscription, here's the command I use to create a project collection subscription (which captures all events in our case):
bissubscribe /eventType WorkItemChangedEvent /address http://localhost:8080/{vdir_path}/Alerts/WorkItemChanged.asmx /collection http://localhost:8080/tfs/{project_collection_name}
Result:
TF50001: Created or found an existing subscription. The subscription ID is 36
Debugging
TFS 2010 only sends alerts every two minutes by default and events subscribed to via bissubscribe.exe adhere to the same policy. This can be a bit annoying when you're developing so you may want to dial down the batch wait time. I've included a Powershell script in the solution to configure this but otherwise, check out chrisid's post on the subject.
For additional help debugging bissubscribe, Grant Holliday has some useful tips.
Finally, don't forget to actually configure your TFS server to send email!
Resources
- Creating your own event handler for the TFS Event Handler Service
- TFS Event Handler (Codeplex project)
- TFS Event Handler for Team Foundation Server 2010
- Team Foundation Server Event Service
Wednesday, 12 January 2011
How to change the service accounts used by TFS 2010
As with many Microsoft products running with specific service accounts, TFS offers an easy way to change the service account it uses or update the account password.
You can do this manually by mucking with application pool identities and database permissions but there's a much easier way using the TFS Administration Console.
Assuming you have the right permissions, fire up the console and click into the Application Tier node; in the Application Tier Summary you'll find two links: Change Account and Reapply Account.
Change Account allows you to change the service account used by the system while Reapply Account allows you to change the password for the currently configured account. You can easily switch from Network Service to a local or domain account (or vice versa) but be sure to grant any local/domain account the Log on as service permission.