TFS 2012 API Create Alert Subscriptions
- by Bob Hardister
Originally posted on: http://geekswithblogs.net/BobHardister/archive/2013/07/24/tfs-2012-api-create-alert-subscriptions.aspxThere were only a few post on this and I felt like really important information was left out: What the defaults are 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;
}
}