Customize Team Build 2010 – Part 4: Create your own activity

by Ewald Hofman 29. April 2010 21:21

In the series the following parts have been published

  1. Part 1- Introduction
  2. Part 2- Add arguments and variables
  3. Part 3- Use more complex arguments
  4. Part 4- Create your own activity
  5. Part 5- Increase AssemblyVersion
  6. Part 6- Use custom type for an argument
  7. Part 7- How is the custom assembly found
  8. Part 8- Send information to the build log
  9. Part 9- Impersonate activities (run under other credentials)
  10. Part 10- Include Version Number in the Build Number

In this post I will show you how you can add your own custom activities. Debugging the customizations is not the best experience. In this post I will show you how I modified the build process template. If you have a better idea, feel free to ping me (because I am never to old to learn :) )

  1. Open a new visual studio 2010 editor and create a new solution with 2 projects (of type Class Library) called Template and BuildTasks. One of the projects is for the custom code and custom activities, the other one to modify the build process template.
  2. Add a project reference from the Template project to the BuildTasks project

    image
  3. Add in the BuildTasks project a reference to the following assemblies:
    1. From c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0
      1. Microsoft.TeamFoundation.Build.Client.dll
    2. System.Activities
  4.   And add the following references to the Template project
    1. From c:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0
      1. Microsoft.TeamFoundation.Build.Client.dll
      2. Microsoft.TeamFoundation.VersionControl.Client.dll
      3. Microsoft.TeamFoundation.WorkItemTracking.Client.dll
    2. From C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies
      1. Microsoft.TeamFoundation.Build.Workflow.dll
      2. Microsoft.TeamFoundation.TestImpact.BuildIntegration.dll
    3. From C:\Windows\assembly\GAC_MSIL\Microsoft.TeamFoundation.TestImpact.Client\10.0.0.0__b03f5f7f11d50a3a
      1. Microsoft.TeamFoundation.TestImpact.Client.dll
    4. System.Activities
    5. System.Drawing
    6. System.ServiceModel
    7. System.ServiceModel.Activities
    8. System.Xaml
  5. Create a copy of the DefaultTemplate, call it CustomTemplate.xaml and put it in the folder where the Template project is located. Add the file to the project, and set the build action to XamlAppDef. If you don't see the XamlAppDef option, then add an activity to the Template project to add the correct references and then delete it again.
  6. Add to the BuildTasks project two folders called “Activities” and “Library”

    image
  7. Right click on the Activities and choose Add –> New Item. Choose from the dialog to only show the Workflow templates. And choose the Code Activity. Give it the name DoExcitingThings, and close the dialog with OK

    image
  8. In the code we see some interesting things. As we have seen in earlier posts in this series the build heavily relies on activities (such as this code activity) and you can configure activities with Arguments which can be set with the properties window. In the code you decorate every property you want to see in the properties window with the InArgument (or InOutArgument). When you want to get the value of this property, you must use the context to get the value. The property itself won’t hold the value!

    image
  9. I have modified the class so we can see the purpose and usage of the different argument types

    image
  10. We also have to indicate that our activity is used by the Build Controller and the Build Agents. To do this, add a using to the Microsoft.TeamFoundation.Build.Client and decorate the class with the following statement: [BuildActivity(HostEnvironmentOption.All)] 

    If you forget to specify this argument you encounter the error

    "TF21509:An error occured while initializing a build definition \CustomBuildTasks\BuildName:Cannot create
    unknown type '{clr-namepace:NamespaceName,asembly=AssemblyName}Activityname'."

    image
  11. Build the solution
  12. Open the CustomTemplate.xaml file and open the toolbox. In the toolbox we see our new DoExcitingThings activity added.

    image
  13. Drag ‘n drop this activity after the “Get the Build” activity.

    image
  14. When you open the properties window you see the three arguments we have added to our exciting activity.

    image
  15. Lets put in a textual value in all the three arguments

    image
  16. There are errors for the two arguments that have an output value, because it needs to store the value somewhere. So to solve this, you must create a variable for the correct scope (see part 2) and use the variable as value for the argument. You can either set the value for the variable in the variable window itself

     image

    Or you can use the Assign activity which you can find in the Primitives tab

     image
  17. Finally add a WriteBuildMessage to show the values of the arguments after the DoExcitingThings activity.
  18. Save the changes and check-in your CustomTemplate.xaml.
  19. Now execute a build based on the CustomTemplate. The build will fail unfortunately with the following error message

    image
  20. The build controller was unable to load our exciting Code Activity, which is obvious. It is pretty simple to solve this. Open the dialog to manage the build controllers. You can find it when you right click the Builds node for the team project in the team explorer

    image
  21. This will open the following dialog

    image
  22. Select the Controller and open the Properties

    image
  23. You see there a box to specify the path for custom assemblies. This means that you need to have one common location where you store all the assemblies that hold customizations (or just use one assembly that holds all the customizations). Since the assembly is not added by default to source control, you need to add the assembly first to Version Control and then specify that path in here.

    image
  24. Be aware that when you add a file to Source Control that it is marked read-only. So do not use the bin or obj folder! You might want to add some logic to the Post-build event in the C# project to automatically create a copy of the assembly and automatically check it in to Version Control.

    You can use for example the following Post-build event:

    "$(DevEnvDir)\TF.exe" checkout "$/CustomBuildTasks/BuildProcessTemplates/CustomActivities/$(TargetFileName)"
    xcopy /y "$(TargetPath)" "$(SolutionDir)..\..\BuildProcessTemplates\CustomActivities"
    "$(DevEnvDir)\TF.exe" checkin "$/CustomBuildTasks/BuildProcessTemplates/CustomActivities/$(TargetFileName)"
  25. When you now run the build, you will get the following result in the build log

     image

