How can I get mapping of current project on TFS 2010? I need to take single file, find out its mapping and with that information I want to find this file on another computer, which has mapped same workspace. Any idea how can I achieve this?
Your question is a little bit unclear.
Whats your main goal?
If you install Team Foundation Sidekicks you can have a view called "Workspace Sidekick".
There you can filter by computername, Owner (User) and access date (first/last).
With TFS Sidekicks its a little bit easier to find mapped workspaces.
So I've found solution by myself.
First I get server name for every file
try
{
WorkspaceInfo wsi = Workstation.Current.GetLocalWorkspaceInfo(localFileName);
TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsi.ServerUri);
Workspace wr = wsi.GetWorkspace(tfs);
string ret = wr.TryGetServerItemForLocalItem(localFileName);
return ret;
}
catch
{
return null;
}
and than, on another computer, I can load local names
try
{
Uri serverUri = new Uri(uri);
TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(serverUri);
VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
Workstation.Current.EnsureUpdateWorkspaceInfoCache(vcs, Environment.UserName);
Workspace wr = vcs.GetWorkspace(Environment.MachineName, Environment.UserName);
string ret=wr.TryGetLocalItemForServerItem(serverFileName);
return ret;
}
catch
{
return null;
}
It has some limitations, but works perfect for me.
Related
Currently when I call GetWorkspace I get ItemNotMappedException exception, but when I iterate over workspaces manually I can get my code working. This is so bizarre that I am wondering if I should call some refresh or something before I call GetWorkspace?
Here is my code:
Workspace active = null;
using (var tfs = new TfsTeamProjectCollection(uri))
{
tfs.EnsureAuthenticated();
VersionControlServer vcs = tfs.GetService<VersionControlServer>();
// displaying info and manually finding desired workspace
foreach (var ws in vcs.QueryWorkspaces(null, vcs.AuthorizedUser, Environment.MachineName))
{
Console.WriteLine(ws.Name);
foreach (var f in ws.Folders)
{
Console.WriteLine($" {f.LocalItem}");
if (f.LocalItem == map_path)
active = ws;
}
}
// at this point workspace is found and I can work with it
// but this will crash
Workspace workspace = vcs.GetWorkspace(map_path);
}
I use VS2015 and the library for TFS is fetched from NuGet repo. It is "Microsoft.TeamFoundationServer.ExtendedClient" version "15.112.1".
The VersionControlServer.GetWorkspace method searches all known workspaces on the current computer to identify a workspace that has explicitly or implicitly mapped the provided local path. If no workspace is found, this method throws an ItemNotMappedException.
Try to call to Workstation.EnsureUpdateWorkspaceInfoCache in your code to force update the workspace information cache:
TfsTeamProjectCollection tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("<your-tfs-uri-here>"));
VersionControlServer tfServer = tpc.GetService<VersionControlServer>();
Workstation.Current.EnsureUpdateWorkspaceInfoCache(tfServer, tfServer.AuthorizedUser);
Have a look at this similar question: Microsoft.TeamFoundation.VersionControl.Client.ItemNotMappedException even when the workspace exists and has a mapping
So I'm having a problem with automating my code to check-in files to TFS, and it's been driving me up the wall! Here is my code:
string location = AppDomain.CurrentDomain.BaseDirectory;
TfsTeamProjectCollection baseUserTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection);
IIdentityManagementService ims = baseUserTpcConnection.GetService<IIdentityManagementService>();
TeamFoundationIdentity identity = ims.ReadIdentity(IdentitySearchFactor.AccountName, #"PROD1\JR", MembershipQuery.None, ReadIdentityOptions.None);
TfsTeamProjectCollection impersonatedTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection, identity.Descriptor);
VersionControlServer sourceControl = impersonatedTpcConnection.GetService<VersionControlServer>();
Workspace workspace = sourceControl.CreateWorkspace("MyTempWorkspace", sourceControl.AuthorizedUser);
String topDir = null;
try
{
Directory.CreateDirectory(location + "TFS");
String localDir = location + "TFS";
workspace.Map("$/Automation/", localDir);
workspace.Get();
destinationFile = Path.Combine(localDir, Name + ".xml");
string SeconddestinationFile = Path.Combine(localDir, Name + ".ial");
bool check = sourceControl.ServerItemExists(destinationFile, ItemType.Any);
PendingChange[] pendingChanges;
File.Move(sourceFile, destinationFile);
File.Copy(destinationFile, sourceFile, true);
File.Move(SecondsourceFile, SeconddestinationFile);
File.Copy(SeconddestinationFile, SecondsourceFile, true);
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
else
{
workspace.PendEdit(destinationFile);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
and the problem is that whenever it's NEW files (PendEdit works correctly when the files already exist in TFS) that my code is attempting to check in, and it runs through this code:
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
The files, instead of being in the included changes in pending changes, are instead in the excluded changes like so:
and when the line that actually does the check-in runs, I'll get a "The array must contain at least one element" error, and the only way to fix it is to manually add those detected changes, and promote them to included changes, and I simply can't for the life of me figure out how to do that programatically though C#. If anyone has any guidance on what direction I should take for this, I would really appreciate it! Thank you!
Edit: I've also discovered another way to solve this by reconciling the folder, which also promotes the detected changes, but again the problem is I can't seem to figure out how to program that to do it automatically.
I know that running the visual studio developer command prompt, redirecting to the folder that this mapping is in, and the running "tf reconcile /promote" is one way, but I can only automate that as far as the /promote part, because that brings up a toolbox that a user would have to input into, which defeats the purpose of the automation. I'm at a loss.
Next Edit in response to TToni:
Next Edit in response to TToni:
I'm not entirely sure if I did this CreateWorkspaceParameters correctly (see picture 1), but this time it gave the same error, but the files were not even in the excluded portions. They just didn't show up anywhere in the pending changes (see picture 2).
Check this blog:
The workspace has a method GetPendingChangesWithCandidates, which actually gets all the “Excluded” changes. Code snippet is as below:
private void PendChangesAndCheckIn(string pathToWorkspace)
{
//Get Version Control Server object
VersionControlServer vs = collection.GetService(typeof
(VersionControlServer)) as VersionControlServer;
Workspace ws = vs.TryGetWorkspace(pathToWorkspace);
//Do Delete and Copy Actions to local path
//Create a item spec from the server Path
PendingChange[] candidateChanges = null;
string serverPath = ws.GetServerItemForLocalItem(pathToWorkspace);
List<ItemSpec> its = new List<ItemSpec>();
its.Add(new ItemSpec(serverPath, RecursionType.Full));
//get all candidate changes and promote them to included changes
ws.GetPendingChangesWithCandidates(its.ToArray(), true,
out candidateChanges);
foreach (var change in candidateChanges)
{
if (change.IsAdd)
{
ws.PendAdd(change.LocalItem);
}
else if (change.IsDelete)
{
ws.PendDelete(change.LocalItem);
}
}
//Check In all pending changes
ws.CheckIn(ws.GetPendingChanges(), "This is a comment");
}
I need to develop a Shell Context Menu extension that references some other custom assemblies... I don't want to assign a Strong Name Key to those custom assemblies!
The guide I followed to do this uses the SharpShell project and illustrates how to sign (but does not expalins why) the assembly... and this is my problem: if I sign my final .dll then I have many errors during my project's building phase, because some assemblies my project references are not strongly named ("Referenced assembly does not have a strong name").
In general, googling about the C# Shell Extension implementation, all best tutorials I found sign the final assembly... is it mandatory?
Without signing the assembly ServerManager.exe returns this error: "The file 'XYZ.dll' is not a SharpShell Server".
Finally I've solved my troubles... the SharpShell.dll file obtained through NuGet was a different version of the ServerManager.exe ones.
Uninstalling the SharpShell NuGet package and directly referencing the SharpShell.dll you find inside the ServerManager folder was my solution!
Moreover, I was looking between the article comments... please read this question.
You don't need to use old DLL.
Please use this code directly, without using ServerManager.exe.
private static ServerEntry serverEntry = null;
public static ServerEntry SelectedServerEntry
{
get
{
if (serverEntry == null)
serverEntry = ServerManagerApi.LoadServer("xxx.dll");
return serverEntry;
}
}
public static ServerEntry LoadServer(string path)
{
try
{
// Create a server entry for the server.
var serverEntry = new ServerEntry();
// Set the data.
serverEntry.ServerName = Path.GetFileNameWithoutExtension(path);
serverEntry.ServerPath = path;
// Create an assembly catalog for the assembly and a container from it.
var catalog = new AssemblyCatalog(Path.GetFullPath(path));
var container = new CompositionContainer(catalog);
// Get the exported server.
var server = container.GetExport<ISharpShellServer>().Value;
serverEntry.ServerType = server.ServerType;
serverEntry.ClassId = server.GetType().GUID;
serverEntry.Server = server;
return serverEntry;
}
catch (Exception)
{
// It's almost certainly not a COM server.
MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning");
return null;
}
}
Install code:
ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true);
Register code:
ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit);
I like to checkout a file trough C# code, but I always get a TF14098 Acess Denied Exception. The TFS Administrator reassures, that I have checkout/edit permissions and in VisualStudio and with tf.exe I do not have any problems to checkout the file.
This is my current C# code:
const string tfsServer = #"http://MyServer:8080/tfs";
const string fileName = #"$/MyFile.xaml";
const string workspaceName = "MyWorkspace";
using (TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(tfsServer)))
{
if (tfs != null)
{
WorkspaceInfo workspaceInfo = Workstation.Current.GetLocalWorkspaceInfo(fileName);
if (null != workspaceInfo)
{
var vcs = tfs.GetService<VersionControlServer>();
Workspace workspace = workspaceInfo.GetWorkspace(tfs);
if(workspace == null){
workspace = vcs.GetWorkspace(workspaceName, vcs.AuthorizedUser);
}
vcs.NonFatalError += VersionControlOnNonFatalError;
vcs.Getting += OnGetting;
vcs.BeforeCheckinPendingChange += OnBeforeCheckinPendingChange;
vcs.NewPendingChange += OnNewPendingChange;
if (workspace != null)
{
workspace.PendEdit(fileName);
}
}
}
}
It results always with:
Non-fatal failure: TF14098: Access Denied: User Me needs PendChange permission(s) for $/MyFile.xaml.
After a lot of research for this error I tryed to check the permissions trough Dos-Box and I did the following commandline:
tf checkout $/MyFile.xaml
it results in a Checkout of the file without any problem! (If I am in the directory where the file resists)
Has anyone a Idea what the problem may be? What's the difference between my code (my Application written and executed with VisualStudio2012) and the commandline tf checkout?
Thanks for tips and hints!
Patrik
The problem in your code is, that the TfsTeamProjectCollection does not fit to your path, because you never set the Collection name (should be something like #"http://MyServer:8080/tfs/DefaultCollection").
I never did a checkout by using the API, but I did a checkin starting like this:
WorkspaceInfo wi = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
TfsTeamProjectCollection tfs = new TfsTeamProjectCollection(wi.ServerUri);
VersionControlServer versionControlServer = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
Workspace workSpace = versionControlServer.GetWorkspace(wi);
As you can see, I search the TeamCollection by using my workspace and not setting it independent. Doing it this way, you will get the right VersionControlServer to do your checkout.
The difference by using the tf.exe tool is, that you run it in your local workspace, so the tool knows to which item it is linked in TFS and to which Collection.
I don't have a great deal of experience with TFS, other than using it for source control. I am working on a C# application that will need to modify files that are being controlled by TFS. From within my C# application, how can I check out a file that is controlled via TFS?
Thanks - Randy
You can use PendEdit to make your files writables, make your changes to it, then you add it to the pending changes, and finally check it in.
Here is some code where a folder structure is created and then checked in (Very similar to what you will need).
private static void CreateNodes(ItemCollection nodes)
{
using (var tfs = TeamFoundationServerFactory.GetServer("http://tfsserver:8080"))
{
var versionControlServer = tfs.GetService(typeof (VersionControlServer)) as VersionControlServer;
versionControlServer.NonFatalError += OnNonFatalError;
// Create a new workspace for the currently authenticated user.
var workspace = versionControlServer.CreateWorkspace("Temporary Workspace", versionControlServer.AuthenticatedUser);
try
{
// Check if a mapping already exists.
var workingFolder = new WorkingFolder("$/testagile", #"c:\tempFolder");
// Create the mapping (if it exists already, it just overides it, that is fine).
workspace.CreateMapping(workingFolder);
// Go through the folder structure defined and create it locally, then check in the changes.
CreateFolderStructure(workspace, nodes, workingFolder.LocalItem);
// Check in the changes made.
workspace.CheckIn(workspace.GetPendingChanges(), "This is my comment");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
// Cleanup the workspace.
workspace.Delete();
// Remove the temp folder used.
Directory.Delete("tempFolder", true);
}
}
}
private static void CreateFolderStructure(Workspace workspace, ItemCollection nodes, string initialPath)
{
foreach (RadTreeViewItem node in nodes)
{
var newFolderPath = initialPath + #"\" + node.Header;
Directory.CreateDirectory(newFolderPath);
workspace.PendAdd(newFolderPath);
if (node.HasItems)
{
CreateFolderStructure(workspace, node.Items, newFolderPath);
}
}
}
Using the other solution gave me permission problems.
Here's an alternative way to checkout your files using tf.exe:
//Checkout file
Process proc = new Process();
proc.StartInfo =
new ProcessStartInfo(
#"C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\tf.exe",
string.Format("checkout \"{0}\"", fileLocation)
);
proc.StartInfo.UseShellExecute = false;
proc.Start();
proc.WaitForExit();
For those looking to use the first solution and resolve the permission issue you can use the following code to use the current credentials, this replaces the "TeamFoundationServerFactory.GetServer" call then use the TfsTeamProjectCollection (tmPrjColl) to get the VersionControlServer:
using Microsoft.TeamFoundation.Client;
using MTVC = Microsoft.TeamFoundation.VersionControl.Client;
using MVSC = Microsoft.VisualStudio.Services.Common;
MVSC.VssCredentials creds = new MVSC.VssCredentials(new MVSC.WindowsCredential(true));
using (TfsTeamProjectCollection tmPrjColl = new TfsTeamProjectCollection(new Uri("<source control URL>"), creds))
{
MTVC.VersionControlServer verCtrlSvr = tmPrjColl.GetService<MTVC.VersionControlServer>();
...
}