Matt Burland
Matt Burland

Reputation: 45135

How to handle VSTS credentials in a VSIX extension

I have a Visual Studio extension that we use internally for a project and one of the things it needs to be able to do is post tickets to VSTS. Previously we were using onsite TFS and making a connection to post tickets was as simple as:

var vssCreds = new VssCredentials(true);    
projectCollection = new TfsTeamProjectCollection(url, vssCreds);
workItems = projectCollection.GetService<WorkItemStore>();
project = workItems.Projects["My Project"];
defaultType = project.WorkItemTypes["Bug"];

//...
var newItem = new WorkItem(defaultType)
{
    Title = title
};
newItem.Fields["Assigned To"].Value = assignTo;
newItem.Fields["Repro Steps"].Value = repoSteps;
var validationResult = newItem.Validate();
newItem.Save();

And this worked fine. But after upgrading to VSTS I'm having a hard time getting the credentials part to work. I changed this line:

projectCollection = new TfsTeamProjectCollection(url, vssCreds);

To this:

projectCollection = new TfsTeamProjectCollection(url, new VssClientCredentials());

And this worked fine for me. But when I share it with other people on my team it didn't work at first and then started working a little later. I am guessing that interacting with VSTS caused their credentials to be loaded so that it then worked. But I have at least one person who just seems to be completely unable to make it work.

So what's the correct way to get it to use the VSTS credentials (that should already exist in VS)?

I see this overload for VssClientCredentials (https://msdn.microsoft.com/en-us/library/dn228355(v=vs.120).aspx):

public VssClientCredentials(
    IVssCredentialPrompt credentialPrompt
)

Which I suspect might be useful, but I can't seem to find out if there's a built in implementation of IVssCredentialPrompt somewhere or, if not, how to implement it.

Upvotes: 2

Views: 367

Answers (2)

Matt Burland
Matt Burland

Reputation: 45135

For reasons that are entirely unclear and from this answer to an entirely different question: https://stackoverflow.com/a/40256731/1250301

It seems that spawning a new thread causes a login prompt to appear if needed and fix all the problems. So if I do this:

Task.Run(() =>
{
    var url = new Uri(_tfsUrl);
    var cred = new VssClientCredentials();
    projectCollection = new TfsTeamProjectCollection(url, cred);
    workItems = projectCollection.GetService<WorkItemStore>();
}).Wait();

project = workItems.Projects["Job Posting Data"];
defaultType = project.WorkItemTypes["Bug"];
taskType = project.WorkItemTypes["Task"];

Then it works. I have no idea why it works, or why this is necessary (at first I thought maybe it was a problem with not being in the UI thread so I'd tried Application.Current.Dispatcher.Invoke which did not work) but it seems to have fixed the problem.

Upvotes: 0

starian chen-MSFT
starian chen-MSFT

Reputation: 33698

Remove the related key from Computer\HKEY_CURRENT_USER\Software\Microsoft\VSCommon\14.0\ClientServices\TokenStorage\VisualStudio\VssApp, then authentication again.

You also can specify other Kind (vssApp by default) and Namespace (VisualStudio by default) by using this code:

var c = new VssClientCredentials();
c.Storage = new VssClientCredentialStorage(storageKind: "VssApp2", storageNamespace: "VisualStudio");
projectCollection = new TfsTeamProjectCollection(url, c);

Upvotes: 1

Related Questions