get specific projects that a user is a part of - c#

Here I am using IIdentityManagementService to retrieve a specified user by name. Now I want to retrieve only those team projects which they are a member of and can create tasks/workitems for in TFS. My program allows a user to create a task in TFS and I only want them to be able to see a list of the projects which they have access to for creating tasks/work items.
var tfsTpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://dotnettfs:8080/tfs/"));
identityService = tfsTpc.GetService<IIdentityManagementService>();
userId = identityService.ReadIdentity(
IdentitySearchFactor.DisplayName,
strOutlookUser,
MembershipQuery.Direct,
ReadIdentityOptions.None
);
userTpc = new TfsTeamProjectCollection(tfsTpc.Uri, userId.Descriptor);
cssService = (ICommonStructureService4)userTpc.GetService(typeof(ICommonStructureService4));
wis = userTpc.GetService<WorkItemStore>();
lstAllProjects.AddRange(cssService.ListAllProjects().ToList());
List<string> lstViewProjectNames = lstAllProjects.Select(a => a.Name).ToList();
Right now, the list shows all projects within that software collection when I want it to show only those projects which the retrieved user has access to.
then they are able to create a task and specify the iteration and area for one of those projects.
var store = wis.Projects[0]; //should be a specified project, not the first element.
WorkItem pbi = new WorkItem(store.WorkItemTypes["Product Backlog Item"]);
pbi.IterationPath = lstIterations.Where(a => a.Name == selectedIteration.ToString())
.Select(a => a.Path).First().ToString();
pbi.AreaPath = lstAreas.Where(a => a.Name == selectedArea.ToString())
.Select(a => a.Path).First().ToString();

I only want them to be able to see a list of the projects which they
have access to for creating tasks/work items.
Work items are tied to areas and areas are tied to team projects.
The basic steps are:
1) Connect to TFS as the user in question
2) Retrieve the team project in question
3) Get the areas for the team project in question
4) Check each one for the ability to create work items (you can probably get away with doing the recursive check on just the root area node)
The usings you will need (might not need all):
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.TeamFoundation.Server;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
IIdentityManagementService identityManagementService = tpc.GetService<IIdentityManagementService>();
TfsTeamProjectCollection tpc = GetTfsCollection();
TeamFoundationIdentity identity = identityManagementService.ReadIdentity(IdentitySearchFactor.AccountName, #"Domain\username", MembershipQuery.None, ReadIdentityOptions.None);
TfsTeamProjectCollection impersonatedTPC = new TfsTeamProjectCollection(new Uri(this._tfsUri, this._tfsCollectionName), identity.Descriptor);
WorkItemStore impersonatedWIS = impersonatedTPC.GetService<WorkItemStore>();
ProjectCollection impersonatedProjects = impersonatedWIS.Projects;
foreach (Project p in impersonatedProjects)
{
if (p.Name == "My Team Project")
{
NodeCollection areas = p.AreaRootNodes;
foreach (Node area in areas)
{
if (area.HasWorkItemWriteRightsRecursive)
{
//They do have rights
}
}
}
}
Note that I call GetTfsCollection() which my own user defined function (this is just the class that I constructed with, passing in the root tfs uri and the collection name as string). I also didn't put in any exception handling, just showing the basics:
private TfsTeamProjectCollection GetTfsCollection()
{
return TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(this._tfsUri, this._tfsCollectionName));
}

Related

Using Microsoft.Xrm.Tooling to create a service and context

