TFS 2012 API Create Alert Subscriptions

Posted by Bob Hardister on Geeks with Blogs See other posts from Geeks with Blogs or by Bob Hardister
Published on Wed, 24 Jul 2013 04:13:09 GMT Indexed on 2013/08/02 15:40 UTC
Read the original article Hit count: 146

Filed under:

Originally posted on: http://geekswithblogs.net/BobHardister/archive/2013/07/24/tfs-2012-api-create-alert-subscriptions.aspx

There were only a few post on this and I felt like really important information was left out:

  1. What the defaults are
  2. How to create the filter string

Here’s the code to create the subscription.

Get the Collection

public TfsTeamProjectCollection GetCollection(string collectionUrl)
        {
            try
            {
                //connect to the TFS collection using the active user
                TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri(collectionUrl));
                tpc.EnsureAuthenticated();
                return tpc;
            }
            catch (Exception)
            {
                return null;
            }
        }

Use Impersonation

Because my app is used to create “support tickets” as stories in TFS, I use impersonation so the subscription is setup for the “requester.”  That way I can take all the defaults for the subscription delivery preferences.

public TfsTeamProjectCollection GetCollectionImpersonation(string collectionUrl, string impersonatingUserAccount)
        {
            // see: http://blogs.msdn.com/b/taylaf/archive/2009/12/04/introducing-tfs-impersonation.aspx
            try
            {
                TfsTeamProjectCollection tpc = GetCollection(collectionUrl);
                if (!(tpc == null))
                {
                    //get the TFS identity management service (v2 is 2012 only)
                    IIdentityManagementService2 ims = tpc.GetService<IIdentityManagementService2>();

                    //look up the user we want to impersonate
                    TeamFoundationIdentity identity = ims.ReadIdentity(IdentitySearchFactor.AccountName, 
                        impersonatingUserAccount, 
                        MembershipQuery.None, 
                        ReadIdentityOptions.None);

                    //create a new connection using the impersonated user account
                    //note: do not ensure authentication because the impersonated user may not have 
                    //windows authentication at execution
                    if (!(identity == null))
                    {
                        TfsTeamProjectCollection itpc = new TfsTeamProjectCollection(tpc.Uri, identity.Descriptor);
                        return itpc;
                    }
                    else
                    {
                        //the user account is not found
                        return null;
                    }
                }
                else
                {
                    return null;
                }
            }
            catch (Exception)
            {
                return null;
            }
        }

Create the Alert Subscription

public bool SetWiAlert(string collectionUrl, string projectName, int wiId, string emailAddress, string userAccount)
        {
            bool setSuccessful = false;
            try
            {
                //use impersonation so the event service creating the subscription will default to 
                //the correct account: otherwise domain ambiguity could be a problem
                TfsTeamProjectCollection itpc = GetCollectionImpersonation(collectionUrl, userAccount);

                if (!(itpc == null))
                {

                    IEventService es = itpc.GetService(typeof(IEventService)) as IEventService;

                    DeliveryPreference deliveryPreference = new DeliveryPreference();
                    //deliveryPreference.Address = emailAddress;
                    deliveryPreference.Schedule = DeliverySchedule.Immediate;
                    deliveryPreference.Type = DeliveryType.EmailHtml;

                    //the following line does not work for two reasons: 
                    //string filter = string.Format("\"ID\" = '{0}' AND \"Authorized As\" <> '[Me]'", wiId);

                    //1. the create fails because there is a space between Authorized As
                    //2. the explicit query criteria are all incorrect anyway
                    //   see uncommented line for what does work: you have to create the subscription mannually 
                    //   and then get it to view what the filter string needs to be (see following commented code)
                    
                    //this works
                    string filter = string.Format("\"CoreFields/IntegerFields/Field[Name='ID']/NewValue\" = '12175'" + 
                                                    " AND \"CoreFields/StringFields/Field[Name='Authorized As']/NewValue\"" + 
                                                    " <> '@@MyDisplayName@@'", projectName, wiId);

                    string eventName = string.Format("<PT N=\"ALM Ticket for Work Item {0}\"/>", wiId);

                    es.SubscribeEvent("WorkItemChangedEvent", filter, deliveryPreference, eventName);

                    ////use this code to get existing subscriptions: you can look at manually created 
                    ////subscriptions to see what the filter string needs to be
                    //IIdentityManagementService2 ims = itpc.GetService<IIdentityManagementService2>();
                    //TeamFoundationIdentity identity = ims.ReadIdentity(IdentitySearchFactor.AccountName, 
                    //    userAccount, 
                    //    MembershipQuery.None, 
                    //    ReadIdentityOptions.None);
                    //var existingsubscriptions = es.GetEventSubscriptions(identity.Descriptor);

                    setSuccessful = true;

                    return setSuccessful;
                }
                else
                {
                    return setSuccessful;
                }
            }
            catch (Exception)
            {
                return setSuccessful;
            }
        }

© Geeks with Blogs or respective owner