Now you have followed the basics how you can can modify the build process template. The following posts will describe how to solve the common scenario’s like building database, BI or setup projects and incrementing the AssemblyVersion.

Go to the next post in this series: Customize Team Build 2010 – Part 5: Increase AssemblyVersion

You can download the full solution at BuildProcess.zip. It will include the sources of every part and will continue to evolve.

Tags: ,

Team Build | VSTS 2010

Comments

5/13/2010 8:34:53 PM #

Steve

Excellent post - in particular all the assemblies references required to adding a project is something that has not been well-documented. Good job here.

Steve United States | Reply

5/20/2010 3:51:22 PM #

Leo Swiontek

First of all I want to thank you so much Ewald for giving such great examples on how to use WF and code to create custom activities.

For the life of me I can NOT get around the setting of the "version control path to custom assemblies" error:
1 error(s), 0 warning(s)
TF215097: An error occurred while initializing a build for build definition \TeamBuildCustomize\MainCont: Cannot create unknown type '{clr-namespace:BuildTasks.Activities;assembly=BuildTasks}DoExcitingThings'.

I have the assemblie checked in under version control ($/TeamBuildCustomize/Main/Build), and I have my Build controller's "Version control path to custom assemblies" path set to this path, but I keep getting the same error.  What the heck am I doing wrong?

Thanks Ewald!

Leo

Leo Swiontek United States | Reply

5/21/2010 8:54:15 AM #

Ewald Hofman

I have seen this error also in the past, but I can't really recall what I did to solve it.

When I dig very deep into my mind, I think adding the workflow to a project that has a reference to the BuildTasks solved my issue.

Did you follow the exact steps in the post?

Ewald Hofman Netherlands | Reply

5/21/2010 9:50:42 PM #

Leo Swiontek

Thanks for the quick reply.  I believe I've added all the correct references and everything.  Ewald, anyway I can get the exact source code you used?  I could try that out and that would prove right away if I did something wrong, or if its a machine issue.  I am developing on a 64bit OS, and building on a 32bit OS.

Leo Swiontek United States | Reply

5/22/2010 11:30:27 AM #

Ewald Hofman

I added the solution to the post

Ewald Hofman Netherlands | Reply

6/1/2010 9:00:31 PM #

Leo Swiontek

Well, here is the real error I'm getting and I don't know why it is looking for BuildTasks.dll in the 'file:///C:\Users\tfs10build\AppData\Local\Temp\BuildAgent\24\' directory.  This error comes from the Event Viewer for the TF Build Services.  My "Version control path to custom assemblies" is set to $/TeamBuildCustomize/Main/TeamBuildCustomizeBin

Service 'TeamBuildCustomize Agent - buildone' had an exception:
Exception Message: Problem with loading custom assemblies: Could not load file or assembly 'file:///C:\Users\tfs10build\AppData\Local\Temp\BuildAgent\24\BuildTasks.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format. (type Exception)

To me Ewald it's like some mapping is screwed up.  Just to let you know that we are still on the VS 2010 Ultimate RC release.  We will soon be upgrading to the RTM release from April.  Any help would be greatly appreciated.  I so want to make this work.

Thanks

Leo Swiontek United States | Reply

6/1/2010 9:11:25 PM #

Ewald Hofman

The problem is not that it cannot find the assembly, but it cannot load it.

I encountered the error with the incorrect format also when mixing with 32 and 64 bit. There are many posts on this subject, like:

www.robertwray.co.uk/.../...as-made-to-load-a.html
blogs.msdn.com/.../...rmat-net-p-invoke-issue.aspx

Ewald Hofman Netherlands | Reply

6/17/2010 8:06:51 PM #

Leo Swiontek

Yup!  That was it Ewald.  Once I compiled / built everything with "Any CPU" this error went away and I was able to get past this step.  Thanks for your article and your help.

Leo Swiontek | Reply

6/1/2010 9:02:39 PM #

Leo Swiontek

