Customize Team Build 2010 – Part 6: Use custom type for an argument

by Ewald Hofman 17. May 2010 07:06

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
  11. Part 11: Speed up opening my build process template
  12. Part 12: How to debug my custom activities
  13. Part 13: Get control over the Build Output
  14. Part 14: Execute a PowerShell script
  15. Part 15: Fail a build based on the exit code of a console application
  16. Part 16: Specify the relative reference path

In this post I will show you how you can create your own type for an argument, including an editor to change the value for the argument.

In this post I want to add an argument that holds an username and password. I will use this information to execute one of my activities with different credentials. Since I don’t want that the password is visible to anyone, I will create a new type called Credential. This has a UserName and Password property. In the properties window of the Process tab the Credential argument will only show the UserName. When I edit the argument a dialog is opened where I can enter the UserName and Password. If you want to make this option even more secure, you can even provide an encryption for the internal storage of the password. For the simplicity this is not implemented in this post.

At the end of the post, the classes, that are required for the solution, are attached for your convenience.

  1. Open the solution that is created in the following post: Customize Team Build 2010 – Part 4: Create your own activity.
  2. Create a new folder in the BuildTasks project called CustomType. In this folder all files required to support a custom type including the editor is stored.

    Credential
    In the credential class we will store the information that is required for the storage of the credentials. There is no magic in this class.
  3. Add a new class to this folder and call it Credential
  4. Add the UserName and Password property to this class.
  5. When editing the Process tab for the Build Definition, the ToString() function is called to retrieve the value. So override this function and return the UserName property.
  6. This will result in the following code
    namespace BuildTasks.CustomType
    {
        public class Credential
        {
            public string UserName { get; set; }
            public string Password { get; set; }

            public override string ToString()
            {
                return UserName;
            }

        }
    }



     
    CredentialDialog
    This dialog will be shown when an user edits the value for the argument in the Process tab of the Build Definition. It gives you the ability to provide a user friendly method of providing values.
     
  7. Add a new form to this folder and call it CredentialDialog
  8. Create an UI like this and call the two textboxes UserNameTextbox and PasswordTextbox.

    image
  9. Now add the following code to the textbox:
    using System.Windows.Forms;

    namespace BuildTasks.CustomType
    {
        public partial class CredentialDialog : Form
       
        {
            public CredentialDialog()
            {
                InitializeComponent();
            }

            public string Password
            {
                get
                {
                    return PasswordMaskedTextbox.Text;
                }
                set
                {
                    PasswordMaskedTextbox.Text = value;
                }
            }
           
            public string UserName
            {
                get
                {
                    return UserNameTextbox.Text;
                }
                set
                {
                    UserNameTextbox.Text = value;
                }
            }
        }
    }
    CredentialEditor
    This class contains the metadata for Visual Studio what you want to do when the user clicks on the ellipsis button of the argument 
  10. Add a new class to the CustomType folder and call it CredentialEditor.
  11. This class overrides from the UITypeEditor class. You should override two methods, being EditValue and GetEditStyle. In the GetEditStyle you can tell Visual Studio to open up a combobox or a dialog. In this post I choose to open a dialog.
  12. In the EditValue you add the logic that is executed when the user clicks on the ellipsis button.
  13. The full code of the class is the following:

    using System.Drawing.Design;
    using System.Windows.Forms.Design;
    using System.ComponentModel;
    using System;
    using System.Windows.Forms;

    namespace BuildTasks.CustomType
    {

        class CredentialEditor : UITypeEditor
        {

            public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
            {
                if (provider != null)
                {
                    IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

                    if (editorService != null)
                    {
                        Credential credential = value as Credential;

                        using (CredentialDialog dialog = new CredentialDialog())
                        {
                            dialog.UserName = credential.UserName;
                            dialog.Password = credential.Password;

                            if (editorService.ShowDialog(dialog) == DialogResult.OK)
                            {
                                credential.UserName = dialog.UserName;
                                credential.Password = dialog.Password;
                            }
                        }
                    }

                }

                return value;
                
            }

            public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
            {
                return UITypeEditorEditStyle.Modal;
            }
        }
    }

    Metadata
    Now we add a new argument with the correct type and provide metadata to the Build Process Template so Visual Studio knows it has to execute the logic that is specified in the CredentialEditor.
  14. First build the BuildTasks project so we have access to the new Credentials type.
  15. Now open the CustomTemplate.xaml Build Process Template
  16. Open the Arguments list and add a new argument called Credentials
  17. In the Argument Type choose for the “Browse for Types …” option

    image 
  18. In the Browse dialog, navigate to the BuildTasks reference and choose the Credential class.

    image
  19. Click on OK to close the dialog
  20. Now locate the Metadata argument in the list to provide metadata for this argument. When you have found it, click on the ellipsis button. This will open the Metadata editor.
  21. Add the Credentials parameter. The most exciting we do in this dialog is providing the Editor value. You have to give it the value of the CredentialEditor class. You specify the reference to this class in the for of <full namespace>.<class>,<assembly name>. In our case, this is BuildTasks.CustomType.CredentialEditor,BuildTasks

    image
  22. Save the CustomTemplate.xaml file and check it in.
    Test the dialog
  23. Edit the build definition that is using the Build Process Template and go to the Process tab. You will now see a new argument called Credential.
  24. When you click on the ellipsis, you will see the new dialog.

     image
  25. When you accept the values, you will see the following in the Credential argument

    image

 

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

