3

Workstation.Current.GetLocalWorkspaceInfo(string) returns the WorkspaceInfo object associated with the given local directory.

So, I wrote a simple program that displays the workspace name given the local directory name. It works great on my machine, but does not work on another.

The difference between the two is that mine runs VS2012 and the other one - VS2013. For the life of me, I cannot understand it. Both workspaces are linked to the same TFS server 2010.

After reading TFS API: GetLocalWorkspaceInfo always returns null I replaced the Microsoft.TeamFoundation.XXX references to ones found on the second machine and it worked again. But, of course, it stopped working on my machine.

It cannot be the right way. I must be doing something wrong here.

I want a single executable to work for both machines without resorting to reflection. My question is simple - how?

The complete source code can be found here - https://bitbucket.org/markkharitonov/tfsinsanity/src. Basically, it is two projects sharing exactly the same source code, but using a different set of dependencies.

The main source code is:

private static Workspace GetWorkspace(string wsRoot, string wsName, string wsOwner)
{
    var coll = new TfsTeamProjectCollection(new Uri("http://torsvtfs01:8080/tfs/DefaultCollection"));
    var vcs = (VersionControlServer)coll.GetService(typeof(VersionControlServer));
    WorkspaceInfo wsInfo;
    if (wsRoot == null)
    {
        Console.WriteLine(Workstation.Current.Name);
        wsInfo = Workstation.Current.GetLocalWorkspaceInfo(vcs, wsName, wsOwner);
        if (wsInfo == null)
        {
            throw new Exception(string.Format("Failed to identify the workspace {0};{1}", wsName, wsOwner));
        }
    }
    else
    {
        wsInfo = Workstation.Current.GetLocalWorkspaceInfo(wsRoot);
        if (wsInfo == null)
        {
            throw new Exception(string.Format("Failed to identify the workspace corresponding to \"{0}\"", wsRoot));
        }
    }
    return wsInfo.GetWorkspace(coll);
}

Here how it works on my machine (VS2012):

PS C:\work\GetShelvedChangeset> tf workspaces
Collection: http://torsvtfs01:8080/tfs/defaultcollection
Workspace Owner                Computer Comment
--------- -------------------- -------- ------------------------------------------------------------------------------------
CANWS212  DAYFORCE\mkharitonov CANWS212
PS C:\work\GetShelvedChangeset> .\bin\Debug2012\GetShelvedChangeset.exe --wsRoot C:\dayforce\SharpTop
Microsoft.TeamFoundation.VersionControl.Client, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Workspace instance -784339741
  Comment:
  Computer: CANWS212
  EffectivePermissions: 0
  Folders: [0]
  IsLocalWorkspace: False
  LastAccessDate: 1/1/0001 12:00:00 AM
  Name: CANWS212
  Options: 0
  OwnerAliases: [0]
  OwnerDisplayName: DAYFORCE\mkharitonov
  OwnerIdentifier:
  OwnerIdentityType:
  OwnerName: DAYFORCE\mkharitonov
  OwnerUniqueName:
  SecurityToken: /CANWS212;34be4ed8-c4fd-4e9f-bdae-d1843df36b0f
PS C:\work\GetShelvedChangeset> .\bin\Debug2013\GetShelvedChangeset.exe --wsRoot C:\dayforce\SharpTop
Failed to identify the workspace corresponding to "C:\dayforce\SharpTop"
PS C:\work\GetShelvedChangeset>

And on the other machine:

PS C:\tfs\DFGatedCheckInTest2\Build\2010\scripts> &"C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\tf.exe" workspaces
Collection: http://torsvtfs01:8080/tfs/defaultcollection
Workspace            Owner             Computer     Comment
-------------------- ----------------- ------------ ----------------------------------------------------------------------------------------
1733_TORSVBUILD10    DAYFORCE\tfsbuild TORSVBUILD10 Workspace Created by Team Build
1846_91_TORSVBUILD10 DAYFORCE\tfsbuild TORSVBUILD10 Workspace Created by Team Build
1846_92_TORSVBUILD10 DAYFORCE\tfsbuild TORSVBUILD10 Workspace Created by Team Build
PS C:\tfs\DFGatedCheckInTest2\Build\2010\scripts> .\debug2012\GetShelvedChangeset.exe --wsRoot C:\tfs\DFGatedCheckInTest2
Failed to identify the workspace corresponding to "C:\tfs\DFGatedCheckInTest2"
PS C:\tfs\DFGatedCheckInTest2\Build\2010\scripts> .\debug2013\GetShelvedChangeset.exe --wsRoot C:\tfs\DFGatedCheckInTest2
Microsoft.TeamFoundation.VersionControl.Client, Version=12.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
Workspace instance 215494889
  Comment: Workspace Created by Team Build
  Computer: TORSVBUILD10
  EffectivePermissions: 0
  Folders: [0]
  IsLocalWorkspace: False
  LastAccessDate: 1/1/0001 12:00:00 AM
  Name: 1733_TORSVBUILD10
  Options: 0
  OwnerAliases: [0]
  OwnerDisplayName: DAYFORCE\tfsbuild
  OwnerIdentifier:
  OwnerIdentityType:
  OwnerName: DAYFORCE\tfsbuild
  OwnerUniqueName:
  SecurityToken: /1733_TORSVBUILD10;f2899138-af14-4449-9f6d-78a0fbccebb8
PS C:\tfs\DFGatedCheckInTest2\Build\2010\scripts>
Community
  • 1
  • 1
mark
  • 59,016
  • 79
  • 296
  • 580

2 Answers2

3

In this case, the method signatures should be identical, you simply need to worry about getting the proper DLL referenced in the first place. You should be able to link to the newer DLL and use binding redirection to load the DLL for users who have VS 2012 installed.

We used this method successfully in a previous product to provide TFS 2005 and 2008 compatibility.

In short, you create a custom assembly resolver. Here we will attempt to load all Microsoft.TeamFoundation.* DLLs from VS 2012 when we fail to load the VS 2013 versions that we were linked against:

AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(ResolveAssembly);

public static Assembly ResolveAssembly(object sender, ResolveEventArgs args)
{
    String[] arguments = args.Name.Split(new string[] { ", ", "," }, 
        StringSplitOptions.RemoveEmptyEntries);
    String assemblyName = arguments[0];

    if(assemblyName.StartsWith("Microsoft.TeamFoundation.", StringComparison.CurrentCultureIgnoreCase))
    {
        return Assembly.Load(assemblyName + ", Version=11.0.0.0");
    }

    return null;
}

(Note that you should probably check the requested version number and pass the culture information to the loader, as outlined in the blog post, but this snippet should be sufficient to get you started.)

Edward Thomson
  • 74,857
  • 14
  • 158
  • 187
  • +1. I will check this approach. However, am I the only one to think the whole affair is insane? – mark Oct 29 '14 at 14:03
  • The issue is more subtle. Apparently, the second machine has both versions of assemblies available in the GAC. So no assembly resolve event is ever fired. It just works wrong, that's it. – mark Oct 29 '14 at 14:39
  • Hi Mark..Can you please post your answer as how you solved this issue. I am also facing same issue and am unable to resolve it. Thanks in advance. – vinay May 14 '15 at 13:06
0

Add your project's referenced TFS assemblies to the executable, by setting the CopyLocal property to Always.

Giulio Vian
  • 8,248
  • 2
  • 33
  • 41