I'm using the .NET libraries for accessing Visual Studio Team Services and i'm trying to work around a glaring design flaw on Microsoft's part. Apparently you can't have more than one collection per server/account, so i have to use several accounts, which in this example i'll refer to as collections, since Microsoft has even made clear they map to the same thing.
What i'm actually trying to achieve is to have a list with all my work items from all the collections i'm a member of. I have a QueryWorkItems() method that uses GetAllCollections() to get all my collections. That method has been tested and it works, it does return the two accounts i have. The top level method that triggers the whole thing is AssignedWorkItems(). My code is as follows:
public static List<TfsTeamProjectCollection> GetAllCollections()
{
// Get collections/accounts associated with user
string request = "https://app.vssps.visualstudio.com/_apis/Accounts?memberId=" + versionControl.AuthorizedIdentity.TeamFoundationId + "&api-version=3.2-preview";
string content = MakeRequestToAPI(request).Result;
dynamic results = JsonConvert.DeserializeObject<dynamic>(content);
List<TfsTeamProjectCollection> collections = new List<TfsTeamProjectCollection>();
// Iterate through all collections
Parallel.ForEach((IEnumerable<dynamic>)results.value, collection =>
{
TfsTeamProjectCollection col = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri((string)collection.accountUri));
collections.Add(col);
});
return collections;
}
public static List<WorkItem> QueryWorkItems(string query)
{
List<WorkItem> workItems = new List<WorkItem>();
List<TfsTeamProjectCollection> collections = GetAllCollections();
//Parallel.ForEach(collections, collection =>
foreach(var collection in collections)
{
WorkItemCollection items = collection.GetService<WorkItemStore>().Query(query);
// Add each work item to the overall list
Parallel.For(0, items.Count, i =>
{
Console.WriteLine(items[i].Title);
lock (workItems)
{
workItems.Add(items[i]);
}
});
}
return workItems;
}
public static List<WorkItem> AssignedWorkItems()
{
Init(); //initializes variables like projectName, workItemStore and VersionControlServer(versionControl)
string myItems = "select * from issue where [System.AssignedTo]=@me";
return QueryWorkItems(myItems);
}
When i call the AssignedWorkItems method i get a login prompt, even though i have a default connection already setup:
After i input my credentials though, in this line:
WorkItemCollection items = collection.GetService().Query(query);
i get the following error:
An unhandled exception of type 'Microsoft.TeamFoundation.TeamFoundationServiceUnavailableException' occurred in Microsoft.TeamFoundation.Client.dll
Additional information: TF31002: Unable to connect to this Team Foundation Server: https://xxxxxx.vssps.visualstudio.com/.
Team Foundation Server Url: https://xxxxxx.vssps.visualstudio.com/
Possible reasons for failure include:
The name, port number, or protocol for the Team Foundation Server is incorrect.
The Team Foundation Server is offline.
The password has expired or is incorrect.
Funny thing is everytime i run this the URL mentioned in the error switches back and forth between the two collections i have. Any idea as to why this is happening?
I can test the method QueryWorkItems
successfully.
Based on the error message you got, it seems the VSTS URL stored in collections
as the format https://account.vssps.visualstudio.com instead of https://account.visualstudio.com. So please confirm the URLs stored in collections for the method GetAllCollections
are correct.
I used this GetAllCollections
method to verify QueryWorkItems
:
public static List<TfsTeamProjectCollection> GetAllCollections()
{
List<TfsTeamProjectCollection> collections = new List<TfsTeamProjectCollection>();
NetworkCredential cred1 = new NetworkCredential("username for Alternate authentication", "password for Alternate authentication");
TfsTeamProjectCollection tpc1 = new TfsTeamProjectCollection(new Uri("https://account1.visualstudio.com"), cred1);
collections.Add(tpc1);
NetworkCredential cred2 = new NetworkCredential("username for Alternate authentication", "password for Alternate authentication");
TfsTeamProjectCollection tpc2 = new TfsTeamProjectCollection(new Uri("https://account2.visualstudio.com"), cred2);
collections.Add(tpc2);
return collections;
}