10/18/2010 3:32:45 PM #

Darrell Sveistrup

I followed that example and create my own type, but got an error when tried to edit build definition.

"The process template could not be loaded: The build process could not be deserialized due to the following error: the type 'InArgument(tbw:myArgs)' of property 'Args' could not be resolved."

Same error if I try and add your type of credintals in

Where does the new custom dll need to be places so that the build editor can use it, Its already in the custom build path for the workflow to use.

Darrell Sveistrup New Zealand |

10/18/2010 11:31:04 PM #

Ewald Hofman

Have you taken a look at www.ewaldhofman.nl/.../...stom-assembly-found.aspx

Ewald Hofman Netherlands |

10/19/2010 12:32:32 PM #

Michael Zboray

I got the same error. Don't overlook the fact that you may need to close and reopen Visual Studio. This is what worked for me.

This series has been very helpful. I'm looking forward to future installments.

Michael Zboray United States |

10/19/2010 2:26:58 PM #

Darrell Sveistrup

It was two things.

1) When you create a new assembly you do need to close VS2010 and open it again.
   That will then allow TFS to ref the new assembly for your build definition.

2) If you have no CodeActivity in your assembly then TFS will not load it.
   I was only after a container to pass in data not an custom activity,
   so with no CodeActivity in the assembly TFS will not load it.

Once I added the empty Activity below, rebuilt, moved the assembly to the custom area on the server, and restarted VS2010 then I the error went away.

[BuildActivity(HostEnvironmentOption.All)]
public sealed class EmptyActivity : CodeActivity
{
   protected override void Execute(CodeActivityContext context)
   {
   }
}

Darrell Sveistrup New Zealand |

1/28/2011 12:22:56 PM #

Marcel Gosselin

To complete on Darrell's comment, if you make a change to a dll to add a custom type, you also need to restart VS2010 if you want to Queue a new Build that uses that custom type in its process parameters. If you don't, you get the same error mentioned above.

Marcel Gosselin Canada |

1/29/2011 12:22:37 AM #

Darrell Sveistrup

Found out yesterday,
You will also get that error if you don't have permission to where the dll is stored in TFS.

Darrell Sveistrup New Zealand |

10/19/2010 2:54:29 PM #

Kamal

Hi,

I have a custom assembly that uses a dependent assembly. The custom type is defined in dependent assembly and the editor is in custom assembly. I have also specified this editor for a parameter in xaml. When I try to open the build definition to modify this custom argument, i dont find a button that opens the editor. Have you come across such behavior?

Thanks,
Kamal

Kamal United States |

11/9/2010 5:32:32 AM #

trackback

Part 14: Execute a PowerShell script

Part 14: Execute a PowerShell script

Ewald Hofman |

11/10/2010 9:14:23 AM #

pingback

Pingback from blogs.like10.com

TechDays 2010 Presentations « Microsoft Team Foundation Server, SharePoint Server, .NET, and SQL Server

blogs.like10.com |

1/12/2011 3:26:22 AM #

Daniel

Hi Ewald,

Thanks for the nice post. Although I have a problem when trying to reproduce your results.
I have an assembly that contains custom activities, custom types and a custom editor. The assembly is checked into source control and that path is also set on the build controller. The build controller executes the custom activities just fine.
But the custom editor does not work. I set the editor on my custom type just like you did: <full namespace>.<class>,<assembly name>. I even tried to sign the assembly and provided that within the metadata; still no success.
From Fusion Log I see that Visual Studio is loading my assembly from a temp path using LoadFrom, which works. This can also be verified due to the fact that my custom types show up in the process property grid and no warning/error is shown in Visual Studio. Then there is another entry in Fusion Log where Visual Studio tries to load my assembly again using Load. This time the assembly is searched for in the default locations of Visual Studio, where of course it cannot be found. I suspect that this is the time when Visual Studio tries to find the editor type, which fails.