I am now updating an integration program written for Dynamics 2015 in order to support Dynamics 365. At the moment it uses the Microsoft.Xrm.Client dll methods to create an organization service context. Is there an equivalent to Microsoft.Xrm.Tooling as Microsoft.Xrm.Client seems unsupported.
var getCRMOrgService = CreateCRMOrgService(logger);
var client = CreatePosPerfectConnection(logger);
if (getCRMOrgService != null)
{
using (var ctx = new DataContext(new CrmOrganizationServiceContext(getCRMOrgService)))
{
ctx.TryAccessCache(cache => cache.Mode = OrganizationServiceCacheMode.Disabled);
/******Rest of the code******/
Here I require to change the CreateCRMOrgService and CrmOrganizationServiceContext Methods to the ones supported by Microsoft.Xrm.Tooling alone
It looks like you'll want to switch to CrmServiceClient, which is in the Microsoft.Xrm.Tooling.Connector namespace.
To get the NuGet package:
In your project, right click on the References node and select Manage NuGet Packages. Under Browse search for "xrm tooling". Install Microsoft.CrmSdk.XrmTooling.CoreAssembly and you should be good to go.
Then create a CrmServiceClient via a connection string
var svc = new CrmServiceClient(connectionString);
Then for the context (query provider) do something like this (please note this is untested code):
private List<Entity> getRecords()
{
using (var context = new Microsoft.Xrm.Sdk.Client.OrganizationServiceContext(svc))
{
var result = from e in organizationServiceContext.CreateQuery("new_entity")
where e.GetAttributeValue<string>("new_field") == "my value"
select e;
return result.Take(100).ToList();
}
}

Finding user in TFS Project programmatically

We have more than one collection under one TFS server and each collection have more than one project. I want to be able to check if entered username is part of any project level group on TFS server.
So far I am able to connect to TFS, and get all project names under the collection. I need help in finding the group name and then querying those groups to check if user is part of that group or not.
Here is the code I tried -
static void Main(string[] args)
{
NetworkCredential netCred = new NetworkCredential(#"username", #"pwd");
TfsConfigurationServer configServ = new TfsConfigurationServer(new Uri("https://my-tfs.schwab.com/tfs"), netCred);
var tfsAllCols = new List<KeyValuePair<Guid, string>>();
try
{
configServ.Authenticate();
Console.WriteLine("Autheticated in server with ad creds...");
ReadOnlyCollection<CatalogNode> colNodes = configServ.CatalogNode.QueryChildren(
new[] { CatalogResourceTypes.ProjectCollection },
false,
CatalogQueryOptions.None);
foreach (CatalogNode node in colNodes)
{
var colId = new Guid(node.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection teamProjectCollection =
configServ.GetTeamProjectCollection(colId);
tfsAllCols.Add(new KeyValuePair<Guid, string>(colId, teamProjectCollection.Name));
}
//hardcoding the colname for testing
TfsTeamProjectCollection tpc = new TfsTeamProjectCollection(new Uri("https://ruby-tfs.schwab.com/tfs/colname/"), netCred);
tpc.EnsureAuthenticated();
// Get the catalog of team project collections
ReadOnlyCollection<CatalogNode> projNodes = tpc.CatalogNode.QueryChildren(
new[] { CatalogResourceTypes.TeamProject },
false, CatalogQueryOptions.None);
}
catch (Exception ex)
{
throw ex;
}
Console.ReadLine();
}
Instead of hard coding, you could use TFSSecurity command-line tool to retrieve the groups and members in team project:
Use /g to list the groups in a team project, in a team project collection, or across Team Foundation Server:
tfssecurity /g [scope] [/collection:CollectionURL] [/server:ServerURL]
Use /imx to display information about the identities that compose the expanded membership of a specified group:
> tfssecurity /imx Identity [/collection:CollectionURL][/server:ServerURL]
If you insist hard coding, you could follow the blog below to query TFS for groups and memberships:
https://blogs.msdn.microsoft.com/vasu_sankaran/2010/10/11/querying-tfs-for-groups-and-memberships/
Update:
If you want to check the user's groups, you can call ims.ReadIdentity() method directly. Here is the simple code for your reference:
using System;
using System.Collections.Generic;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;
using Microsoft.VisualStudio.Services.Client;
using Microsoft.VisualStudio.Services.Common;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
TfsConfigurationServer tcs = new TfsConfigurationServer(new Uri("http://xxxx:8080/tfs/"));
IIdentityManagementService ims = tcs.GetService<IIdentityManagementService>();
TeamFoundationIdentity tfi = ims.ReadIdentity(IdentitySearchFactor.AccountName, "domain\\username", MembershipQuery.Direct, ReadIdentityOptions.None);
Console.WriteLine("Listing Groups for:" + tfi.DisplayName);
Console.WriteLine("Total " + tfi.MemberOf.Length + " groups.");
IdentityDescriptor[] group = tfi.MemberOf;
foreach (IdentityDescriptor id in group)
{
TeamFoundationIdentity detail = ims.ReadIdentity(IdentitySearchFactor.Identifier, id.Identifier, MembershipQuery.None, ReadIdentityOptions.None);
Console.WriteLine(detail.DisplayName);
}
Console.ReadLine();
}
}
}
If this does not meet your requirement, you can also use this method to get the members of each project group.

Access the Source Control Explorer in TFS from C#.net code

Here is the code which I have written to access the Projects and the team, but it shows some error. I want to access the project and then the Source Code present in the Source Control Explorer in the Project/Team.
Uri _serverUri = new Uri("MyURI");
string _teamProjectName = "MyProject";
TfsTeamProjectCollection collection =
TfsTeamProjectCollectionFactory.GetTeamProjectCollection(_serverUri);
// Retrieve the project URI. Needed to enumerate teams.
var css4 = collection.GetService<ICommonStructureService>();
ProjectInfo projectInfo = css4.GetProjectFromName(_teamProjectName);
// Retrieve a list of all teams on the project.
TfsTeamService teamService = collection.GetService<TfsTeamService>();
var allTeams = teamService.QueryTeams(projectInfo.Uri);
allTeams.ToList().ForEach
(
allteams => { Console.WriteLine(allteams); });
The error which it shows is "The type or namespace 'Core' does not exist in the namespace Microsoft.TeamFoundation.Server
I also want to access the source control, so if anyone can help me with both of my issues.

SharePoint 2010: How to extract personalized web part property for all users

Background:
I have a built-in-house custom SharePoint 2010 web part, inheriting from System.Web.UI.WebControls.WebParts.WebPart, which has a property defined like so:
[Personalizable(PersonalizationScope.User)]
[WebBrowsable(true)]
[WebDisplayName("...")]
[WebDescription("...")]
[Category("...")]
public string CustomProp { get; set; }
The Powers-That-Be would like to know the value of the property for each of its 3,000 users. I'm already familiar with how to use the SPLimitedWebPartManager to extract the property in either shared view or my own personal view, using code similar to:
var pageUrl = "/Pages/SomePage.aspx";
var limitedManager = SPContext.Current.Web.GetLimitedWebPartManager(
pageUrl,
PersonalizationScope.User); // or .Shared, if loading the shared value
var webPart = limitedManager.WebParts.OfType<MyWebPart>().FirstOrDefault();
var prop = webPart.CustomProp;
So, the question:
I'm stuck on collecting this information for all users. Assuming I already have, or know how to retrieve, a list of login names or SPUser objects, how do I go about retrieving the web part property for all users? I can use suggestions in C#, VB.NET, or PowerShell.
Try this code - I haven't tested it but I think it should work.
const string absolutePageUrl = "http://spsite:5000/Pages/SomePage.aspx";
foreach (SPUser user in SPContext.Current.Site.RootWeb.AllUsers.Cast<SPUser>())
{
if (!user.LoginName.StartsWith("DOMAIN NAME"))
continue;
using (SPSite site = new SPSite(absolutePageUrl, user.UserToken))
using (SPWeb web = site.OpenWeb())
{
var mgr = web.GetLimitedWebPartManager(absolutePageUrl, PersonalizationScope.User);
var webPart = mgr.WebParts.OfType<MyWebPart>().FirstOrDefault();
var prop = webPart.CustomProp;
}
}

TFS 2010: How to produce a changelog (ie. list of work items) between two releases of the application using labels?

I'm looking for a way to automatically produce a changelog (actually a list of workitems) between two releases of my application. I have two versions of my application, v1 and v2, each is identified by a label in TFS 2010 (LABEL1 and LABEL2) that I manually created before building the setups of my app.
I have a branching system, which means I have a trunk were most of bugs are fixed, and a branch where patches are applied mostly using merges from the trunk (but there are also some fixes on the branch only that do not concern the trunk). The two versions of my application (v1 and v2) are versions from the branch.
I would like TFS 2010 to be able to return the list of bugs that were fixed (ie. the list of work items with type = Bug that are closed and verified) between these two labels.
I tried to achieve this using the web UI of TFS 2010, or using Visual Studio, but I didn't find any way.
Then I tried to ask tf.exe for a history using the following command line:
tf history /server:http://server_url/collection_name "$/project_path" /version:LLABEL1~LLABEL2 /recursive /noprompt /format:brief
where LABEL1 is the label that has been associated with the source code of the v1 of the application, and LABEL2 the label that has been associated with the source code of the v2 of the application.
It actually fails in two ways:
- the command line only returns a list of changesets, not a list of associated closed work items
- the list of changesets only contains the changesets that I applied on the branch itself, not the changesets that I also applied and the trunk and then merged to the branch. Setting or not the "/slotmode" parameter doesn't change anything.
There I tried to write a piece of C# code to retrieve the list of workitems (not the list of changesets):
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://server_url/collection_name"));
VersionControlServer controlServer = tfs.GetService<VersionControlServer>();
VersionControlServer vcs = tfs.GetService<VersionControlServer>();
VersionSpec sFrom = VersionSpec.ParseSingleSpec("LLABEL1", null);
VersionSpec sTo = VersionSpec.ParseSingleSpec("LLABEL2", null);
var changesets = vcs.QueryHistory(
"$/project_path",
sTo,
0,
RecursionType.Full,
null,
sFrom,
sTo,
int.MaxValue,
true,
false); // Slotmode to false
Dictionary<int, WorkItem> dico = new Dictionary<int, WorkItem>();
foreach (Changeset set in changesets)
{
foreach (WorkItem zz in set.WorkItems)
{
if (!dico.ContainsKey(zz.Id))
{
dico.Add(zz.Id, zz);
}
}
}
foreach (KeyValuePair<int, WorkItem> pair in dico.OrderBy(z => z.Key))
{
Console.WriteLine(string.Format("ID: {0}, Title: {1}", pair.Key, pair.Value.Title));
}
This actually works, I get the list of workitems between my two labels which is actually what I wanted. But only workitems associated to changesets that were committed on the branch itself are taken into account: the workitems of type "Bug" that were solved on the trunk then merged to the branch don't appear. Slotmode doesn't change anything.
Then I finally tried to replace VersionSpecs that were defined by a label with VersionSpecs that are defined by changesets:
VersionSpec sFrom = VersionSpec.ParseSingleSpec("C5083", null);
VersionSpec sTo = VersionSpec.ParseSingleSpec("C5276", null);
And my code finally works.
So my question is: how could I get the same result with labels, which are the TFS objects I use to identify a version? If it's not possible, how should I identify a version in TFS 2010?
Thx.
Btw I found some questions on stackoverflow, but none of them gave me answers with labels. For instance:
Question example
I think http://tfschangelog.codeplex.com/ can possibly help you here.
TFS ChangeLog applicatoin allows users to automatically generate release notes from TFS. Users will have to provide information on thier project, branch and changeset range and then TFS ChangeLog application will extract information from each changeset in a given range and all the associated workitems to such changesets. i.e. it will travel from starting changeset upto ending changeset and will extract data about each changeset along with associated workitems in an XML file.
Users can then use their own transformation logic including filter, sorting, styling, output formatting, etc. to generate Release Notes Report.
Another thing I would like to add here will be related to Labels in TFS. Labels are basically assigned / associated with changesets. Currently, TFS ChangeLog application does not support Labels to define starting and ending point but it does support changeset which can be used as a workaround solution.
Hope this is useful.
In general, the absolute method of defining points in time in any SCM is clearly the checkin-id. Using labels to abstract this, is in TFS not the optimum as discussed here & here. A better approach is to use builds instead, especially in a modern CI environment.
In order to retrieve the max changeset that was contained in a given build you 'd have to do something like this:
using System;
using System.Collections.Generic;
using Microsoft.TeamFoundation.Build.Client;
using Microsoft.TeamFoundation.Client;
namespace GetChangesetsFromBuild
{
class Program
{
static void Main()
{
TfsTeamProjectCollection tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri("http://TFSServer:8080/Name"));
IBuildServer bs = (IBuildServer)tpc.GetService(typeof(IBuildServer));
IBuildDetail build = bs.GetAllBuildDetails(new Uri("vstfs:///..."));
List<IChangesetSummary> associatedChangesets = InformationNodeConverters.GetAssociatedChangesets(build);
int idMax = associatedChangesets[0].ChangesetId;
}
}
}
A difficulty with the above is to retrieve the BuildUri of the builds you are interested in. In order to get this information you could do something like this:
IBuildDetail[] builds = bs.QueryBuilds("TeamPorjectName", "yourBuildDefinitionName")
and then retrieve the Uri's that are important to you.
This is also a good vehicle if you eventually insist on using labels: Besides Uri, each build[] has also a LabelName.
I have been in the same situation as you. I also want Work Items from merged changesets included. I only include Work Items that are Done. Also if the same Work Item is linked to multiple changesets, only the last changeset is reported. I use this in a CI setup; and create a changelog for each build. The List<ChangeInfo> can then be exported to a XML/HTML/TXT-file. Here is my solution:
namespace TFSChangelog
{
public class TFSChangelogGenerator
{
private const string workItemDoneText = "Done";
/// <summary>
/// This class describes a change by:
/// Changeset details
/// and
/// WorkItem details
/// </summary>
public class ChangeInfo
{
#region Changeset details
public DateTime ChangesetCreationDate { get; set; }
public int ChangesetId { get; set; }
#endregion
#region WorkItem details
public string WorkItemTitle { get; set; }
public int WorkItemId { get; set; }
#endregion
}
public static List<ChangeInfo> GetChangeinfo(string tfsServer, string serverPath, string from, string to)
{
// Connect to server
var tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(tfsServer));
tfs.Connect(ConnectOptions.None);
var vcs = tfs.GetService<VersionControlServer>();
// Create versionspec's
VersionSpec versionFrom = null;
if (!string.IsNullOrEmpty(from))
versionFrom = VersionSpec.ParseSingleSpec(from, null);
VersionSpec versionTo = VersionSpec.Latest;
if (!string.IsNullOrEmpty(to))
versionTo = VersionSpec.ParseSingleSpec(to, null);
// Internally used dictionary
var changes = new Dictionary<int, ChangeInfo>();
// Find Changesets that are checked into the branch
var directChangesets = vcs.QueryHistory(
serverPath,
VersionSpec.Latest,
0,
RecursionType.Full,
null,
versionFrom,
versionTo,
Int32.MaxValue,
true,
false
).Cast<Changeset>();
foreach (var changeset in directChangesets)
{
foreach (var workItem in changeset.WorkItems.Where(workItem => workItem.State == workItemDoneText))
{
if (changes.ContainsKey(workItem.Id))
{
if (changeset.ChangesetId < changes[workItem.Id].ChangesetId) continue;
}
changes[workItem.Id] = new ChangeInfo { ChangesetId = changeset.ChangesetId, ChangesetCreationDate = changeset.CreationDate, WorkItemId = workItem.Id, WorkItemTitle = workItem.Title };
}
}
// Find Changesets that are merged into the branch
var items = vcs.GetItems(serverPath, RecursionType.Full);
foreach (var item in items.Items)
{
var changesetMergeDetails = vcs.QueryMergesWithDetails(
null,
null,
0,
item.ServerItem,
VersionSpec.Latest,
0,
versionFrom,
versionTo,
RecursionType.Full
);
foreach (var merge in changesetMergeDetails.Changesets)
{
foreach (var workItem in merge.WorkItems.Where(workItem => workItem.State == workItemDoneText))
{
if (changes.ContainsKey(workItem.Id))
{
if (merge.ChangesetId < changes[workItem.Id].ChangesetId) continue;
}
changes[workItem.Id] = new ChangeInfo { ChangesetId = merge.ChangesetId, ChangesetCreationDate = merge.CreationDate, WorkItemId = workItem.Id, WorkItemTitle = workItem.Title };
}
}
}
// Return a list sorted by ChangesetId
return (from entry in changes orderby entry.Value.ChangesetId descending select entry.Value).ToList();
}
}
}
This question got me closer to solving a similar problem I was having.
Use the type LabelVersionSpec instead of VersionSpec for label versions.
Replace:
VersionSpec sFrom = VersionSpec.ParseSingleSpec("LLABEL1", null);
VersionSpec sTo = VersionSpec.ParseSingleSpec("LLABEL2", null);
with:
LabelVersionSpec sFrom = new LabelVersionSpec("LLABEL1");
LabelVersionSpec sTo = new LabelVersionSpec("LLABEL2");

Categories

Resources