TfsTeamProjectCollectionFactory.GetTeamProjectCollection failing despite available TFS server - tfs

So, I have a TFS server at http://mytfsserver:8080. I'm connected to it fine from visual studio doing all the usual TFSy things without any issue at all.
I'm trying to connect from code though - I do the following:
tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://mytfsserver:8080"));
tfs.EnsureAuthenticated();
But I get a TeamFoundationServiceUnavailableException.
I'm not connecting to my server in any funny ways, so what is different about what I'm doing to what VS does when it connects?

You just need to add the collection name at the end of the Uri
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
new Uri("http://TFS:8080/TFS/DefaultCollection"));

Try adding /tfs to your server URI.
var tfsServerUri = new Uri("http://mytfsserver:8080/tfs");
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(tfsServerUri);
tfs.EnsureAuthenticated();

Related

TfsTeamProjectCollection does not ask for credential

Dears
Please help me with VS add-in Tfs connection question.
I've wrote VS 2017 plugin that uses TfsTeamProjectCollection class to connect to the tfs server. Tfs server is hosted in the https://dev.azure.com
However on certain computers it fails to connect to the Tfs server.
For example, I've tried to reproduce this and cleared all caches like described here. After clearing/connecting several cycles I've got the following:
VS Team Explorer is connected to the Tfs. I can checkout/checkin files, load history etc.
My add-in fails to connect with 401 non authorized error.
unity test started by VS is able to connect to the same Tfs using the same code
I've created sample console application that uses exactly the same class and method from add-in to connect and it works too.
Here is the source code I'm using to connect:
public override TfsTeamProjectCollection CreateCollection(WorkspaceInfo wi)
{
var s = (overrideConfig ?? Config);
var u = wi.ServerUri;
var vssCred = new VssClientCredentials(); // GetCredentials(s.Vsts);
Logger.Debug("getting collection for url:{0}", u);
TfsTeamProjectCollection tpc = null;
try
{
tpc = new TfsTeamProjectCollection(u, vssCred);
Logger.Debug("authenticating");
tpc.Authenticate(); // 401 non authorized exception here
}
I've tried to add vssCred.Storage = new VssClientCredentialStorage(); before Autheticate() but no luck
Then I've checked network packets using Fiddler application.
It shows the same request packet is sent using unit test, console application and add-in.
But console application and unit test produces initial request
POST
https://dev.azure.com/quipu-cwnet/Services/v3.0/LocationService.asmx
HTTP/1.1
and response is
HTTP/1.1 401 Unauthorized
X-TFS-FedAuthRedirect:
https://app.vssps.visualstudio.com/_signin?realm=dev.azure.com&reply_to=https%3A%2F%2Fdev.azure.com%2F...
Then console and unit test sends packet to the redirect url and asks for user credentials.
When add-in tries to connect to the Tfs server fiddler shows only first POST request and 401 response (with the same X-TFS-FedAuthRedirect header. But there is no redirection. From user side it looks like application freezes for some period after 401 response is obtained and then fails with 401 error.
Both Unit test and add-in assemblies has the same references to the 15.0.0 assemblies like Microsoft.TeamFoundation.VersionControl.Client and related.
I've tried VssConnection but the same
VssConnection connection = new VssConnection(u, vssCred);
connection.ConnectAsync().SyncResult();
var prj = connection.GetClient<ProjectHttpClient>();
var prjCollection = prj.GetProjects().Result; // 401 error here when is executed as VS add-in
foreach (var pc in prjCollection)
Logger.Debug("\tVssConnection project {0} {1}", pc.Id, pc.Name);
I'm using the same user to start VS (and add-in) and console. No elevated permissions.
Is there anything I can do with TfsConnection when used as VS add-in ?
the answer is to execute Authenticate() in the separate thread (non GUI) :crazy
var authTask = Task.Run(() => tpc.Authenticate());
authTask.Wait();
Please note that I'm using VS 2017 15.9.11 and Microsoft.TeamFoundationServer.ExtendedClient.15.112.1
upd1: I've upgraded Microsoft.TeamFoundationServer.ExtendedClient to 15.113.1
it works on my machine but still fails on my colleague machine.
Tfs credentials are working like a charm on both machines:
var tfsClientCredentials = TfsClientCredentials.LoadCachedCredentials(wi.ServerUri, false, false);
var res = new TfsTeamProjectCollection(wi.ServerUri, tfsClientCredentials);
res.EnsureAuthenticated();
despite the fact it is marked as obsolete.

Getting #Mention to work with a TFS Extension on TFS 2017.3

I am trying to programmatically add the mention of users that are members of groups in TFS in the discussion area of work items. We were using the 1.0 version with TFS 2017 update 2 with success:
#{id.DisplayName}
However upgrading to TFS 2017 update 3 fails to send emails on the notifications. We also tried all of the "user ids" we could find on the TeamFoundationIdentitiy object for the solutions found here:
VSTS - uploading via an excel macro and getting #mentions to work
So how can we get emails for #mentions to work again in TFS 2017.3?
Update: 9/11/2018
Verified service account fails to send emails while my account running the same code will send emails for mentions:
using (var connection = new VssConnection(collectionUri, cred))
using (var client = connection.GetClient<WorkItemTrackingHttpClient>())
{
var wi = new JsonPatchDocument
{
new JsonPatchOperation()
{
Operation = Operation.Add,
Path = "/fields/System.History",
Value = $"#{id.DisplayName} <br/>"
}
};
using (var response = client.UpdateWorkItemAsync(wi, workItemId, suppressNotifications: false))
{
response.Wait();
}
}
We solved by dropping use of the WorkItemHttpClient and going back to loading the SOAP WorkItemStore as the user that submitted the changes instead of the service account. It would be nice if we could use impersonation of a user with TFS's WebApi

TFS2018 path to api

I have a TFS2018 setup on a server and I am trying to figure out what is the path to the api. Should the path look look like this? Do I have to enable the API on the server?
https://myserver/tfs/DefaultCollection/MyProject/_apis
If I run this in code like this
var cred = new VssCredentials(
new WindowsCredential(new NetworkCredential("username", "Pass")));
var buildClient = new BuildHttpClient(new Uri("https://myserver/tfs/DefaultCollection/MyProject/_apis", UriKind.Absolute), cred);
await buildClient.CreateDefinitionAsync(buildDef);
I get the following error
Web method running:
[https://myserver/tfs/DefaultCollection/MyProject/_apis]
(OPTIONS)_apis[]
It depends on how the server was setup. If it's a fresh install, the /tfs/ is no longer used. If it's an upgrade the /tfs/ is retained to not break existing clients. And I suspect you can leave off the /_api/ part as well, as that should be automatically added.
The best way to get to the BuildCLient is to use the TFS Server or Collection object and request the server:
var collection = new TfsTeamProjectCollection(tfsCollectionUri, credential);
var buildClient = collection.GetClient<BuildHttpClient>();

Get historical data in TFS 2013

I'm trying to get historical data from a server in Team Foundation server 2013, does someone know how? In TFS 2015 there is a way with AsOf but it doesn't work in the 2013 version.
Turns out, what I wanted was an endpoint.
I found one, it needs to be formatted to use the data that is there:
#{server_url}/_api/_wit/workitems?ids=#{workItem_id}
In TFS2013, you need work with TFS API to get work item historical data. You should use the WorkItem.Revisions property.
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://tfsservername:8080/tfs/defaultcollection"));
var service = tfs.GetService<WorkItemStore>();
var wi = service.GetWorkItem(workitemid);
foreach (Revision revision in wi.Revisions)
{
//historical data
}
Have a check on this blog for the details: http://geekswithblogs.net/TarunArora/archive/2011/08/21/tfs-sdk-work-item-history-visualizer-using-tfs-api.aspx

Get the URL of the WebAccess for a TFS Team Project programmatically

I want to get the URL of the web access Page for a specific TeamProject.
I found some samples using a TswaClientHyperlinkService object calling GetHomeUrl(new Uri("MyprojectName")), but I was not able to provide a correct Uri value for that. Maybe I did not understand how to format the parameter..
I know how to get the base url for the webaccess, but I want to get to the page for a specific Team Project within a specifc Team Project Collection.
It turns out that the GetHomeUrl method expects a vsts:// url, not the url to the project collection you'd normally use. The following code can be used to get the Uri:
var server = TfsConfigurationServerFactory.GetConfigurationServer(new Uri("http://localhost:8080/tfs" /* your tfs uri here */));
server.Authenticate();
var service = server.GetService<TswaClientHyperlinkService>();
var projectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://localhost:8080/tfs/DefaultCollection"));
var cssService = projectCollection.GetService<ICommonStructureService3>();
var project = cssService.GetProjectFromName(/*YourProjectNameHere*/);
var home = service.GetHomeUrl(new Uri(project.Uri));

Resources