So my question is: Did you put your assembly into the GAC or the PrivateAssemblies folder, or did you just put it into source control (using custom assembly path of the build controller)?

If you did not put it into the GAC or the PrivateAssemblies folder, how did you manage that Visual Studio finds your editor?

Thanks in advance,
Daniel

Daniel Austria |

1/12/2011 1:57:00 PM #

Ewald Hofman

It is a time ago since I have done this, but IIRC I was able to put this assembly in the custom assembly path. I have been struggling with this in the past too. You might want to post this issue to connect: https://connect.microsoft.com/visualstudio

Ewald Hofman Netherlands |

1/17/2011 11:23:24 PM #

Daniel

Thank you for your response, Ewald.

Of course I did something different from you. I tried to add a custom editor for a string property. It seems that a custom editor is only found when it is in the assembly as the custom type. I found out more weird stuff but nothing really useful Smile

So I now use a custom type with a single string property and a custom editor. It works with one exception: If no build controller is defined, Visual Studio can not deserialize the build process as it does not know the custom assembly. Unfortunately, if you have seen this message once you must restart Visual Studio. Even if you select a build controller afterwards, the message remains.

It is even worse when you use a template with a custom type as your default template. In this case the build process is loaded immediately when you create a new build definition (no build controller is selected initially). In this case you cannot create build definitions anymore (except some very ugly workarounds: new build definition - select MS template - save build definition - close VS - open VS - edit build definition - select correct controller - select custom template).

Unfortunately, I don't see a solution to this. Visual Studio cannot know about your custom type unless you have selected a build controller. I hope I'm wrong here, but chances seem very unlikely...

Thanks for your support,
Daniel

Daniel Austria |

2/17/2011 10:18:18 PM #

Satya Srikanth Mantha

Hi Ewald,

Thats a interesting post which helped me to add windows dialogs like open file dialog, sql connection string dialog and the open folder dialog.

My question, how is it possible to default these values so that the parameters are initialized when we are editing the Build Process Template.

Kind Regards,
Satya

Satya Srikanth Mantha India |

2/23/2011 10:07:38 AM #

Ewald Hofman

When you add a new Argument in the build template, you can give it a value. This value is the default value for a build defintion.

Ewald Hofman Netherlands |

3/1/2011 5:52:52 AM #

trackback

Problem Deserializing Classes From Assemblies Loaded at Runtime Implicitly – TFS Build Custom UI Type Editor

Lately I’ve created a Custom UI Type Editor for the “Process” Tab in the TFS Build Definition Interface

Oshry Horn |

4/12/2011 9:00:17 AM #

Padda

What I found is that it's important that within your solution, you have a separate project that holds the xaml template - exactly as Ewald has done in his example. If you don't, the assembly name gets dropped from the xaml from beside the namespace.

Example: So if your namespace is MyCustom.BuildTasks and your assembly is called CustomTasks, when you look at the xaml code you should see, "clr-namespace:MyCustom.BuildTasks;assembly=CustomTasks". If you link to the xaml from within the same project as the CustomTasks, you'll find that the ";assembly=CustomTasks" gets deleted by Visual Studio and you have to reinsert it manually. Without the assembly, you'll get the "The process template could not be loaded: The build process could not be deserialized due to the following error: the type 'InArgument(tbw:myArgs)' of property 'Args' could not be resolved," error.

Hope this helps.
Padda

Padda United Kingdom |

4/27/2011 2:56:15 AM #

Padda

Another issue I've found, I'm not sure if anyone else has found this, but when I change the Parameter setting so that it shows, "View the parameter when:" "Always show the parameter" (in the Process Parameter Metadata Editor), the values that I set when queueing a new build are ignored and the settings in the Build Definition Editor are kept when running the build. Either the queuing new build settings are ignored, or they're overridden by the Edit Build Definition settings. HAs anyone else found this, or can anyone help with this?

Padda United Kingdom |

5/12/2011 1:24:51 AM #

Bob

I'm experiencing the same issue. Did you manage to find a solution?

Bob United Kingdom |

5/12/2011 12:36:41 PM #