I forgot to mention that the error happens anytime an agent restarts that is tied to the WEdgeOne controller, and 2) I'm developing on a x64 box, and building on a x32 box.

Leo Swiontek | Reply

6/8/2010 11:55:10 AM #

Patrick

I have created all and added to source control the XAML and the  BuildTask.dll from the bin directory. When i open the XAML from the source control i looked at the position at which i put my custom activity, but here is a red label:

Activity could not be loaded because of errors in the XAML.

I added the custom assemblies path in the controller properties to my BuildTask.dll assembly.

In the Toolbox i can see my BuildTasks.Activities, but i couldn´t place this in the XAML there is a deny symbol when i drag it over.

Any ideas?

Patrick Germany | Reply

6/8/2010 12:02:00 PM #

Ewald Hofman

It can be possible that the XAML could not load the BuildTasks.dll

See www.ewaldhofman.nl/.../...stom-assembly-found.aspx for more information.

Another option you have is to spin up another instance of Visual Studio and attach it to the first instance of Visual Studio (Debug -> Attach to Process, choose devenv.exe). Then open the Modules window (Debug -> Windows -> Modules) and check whether the BuildTasks.dll is loaded and which version.

Ewald Hofman Netherlands | Reply

6/10/2010 11:33:42 AM #

Patrick

Hi, i tried to use your BuildProcess, i uploaded the CustomTemplate.xaml in the BuildProcessTemplate. The generated DLLs from the Template project: BuildTasks.dll and Template.dll

Under the controller i set correct the path to these assemblies. So when i open the checked in XAML file in the designer i also get the same error Frown
On the build server i couldn´t find the devenv.exe.config because there is no VS2010 installed, only VS2010 Express.

why must i debug my local VS, i couldn´t undertand it.
Any other ideas?

Patrick Germany | Reply

6/10/2010 2:09:24 PM #

Ewald Hofman

Did you check www.ewaldhofman.nl/.../...stom-assembly-found.aspx

Ewald Hofman Netherlands | Reply

6/11/2010 2:53:36 PM #

Padda

Hi,

I'm having the same problem as Patrick. Is it a case whereby the Build uses the Version Control path to custom assemblies, but Visual Studio itself does not. So, if the CustomTemplates.xaml file is in the BuildProcessTemplates and opened from within TFS (Source Control Explorer), it will open the the xaml but any references for custom activities not in GAC or probing paths won't be found?

When I open the CustomTemplates.xaml file as part of a solution, all references are resolved, and I don't see the "Activity could not be loaded because of errors in the XAML" error.

If this is the expected behaviour, it seems as those something is not quite right.

Padda United Kingdom | Reply

6/13/2010 8:59:04 AM #

Ewald Hofman

You need indeed to open the xaml from within the solution. Since the Build Process Template (the xaml) is now default Windows Workflow 4.0, it is required to do it in this way.

Ewald Hofman Netherlands | Reply

7/13/2010 8:59:55 PM #

Bob Hardister

Hi Ewald, these are great exercises to get started with. Interestly, when I created the team build definition, I chose to build the custom activity solution. The build failed unable to find the reference to -

c:\program files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.TestImpact.BuildIntegration.dll

While this reference worked fine locally (in the IDE), I could not get it to fly in team build. I put the dll in TFS VC and that worked. Also, if I copied it to ...\Common7\IDE\ReferenceAssemblies\v2.0 the team build worked.

Any idea why this is happening? Suggestions?

Thanks!

Bob Hardister United States | Reply

7/14/2010 6:28:03 AM #

Ewald Hofman

In the IDE you have a reference path specified, which is not used in Team Build. See www.ewaldhofman.nl/.../...ncePath-in-TFS-2010.aspx

Ewald Hofman Netherlands | Reply

7/15/2010 6:22:23 PM #

Praneedh

I am getting the following error when Ibuild the project. The asseembly is in the reference list and the private assemblies folder.

C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Microsoft.Common.targets (1360): Could not resolve this reference. Could not locate the assembly "Microsoft.TeamFoundation.TestImpact.BuildIntegration". Check to make sure the assembly exists on disk. If this reference is required by your code, you may get compilation errors.

Praneedh United States | Reply

7/15/2010 8:00:46 PM #

Praneedh

I got the error fixed by adding the assembly into GAC using,

VS CommandPrompt>gacutil /i "C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.TestImpact.BuildIntegration.dll"

Praneedh United States | Reply

Add comment


(Will show your Gravatar icon)

  Country flag

biuquote
  • Comment
  • Preview
Loading



Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen

About the author

 

Ewald Hofman is MVP VS ALM and consultant at Avanade. His specialization is Application Lifecycle Management solutions based on Visual Studio ALM.

 

 

ClusterMap

Statistics

Statistics created at 09 Sep 2009

105 posts
129 comments
73 raters
124037 visit (345 per day)
10 users online

Recent comments

Comment RSS