Get required fields for some WorkItem - tfs

Is it possible to get such XML, using TFS API or other tools?
This XML contains information about the fields that must be filled in translation work item to another status.
Screen here http://sqlrefactorstudio.com/content/png/TFS%20Work%20item%20required%20fields.png

Using the TFS API in the simple example below will write out the required fields for a given work item.
/// <summary>
/// Writes out the required fields for a work item.
/// </summary>
/// <param name="workItemId">The ID of a work item.</param>
private static void _GetRequiredFieldsForWorkItem(int workItemId)
{
using (TeamProjectPicker tpp = new TeamProjectPicker(TeamProjectPickerMode.SingleProject, false, new UICredentialsProvider()))
{
if (tpp.ShowDialog() == DialogResult.OK)
{
TfsTeamProjectCollection projectCollection = tpp.SelectedTeamProjectCollection;
WorkItemStore store = projectCollection.GetService<WorkItemStore>();
Console.WriteLine("Required Work Item Fields");
Console.WriteLine("-------------------------------");
WorkItem item = store.GetWorkItem(workItemId);
foreach (Field field in item.Fields)
{
if (field.IsRequired)
{
Console.WriteLine(field.ReferenceName);
}
}
}
}
}

Related

What is the burden of User.Identity.GetUserId()?

In my ASP.NET MVC applications I use User.Identity.GetUserId() abundantly. However, I wonder if this has severe performance penalties.
Alternatively, I believe I can do this: In a View, I can assign the current user's id to a hidden field in the first page load. Then, when making AJAX calls, I can pass the hidden field value to controllers' actions. This way, I would not need to use User.Identity.GetUserId() method to retrieve the userid of the current user.
I wonder if anyone has any ideas on this?
Take a look at the source for GetUserId extension method:
/// <summary>
/// Return the user id using the UserIdClaimType
/// </summary>
/// <param name="identity"></param>
/// <returns></returns>
public static string GetUserId(this IIdentity identity)
{
if (identity == null)
{
throw new ArgumentNullException("identity");
}
var ci = identity as ClaimsIdentity;
if (ci != null)
{
return ci.FindFirstValue(ClaimTypes.NameIdentifier);
}
return null;
}
/// <summary>
/// Return the claim value for the first claim with the specified type if it exists, null otherwise
/// </summary>
/// <param name="identity"></param>
/// <param name="claimType"></param>
/// <returns></returns>
public static string FindFirstValue(this ClaimsIdentity identity, string claimType)
{
if (identity == null)
{
throw new ArgumentNullException("identity");
}
var claim = identity.FindFirst(claimType);
return claim != null ? claim.Value : null;
}
Every time you call that extension method it searches the identity for the ClaimTypes.NameIdentifier claim.
The performance impact is not that substantial (IMO) but leaking user information in hidden (there not actually hidden if one can see them with one click of view source) is not a good idea.
If you are concerned about calling it multiple times and need it in multiple locations through out a request then you can have it lazy loaded behind a property in your controller or a base controller.
private string userId
public string UserId {
get {
if(userid == null) {
userid = User.Identity.GetUserId();
}
return userid;
}
}
You could also create a service to encapsulate that information.

How to Get Current Project Name from TeamFoundationRequestContext

I'm writing a plugin for a TFS process.
I need to get the Project Name from the TeamFoundationRequestContext whenever a work item is in the process of saving.
Normally I can get the work item ID because the record has already been saved. However, when the work Item is being saved the first time, I do not have a way to get the work item ID.
My question is how can I get the Project Name from the TeamFoundationRequestContext when the work item saves for the first time.
Here is a class that captures the work item changed event and checks to see if it is a newly created work item.
From within the event if it is a newly created work item you can then do what you need with the Project name that is associated with that work item.
using Microsoft.TeamFoundation.Framework.Server;
using System;
using Microsoft.TeamFoundation.Common;
using Microsoft.TeamFoundation.WorkItemTracking.Server;
namespace TfsProcess.CaptureProjectNameOnNewWorkItem
{
public class CaptureProjectNameOnNewWorkItem : ISubscriber
{
public string Name
{
get
{
return "CaptureProjectNameOnNewWorkItem";
}
}
public SubscriberPriority Priority
{
get
{
return SubscriberPriority.Normal;
}
}
public EventNotificationStatus ProcessEvent(
TeamFoundationRequestContext requestContext,
NotificationType notificationType,
object notificationEventArgs,
out int statusCode,
out string statusMessage,
out ExceptionPropertyCollection properties)
{
statusCode = 0;
properties = null;
statusMessage = String.Empty;
try
{
ProcessNotification(notificationType, notificationEventArgs, requestContext);
}
catch (Exception exception)
{
TeamFoundationApplicationCore.LogException("Error processing event", exception);
}
return EventNotificationStatus.ActionPermitted;
}
private static void ProcessNotification(NotificationType notificationType, object notificationEventArgs, TeamFoundationRequestContext requestContext)
{
if (notificationType == NotificationType.Notification && notificationEventArgs is Microsoft.TeamFoundation.WorkItemTracking.Server.WorkItemChangedEvent)
{
var ev = notificationEventArgs as WorkItemChangedEvent;
if (ev.ChangeType == ChangeTypes.New)
{
//Do somethin with the project name of the newly created work item
// projectName = ev.PortfolioProject;
}
}
}
public Type[] SubscribedTypes()
{
return new Type[1] { typeof(WorkItemChangedEvent) };
}
}
}
Update:
You could create a plugin implementing the ITeamFoundationRequestFilter interface, which gets executed BEFORE or AFTER Team Foundation Server receives and processes requests. This allows you to validate work items and cancel the creation of the work item if it is not valid based on some logic for instance.
Here is a link to blog with a implementation of this that will cancel the creation of the work item if it is being created by a certain user.
Getting information from a TFS Request
How to implement ITeamFoundationRequestFilter
In order to get the Work Item ID you will intercept the xml soap response and parse it for the work item value.
Using the filter plugin you can filter for any of the methods responsible for updating, creating and querying work items.
The blog goes into more explanation and implementation.
The WorkItemChangedEvent event has a PortfolioProject property, so you should be able to get it like this:
var ev = (WorkItemChangedEvent)notificationEventArgs;
var projectName = ev.PortfolioProject