Padda

Hi Bob,

Yup managed to get it working. You need to return a new Credential object as opposed to "return value" as Ewald has done.

So, something like:
return new Credential() { Username = selected.Username, Password = selected.Password};

This tells TFS that the dialog has been updated, and also alerts the Build Definition Edit screen to the fact that something has changed.

HTH
Padda

Padda United Kingdom |

5/13/2011 3:22:07 AM #

Bob

It works brilliantly. Thank you!

Bob United Kingdom |

5/4/2011 2:19:30 PM #

Jason Smale

Has anyone received the following error when queuing a build after following the instructions in this post:
TF215097: An error occurred while initializing a build for build definition \[project]\[builddefinition]: The type ‘InArgument(b:[customtype])’ of property ‘[propertyname]’ could not be resolved.

The 'b' in this case is defined in the xaml as xmlns:b="clr-namespace:BuildTasks;assembly=BuildTasks". That assembly is checked in to source control, and that version control path is set on the build controller for custom assemblies.

The editing portion of my custom type works just fine. I can edit my build definition, bring up the custom form to edit my custom type, and everything saves properly. I am only running into an issue when I run the build.

Any help would be appreciated.

Jason Smale United States |

5/5/2011 12:32:58 PM #

Padda

Hi Jason,

I had the same problem. I tried adding the assembly to the controllers custom assemblies folder in TFS, the PrivateAssemblies and the GAC, but it made no difference.

I ended up having to convert the output from a custom type to a string (delimited with hyphen's for each piece of text). This then worked, but I can't help but feel it was a bit of a poor compromise. If you get it working please let me know.

Ta
Pads

Padda United Kingdom |

5/5/2011 12:36:14 PM #

Jason Smale

I did end up getting it working. I did two things, so I'm not sure which one did it:

1) Added the fake activity with the TFS attribute as described in the last comment in this post: www.ewaldhofman.nl/.../...stom-assembly-found.aspx

2) I restarted the build controller.

Jason Smale United States |

5/12/2011 12:36:56 PM #

Padda

Hi Bob,

Yup managed to get it working. You need to return a new Credential object as opposed to "return value" as Ewald has done.

So, something like:
return new Credential() { Username = selected.Username, Password = selected.Password};

This tells TFS that the dialog has been updated, and also alerts the Build Definition Edit screen to the fact that something has changed.

HTH
Padda

Padda |

5/19/2011 5:56:16 AM #

Kislay Kishore

I have to use a configuration file containing the parameters for the team build. For this I want to send a NameValueCollection of the app.config file. But everytime I do the same the error is "Type 'System.Configuration.KeyValueInternalCollection' not visible. If the type is local, please set the LocalAssembly field in XamlReaderSettings".
Could you please help me with this.

Kislay Kishore United States |

5/31/2011 8:22:06 AM #

trackback

Ewald’s posts on TFS Build 2010

Ewald Hofman , an ALM MVP, has written a great series of blog posts on Team Build in Team Foundation Server 2010.  The 2010 release introduces Windows Workflow as the overall orchestrator of the build process.  Ewald walks you through quite a few topics related to this and the other new features.  Check it out! Part 1: Introduction Part 2: Add arguments and variables Part 3: Use more complex arguments Part 4: Create your own activity Part 5: Increase AssemblyVersion Part 6: Use custom type for an argument Part 7: How is the custom assembly found Part 8: Send information to the build log Part 9: Impersonate activities (run under other credentials) Part 10: Include Version Number in the Build Number Part 11: Speed up opening my build process template Part 12: How to debug my custom activities Part 13: Get control over the Build Output Part 14: Execute a PowerShell script Part 15: Fail a build based on the exit code of a console application Part 16: Specify the relative reference path Technorati Tags: tfs 2010 , team build , windows workflow

Buck Hodges |

8/20/2011 8:33:18 PM #

pingback

Pingback from pafosphotos.com

Tfs Custom Process Templates | Pafos Photos

pafosphotos.com |

10/23/2012 8:29:15 AM #

pingback

Pingback from devtfs.wordpress.com

Reusable Editors – TFS build arguments « dev.tfs

devtfs.wordpress.com |

Comments are closed

Powered by BlogEngine.NET 1.6.1.0
Theme by Mads Kristensen


ClusterMap

Statistics

Statistics created at 09 Sep 2009

121 posts
488 comments
326 raters
1897337 visit (1042 per day)
17 users online

Recent comments

Comment RSS