다음을 통해 공유


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

  • Anonymous
    July 22, 2012
    thanks for the post.

  • Anonymous
    August 10, 2012
    Thanks, Good Post keep up!

  • Anonymous
    August 12, 2012
    The comment has been removed

  • Anonymous
    August 12, 2012
    The comment has been removed

  • Anonymous
    August 12, 2012
    "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

  • Anonymous
    August 13, 2012
    Thanks :-)

  • Anonymous
    October 15, 2012
    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.

  • Anonymous
    October 15, 2012
    The comment has been removed

  • Anonymous
    November 14, 2012
    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.

  • Anonymous
    November 15, 2012
    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

  • Anonymous
    December 12, 2012
    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.CSharpValue1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] with name &#39;CSharpValue&lt;String&gt;&#39;. &nbsp;Exception was: System.IO.IOException: The process cannot access the file &#39;C:SassEnablementDEVBranchesTest ProjectSEP ProvisioningCustom ActivitiesobjDebugTemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs&#39; because it is being used by another process. &nbsp; at System.Activities.WorkflowApplication.Invoke(Activity activity, IDictionary2 inputs, WorkflowInstanceExtensionManager extensions, TimeSpan timeout)   at System.Activities.WorkflowInvoker.Invoke(Activity workflow, IDictionary2 inputs, TimeSpan timeout, WorkflowInstanceExtensionManager extensions) &nbsp; at System.Activities.WorkflowInvoker.Invoke(Activity workflow, IDictionary2 inputs)   at System.Activities.Validation.ActivityValidationServices.RunConstraints(ChildActivity childActivity, ActivityCallStack parentChain, IList1 constraints, ProcessActivityTreeOptions options, Boolean suppressGetChildrenViolations, IList1& validationErrors) C:SassEnablementDEVBranchesTest ProjectSEP ProvisioningCustom ActivitiesCommonProcessNewProvisioningOrder.xaml Please help me out... Regards Deepa
  • Anonymous
    December 17, 2012
    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

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

  • Anonymous
    January 10, 2013
    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

  • Anonymous
    February 05, 2013
    please vote on the uservoice page: visualstudio.uservoice.com/.../3288596-to-allow-the-usage-of-build-controller-2010-with-t

  • Anonymous
    April 03, 2013
    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.

  • Anonymous
    May 09, 2013
    Hi Riyanka, This error seems to indicate that you haven't fully upgraded all your custom assemblies. Thanks, Jason

  • Anonymous
    May 11, 2013
    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

  • Anonymous
    May 12, 2013
    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

  • Anonymous
    September 03, 2013
    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?  

  • Anonymous
    September 17, 2013
    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

  • Anonymous
    September 23, 2014
    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.

  • Anonymous
    June 22, 2015
    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.

  • Anonymous
    June 23, 2015
    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

  • Anonymous
    August 03, 2015
    I have a customized 2010 TFS Build Template. Is it possible for me to convert this template as 2012 template?

  • Anonymous
    December 11, 2015
    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.

  • Anonymous
    January 04, 2016
    @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.