How to get options list of TFS optioned field?

I'm working on TFS API 2010.
I would like to get the available option list of a field to create a Combobox control. such as:
Priority --> [1,2,3,4]
Severity-->['4-low','3-medium','2-height','1-Critical']
You will need to export the WorkItemType Definition from TFS, then find the field in the xml and use the values from there. Below is a snippet of code that I used to get a list of transitions, if you think that the options might be in a Global List then you'll set the flag in the export method to true.
public List<Transition> GetTransistions(WorkItemType workItemType)
{
List<Transition> currentTransistions;
// See if this WorkItemType has already had it's transistions figured out.
this._allTransistions.TryGetValue(workItemType, out currentTransistions);
if (currentTransistions != null)
{
return currentTransistions;
}
// Get this worktype type as xml
XmlDocument workItemTypeXml = workItemType.Export(false);
// Create a dictionary to allow us to look up the "to" state using a "from" state.
var newTransitions = new List<Transition>();
// get the transitions node.
XmlNodeList transitionsList = workItemTypeXml.GetElementsByTagName("TRANSITIONS");
// As there is only one transitions item we can just get the first
XmlNode transitions = transitionsList[0];
// Iterate all the transitions
foreach (XmlNode transition in transitions)
{
// save off the transition
newTransitions.Add(new Transition { From = transition.Attributes["from"].Value, To = transition.Attributes["to"].Value });
}
// Save off this transition so we don't do it again if it is needed.
this._allTransistions.Add(workItemType, newTransitions);
return newTransitions;
}
Transition is a small class I have as below.
public class Transition
{
#region Public Properties
public string From { get; set; }
public string To { get; set; }
#endregion
}

Silverlight binding with filtering

I am currently trying to figure out a binding solution in Silverlight 4.
I have an observable collection of items. I want to bind this to a ComboBox but only display the items that match a certain condition. For example group == "Test Group." I have tried quite a few ways to make this work but haven't had any success.
In the past I have used LINQ in an exposed property on the VM e.g:
/// <summary>
/// Get filtered results(by location)
/// </summary>
public ObservableCollection<SearchResultData> FilteredResults {
get
{
return new ObservableCollection<SearchResultData>(Results.Where(p => p.LocationId == CurrentLocation.Id));
}
}
Using this approach you will need to provide a notification when the underlying collection in the LINQ changes e.g:
public ObservableCollection<SearchResultData> Results
{
get { return _results; }
set
{
_results = value;
NotifyOfPropertyChange(() => Results);
NotifyOfPropertyChange(() => FilteredResults);
}
}

Entity Framework 4: PropertyChanged event is raised too often

the generated code from EF for a property of an entity looks like this:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=false, IsNullable=false)]
[DataMemberAttribute()]
public global::System.DateTime DateCreated
{
get
{
return _DateCreated;
}
set
{
OnDateCreatedChanging(value);
ReportPropertyChanging("DateCreated");
_DateCreated = StructuralObject.SetValidValue(value);
ReportPropertyChanged("DateCreated");
OnDateCreatedChanged();
}
}
private global::System.DateTime _DateCreated;
partial void OnDateCreatedChanging(global::System.DateTime value);
partial void OnDateCreatedChanged();
This code doesn't check if the value has actually changed (in the setter). Therefore the PropertyChanged event is raised even if you set a value that is equal to the current value. But in this case nothing would have changed, so I wouldn't want this event...
For EntityKey properties they do check this:
/// <summary>
/// No Metadata Documentation available.
/// </summary>
[EdmScalarPropertyAttribute(EntityKeyProperty=true, IsNullable=false)]
[DataMemberAttribute()]
public global::System.Guid Id
{
get
{
return _Id;
}
set
{
if (_Id != value)
{
OnIdChanging(value);
ReportPropertyChanging("Id");
_Id = StructuralObject.SetValidValue(value);
ReportPropertyChanged("Id");
OnIdChanged();
}
}
}
private global::System.Guid _Id;
partial void OnIdChanging(global::System.Guid value);
partial void OnIdChanged();
I would expect this behavior from all properties.
Am I missing a setting in the model designer, or is there another solution?
Thanx!
It is point of T4 templates to allow you modifications you need. It is absolutely wrong approach to say:
But I would rather not use a custom template in my project!
It is like throwing all advantages of T4 templates away and going back to hardcoded custom tools for code generating.
I did, as I knew it was possible and Ladislav also stated, include the T4 template file into the project and made the following changes to the "Write PrimitiveType Properties." part of the template:
if (!Object.Equals(<#=code.FieldName(primitiveProperty)#>, value))
{
<#=ChangingMethodName(primitiveProperty)#>(value);
ReportPropertyChanging("<#=primitiveProperty.Name#>");
<#=code.FieldName(primitiveProperty)#> = StructuralObject.SetValidValue(value<#=OptionalNullableParameterForSetValidValue(primitiveProperty, code)#>);
ReportPropertyChanged("<#=primitiveProperty.Name#>");
<#=ChangedMethodName(primitiveProperty)#>();
}
Hope that will be helpfull to others.

Resources