TFS 2012 – Cleaning up Workflow XAML files (AKA removing versioned namespaces)


If you haven’t run into this problem in TFS Build 2012 yet, you probably will…

Problem:

After Upgrading your Visual Studio client or your build machine from 2010 to 2012, you start seeing errors like these…

  1. Opening a XAML file in Visual Studio 2012 – System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. —> System.Exception: The component “Microsoft.TeamFoundation.Build.Workflow.Design.InvokeForReasonDesigner’ does not have a resource identified by the URI…
  2. Editing a build definition in Visual Studio 2012 – Unable to cast object of type ‘Microsoft.TeamFoundation.Build.Workflow.Activities.TestSpecList’ to type ‘System.Collections.Generic.List`1[Microsoft.TeamFoundation.Build.Workflow.Activities.TestSpecList]’.      
  3. Editing a build definition in Visual Studio 2012 – [A]Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings cannot be cast to [B]Microsoft.TeamFoundation.Build.Workflow.Activities.BuildSettings. Type A originates from ‘Microsoft.TeamFoundation.Build.Workflow, Version=10.0.0.0, …’ in the context ’Default’ at location …. Type B originates from ‘Microsoft.TeamFoundation.Build.Workflow, Version=11.0.0.0, …’ in the context ‘Default’ at location ….
  4. Building on a TFS 2012 Build Machine – Validation Error: The private implementation of activity ‘1: DynamicActivity’ has the following validation error: Compiler error(s) encountered processing expression “BuildDetail.BuildNumber”. Type ‘IBuildDetail’ is not defined.

 

Background:

Due to a bug in one of our activities in TFS 2010, the Visual Studio Workflow Designer would add versioned namespaces to the XAML file upon saving it. They look something like this:

xmlns:mtbw1=”clr-namespace:Microsoft.TeamFoundation.Build.Workflow; assembly=Microsoft.TeamFoundation.Build.Workflow, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”

The version number in this string forces Workflow to attempt to load the 10.0.0.0 assemblies. These assemblies contain the same types as the 11.0.0.0 assemblies and cause all kinds of problems.

[Update: 9/27/2012]

There is another cause for some of these errors. In addition to checking your XAML, you should also look for any custom assemblies in the Controller’s Custom Assembly Path that are compiled against the TFS 10.0 assemblies. Most likely, you will need to recompile any custom assemblies you have against the latest released copies of the .Net framework and the TFS assemblies.

[Update: 10/24/2012]

Fixed a bug in the code below that was removing too many of the namespaces. Some unused namespaces can still be required by the VisualBasic expressions.

Workaround:

Unfortunately, there isn’t a good way for us to fix this problem. Even if we fixed Visual Studio 2010 so that it doesn’t cause the problem, but we can’t prevent those who already have it. The best I could do is create a small program that will strip out all unused namespaces like these from the XAML. Here’s the source code…

[UPDATE: I added some code below to leave in the namespaces listed in the mc:Ignorable attribute found at the top of the file. If you have something listed there that isn’t defined, you will not be able to open the XAML in the Workflow Editor.]

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;

namespace XAMLCleaner{
    class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 2)
            {
                if (args[0].StartsWith("/report", StringComparison.OrdinalIgnoreCase))
                {
                    XamlCleaner.RemoveUnusedNamespaces(args[1], args[1], true);
                }
                else
                {
                    XamlCleaner.RemoveUnusedNamespaces(args[0], args[1], false);
                }
            }
            else if (args.Length == 1)
            {
                XamlCleaner.RemoveUnusedNamespaces(args[0], args[0], false);
            }
            else
            {
                PrintUsage();
            }
        }

        static void PrintUsage()
        {
            Console.WriteLine();
            Console.WriteLine("Usage:");
            Console.WriteLine(" XAMLCleaner.exe <xaml_file> [<new_xaml_file>]");
            Console.WriteLine(" - removes unused namespaces from xaml_file and");
            Console.WriteLine(" optionally puts the changes in new_xaml_file.");
            Console.WriteLine(" XAMLCleaner.exe /report <xaml_file>");
            Console.WriteLine(" - prints the unused namespaces found in xaml_file.");
            Console.WriteLine();
        }
    }

    class XmlNamespace 
    {
        public String Prefix { get; set; }
        public String Namespace { get; set; }
        public String Declaration { get; set; }
    }

    static class XamlCleaner
    {
        public static void RemoveUnusedNamespaces(String inputFile, String outputFile, bool reportOnly)
        {
            List<XmlNamespace> namespaces = new List<XmlNamespace>();
            List<String> ignoredNamespaces = new List<String>();
            String fileContents = File.ReadAllText(inputFile, Encoding.UTF8);
            String newFileContents = fileContents;
            Regex ignorableRegex = new Regex("(:Ignorable=\")(.*?)\"", RegexOptions.Singleline);
            Regex regex = new Regex("(xmlns\\:)(.*?)=\"(.*?)\"", RegexOptions.Singleline);
foreach(Match m in ignorableRegex.Matches(fileContents)) { ignoredNamespaces.AddRange(m.Groups[2].Value.Split(' ')); }             foreach(Match m in regex.Matches(fileContents))
            {
                namespaces.Add(new XmlNamespace() { Prefix = m.Groups[2].Value, Namespace = m.Groups[3].Value, Declaration = m.Groups[0].Value });
            }

foreach (XmlNamespace ns in namespaces) {                 // Only remove namespaces that are not in the Ignore section
                // and contain version=10
                // and are not used in the file
                if (!ignoredNamespaces.Contains(ns.Prefix) &&
                    ns.Namespace.IndexOf("version=10", StringComparison.OrdinalIgnoreCase) >= 0 &&
                    !fileContents.Contains(ns.Prefix + ":"))
{ Console.WriteLine("Removing unused namespace: {0}", ns.Declaration); newFileContents = newFileContents.Replace(ns.Declaration, String.Empty); } } if (!reportOnly) { File.WriteAllText(outputFile, newFileContents, Encoding.UTF8); } } } }

 

Examples:

>XAMLCleaner /report DefaultTemplate.xaml

This will list all the unused namespaces, but will not actually change the file

>XAMLCleaner DefaultTemplate.xaml

This will remove all unused namespaces and overwrite the file that was read in.

>XAMLCleaner DefaultTemplate.xaml NewTemplate.xaml

This will remove all unused namespaces and write a new file called NewTemplate.xaml.

We don’t know exactly how we will end up fixing this issue since we don’t want to forcibly change all build process templates. So, for now you will have to fix these up yourself. I recommend a one time conversion of the files and then simply don’t edit them in Visual Studio 2010 any more.

Hopefully this post will save some of you some time.

Comments (27)

  1. teoman says:

    thanks for the post.

  2. Thanks, Good Post keep up!

  3. Carsten Jacobsen says:

    I got the error:

    TF215097: An error occurred while initializing a build for build definition xxxNew Build Definition: 'sad' prefix is not defined. Line 1, position 11.

    Can you help me?

    Thanks

  4. jacobsen says:

    Hi Jason

    I got the error below when run the program

    TF215097: An error occurred while initializing a build for build definition xxxNew Build Definition 2: 'sad' prefix is not defined. Line 1, position 11.

    Any Idea what I do wrong?

  5. "sad" is usually used for the System.Activities.Designer namespace. Open your xaml file in notepad and see if there are references that include "sad:" My tool may have a bug in regards to how that namespace is used. I will see if I can get a xaml file to produce the same error. The fix should be to remove all of the sad references. But take a close a look at them to see if you need them.

    Jason

  6. jacobsen says:

    Thanks 🙂

  7. TFSUser says:

    How about also removing all presentation data? Mixing together code and presentation is so outdated and prevents from treating your XAMLs as part of code — open it in this awful designer, save — and it will change the file.

  8. Jeremy says:

    I did see all these errors with the addition of another one.  So, just an FYI for others that are looking at this post with build issues after upgrading. I was having an issue after converting my build process with the "LabelSources" activity with the version spec of "W" for workspace.  After I changed the activity from LabelSources to LabelWorkspace with the same parameters save the version spec, the problem seemed to go away.  The exception was the following:

    Exception Message: Object reference not set to an instance of an object. (type NullReferenceException)

    Exception Stack Trace:    at Microsoft.TeamFoundation.Build.Workflow.Activities.LabelSources.ParseVersionSpec.Execute(CodeActivityContext context)

      at System.Activities.CodeActivity`1.InternalExecute(ActivityInstance instance, ActivityExecutor executor, BookmarkManager bookmarkManager)

      at System.Activities.Runtime.ActivityExecutor.ExecuteActivityWorkItem.ExecuteBody(ActivityExecutor executor, BookmarkManager bookmarkManager, Location resultLocation)

    My custom build was a derivative of the default template in TFS 2010 prior to upgrading.  So, I hope this tidbit helps someone else as well.

    Jeremy

  9. You noted, "Due to a bug in one of our activities in TFS 2010…".  When will there be a fix of this available? I prefer to wait in the TFS2012 upgrade until a fix for this is out.

  10. The fix for 2010 can be found here…

    support.microsoft.com/…/2743227

    This fix will not update your xaml files. However, it should keep the problem from happening again if you manually fix the XAML files.

    Thanks,

    Jason

  11. Deepa says:

    I have recently converted my workflow service from 2010 to 2012 .. I started seeing the below errors for the xaml files..

    1) Object reference  not set to an instance of an object.

    2) This below compiler error comes as soon as I open the xaml files

    Internal constraint exception while running constraint with name 'Constraint<Activity>' against activity of type Microsoft.CSharp.Activities.CSharpValue`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] with name 'CSharpValue<String>'.  Exception was: System.IO.IOException: The process cannot access the file 'C:SassEnablementDEVBranchesTest ProjectSEP ProvisioningCustom ActivitiesobjDebugTemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs' because it is being used by another process.

      at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary`2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)

      at System.Activities.WorkflowInvoker.Invoke(Activity workflow, IDictionary`2 inputs, TimeSpan timeout, WorkflowInstanceExtensionManager extensions)

      at System.Activities.WorkflowInvoker.Invoke(Activity workflow, IDictionary`2 inputs)

      at System.Activities.Validation.ActivityValidationServices.RunConstraints(ChildActivity childActivity, ActivityCallStack parentChain, IList`1 constraints, ProcessActivityTreeOptions options, Boolean suppressGetChildrenViolations, IList`1& validationErrors)

    C:SassEnablementDEVBranchesTest ProjectSEP ProvisioningCustom ActivitiesCommonProcessNewProvisioningOrder.xaml

    Please help me out…

    Regards

    Deepa

  12. Hi Deepa,

    I am not a Workflow expert. Your workflow does not appear to be TFS Build related. You may want to post your question on the Windows Workflow forum if you haven't already.

    Jason

  13. Christopher Painter says:

    Regarding recompiling custom code assemblies against the 2012 versions, is it possible to build against 2010 but allow it to run against 2012?  

  14. Unfortunately, this is a bit tricky. We rely on the 4.5 .net framework. So, our build machines can't just have the 4.0 framework installed. This makes it difficult to build "properly" against 2010 sources. We are working on a solution to this problem right now. Hopefully, the solution will make this process easier.

    Jason

  15. Riyanka Daga says:

    Jason,

    I have just finished Upgrading from TFS2010 to TFS2012. And when I try to build i get the following Error:

    TF215097: An error occurred while initializing a build for build definition PredProtectPredP_DEV_BuildDeploy: Exception Message: The root element of the build process template found at $/SCM_Tool/Stable/BuildProcess/BuildTemplates/InterthinxBuildAndDeployProcessTemplate.xaml (version C48815) is not valid. (The build process failed validation. Details: Validation Error: Compiler error(s) encountered processing expression "Microsoft.TeamFoundation.Build.Workflow.BuildVerbosity.Normal".'BuildVerbosity' is ambiguous in the namespace 'Microsoft.TeamFoundation.Build.Workflow'.

    I read your post regarding re-building the Custom Tempalte and making it point to VS11 assemblies. Please can you provide more details on the steps to do that.

  16. Hi Riyanka,

    This error seems to indicate that you haven't fully upgraded all your custom assemblies.

    Thanks,

    Jason

  17. Scott Delicot says:

    We are getting the following error when trying to run our Builds from an upgraded TFS 2010 server to TFS 2012.3 RC. specified argument was out of the range of valid values. Parameter name: column. We are using our TFS 2010, yes 2010, Build Controller and 2010 Build agents (installed on SRV 2003 so can't install 2012) against our newly upgrade TFS 2012.3 server. Again we have upgraded to 2012.3 and are trying to use the build backward compatibility was released with TFS 2012.2 (update 2)  Here is a screen shot: http://i.imgur.com/bo1jRXd.png

  18. Hi Scott,

    This is a known bug that we discovered near the end of development for TFS 2012.3. However, we did include it in the final version of Update 3. If you still experience the error after you get the final version of Update 3, please file a bug against TFS on Microsoft's Connect site.

    The only workaround in the mean time is to turn off the UpdateWorkItems flag on the AssociateChangesetsAndWorkItems activity. This will cause workitems not to be associated with the build.

    Sorry we didn't catch this bug sooner.

    Thanks,

    Jason

  19. Jason,  it appears I have just started to get problem 2 above.  We have a 2010 build server that we use for all our release builds.  It just does two things outside of the default.  It updates the assemblies then looks for MSI files.  I noticed it wasn't building the "mixed platforms" configuration so it isn't building the MSI.  

    A few months ago I went through and manually changed the template to remove all references to 10.0.  Now the just state the DLL.  Anything I can do about it? Does Update 3 of TFS/VS help with this?  

  20. Check out my latest post on upgrading to 2012…

    blogs.msdn.com/…/upgrading-your-build-definitions-from-tfs2010-to-tfs2012.aspx

    I don't think Update 3 will help with these issues 🙁

    Jason

  21. Derek Evermore says:

    I received the following errors related to the labeling of the build changesets while using the UpgradeTemplate.xaml

    The "Label" task failed unexpectedly.

    System.Activities.InvalidWorkflowException: The following errors were encountered while processing the workflow tree:

    'VisualBasicValue<LabelChildOption>': Compiler error(s) encountered processing expression "Microsoft.TeamFoundation.VersionControl.Client.LabelChildOption.Fail".

    'LabelChildOption' is ambiguous in the namespace 'Microsoft.TeamFoundation.VersionControl.Client'.

    The issue was that I was loading a custom MSBuild assembly task (one that I had written) in my TFSBuild.proj… this custom assembly task has a reference to another custom assembly which contained references to the 10.0.0.0 TFS assemblies. Even though there were no calls being made to any TFS API objects the chain of references was causing the 10.0.0.0 assemblies to get loaded in the build process and led to the ambigous naming errors. I recompiled my custom assemblies against the 11.0.0.0 assemblies and this fixed the issue.

  22. Ambhrin Dhar says:

    Hi James – I am running into an issue and after reading through your blogs it makes me think I might be getting closer to the actually but certainly not there yet..

    I have some custom build templates that references to custom activities. These are under the "ProjectBuildProcessTemplates" Folder. We run the daily builds and they work just fine.. But when I checked out the template just my itself on my local machine running vs 2013, it is unable to resolve the custom activity dll's..we are using tfs 2013.. Any help wil be greatly appreciated.

  23. If you want to edit the XAML in the VS Workflow Designer, you will have to create a WF project that has all the correct references and add the XAML to that project. It is quite painful in my opinion. I generally just use a text editor.

    thanks,

    Jason

  24. Chirag says:

    I have a customized 2010 TFS Build Template. Is it possible for me to convert this template as 2012 template?

  25. Binson says:

    I am trying to reuse the TFS 2010 custom build with VS2013. We just upgraded VS alone and no plan of upgrading TFS2010.  Is there any place I use as the starting point.

  26. @Binson. If you aren't going to upgrade your server, you should keep VS 2010 installed on some machines and use those to edit your definitions. We had some compat problems with 2010 that we resolved in later versions, but the VS 2010 should always work against a 2010 server.