Home > C#, Team Foundation Server, WinRT > Using the Team Foundation Service OData API from a Windows Store app – Part two – Changesets

Using the Team Foundation Service OData API from a Windows Store app – Part two – Changesets

09/03/2013

In the first article of this series, we have talked about how to connect to Team Foundation Service using the new OData API to retrieve our team projects. Now we’ll see how to get the list of changesets of a certain project.

First of all, we need to update our model classes to store the new information. Let’s start from what we have created in the previous post (if you haven’t done it yet, you can download the app we have realized). Create a new class with name Changeset:

public class Changeset
{
    public string Name { get; set; }
    public string Description { get; set; }
    public Uri Uri { get; set; }
    public DateTimeOffset Date { get; set; }
    public string Author { get; set; }
}

Then, update the Project class with a property that holds the Uri of the resource that we must query to retrieve the Changesets list:

public class Project
{
    public string Name { get; set; }
    public Uri ChangesetsUri { get; set; }
}

Finally, we need to make a change to the TfsConnector class too. In particular, we need to define an overload for the GetAsync method that takes an Uri as input parameter. It represents the complete Url of the request, while the old method version, that takes a string, mantains the old behavior:

public class TfsConnector
{
    // ...
    
    private async Task<SyndicationFeed> GetAsync(string path)
    {
        var uri = new Uri(ServiceEndpoint + path);
        return await this.GetAsync(uri);
    }

    private async Task<SyndicationFeed> GetAsync(Uri uri)
    {
        var client = this.GetSyndicationClient();
        var feed = await client.RetrieveFeedAsync(uri);

        return feed;
    }
}

We need this new version because in the Project class we’ll save the complete Url for Changesets request, as it comes from the Project XML feed. Let’t see how to do that.

As we have seen in the first article, The XML feed that is returned when we make a request on the /Projects path contains, for each project, a list of link tags, each of one represeting the Url of a resource that can queried to obtain the corresponding information. For example:

<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Changesets" 
      type="application/atom+xml;type=feed" 
      title="Changesets" 
      href="Projects('MyProject')/Changesets" /> 
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Builds" 
      type="application/atom+xml;type=feed" 
      title="Builds" 
      href="Projects('MyProject')/Builds" /> 
<link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/BuildDefinitions" 
      type="application/atom+xml;type=feed" 
      title="BuildDefinitions" 
      href="Projects('MyProject')/BuildDefinitions" /> 

So, if we want to retrieve the Url for Changesets requests, we can search for a link tag whose title is equal to Changesets. We can do that in the GetProjectsAsync method of TfsConnector, that becomes as follows:

public async Task<IEnumerable<Project>> GetProjectsAsync()
{
    var projects = new List<Project>();
    var feed = await this.GetAsync(PROJECTS_PATH);

    foreach (SyndicationItem item in feed.Items)
    {
        var project = new Project
        {
            Name = item.Title.Text,
            ChangesetsUri = item.Links.Where(
                            l => l.Title.ToLower() == "changesets")
                            .Select(l => l.Uri).FirstOrDefault()
        };
        projects.Add(project);
    }

    return projects.OrderBy(p => p.Name);
}

Next, before analyzing the actual method that returns the Changesets list, take a look to another helper method:

private string GetTagElement(XmlDocument content, string tagName)
{
    var element = content.GetElementsByTagName("d:" + tagName);
    if (element != null)
        return ((XmlElement)(element.Item(0))).InnerText;

    return null;
}

Because some information from the feed is contained in tags that belong to a custom namespace, with the GetTagElement method we can easily retrive this data without having to worry about the namespace to use. As we’ll see in the next articles, we’ll use it many, times even for other type of requests. So, if you prefer, you can make it an extension method for the XmlDocument type.

Now, we have all the pieces that we need to actually retrieve the changesets list for a certain project. Add the following method to the TfsConnector class:

public async Task<IEnumerable<Changeset>> GetChangesetsAsync(Uri changesetsUri)
{
    var changesets = new List<Changeset>();
    var feed = await this.GetAsync(changesetsUri);

    foreach (SyndicationItem item in feed.Items)
    {
        var changeset = new Changeset
        {
            Name = item.Links.Where(
                    l => l.Title.ToLower() == "changeset")
                    .Select(l => l.Uri)
                    .FirstOrDefault().ToString().Split('/').Last(),
            Description = item.Summary.Text,
            Date = item.LastUpdatedTime,
            Uri = new Uri(this.GetTagElement(item.Content.Xml, "WebEditorUrl")),
            Author = this.GetTagElement(item.Content.Xml, "Committer"),
        };

        changesets.Add(changeset);
    }

    return changesets;
}

This code extract information from an XML element like to following:

<entry m:etag="W/"datetime'2012-12-07T22%3A55%3A15.337%2B00%3A00'"">
  <id>https://tfsodata.visualstudio.com/DefaultCollection/Changesets(113)</id> 
  <title type="text">vstfs:///VersionControl/Changeset/113</title> 
  <summary type="text">Changeset description</summary> 
  <updated>2012-12-07T22:55:15Z</updated> 
  <author>
    <name /> 
  </author>
  <link rel="edit" title="Changeset" href="Changesets(113)" /> 
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Changes"
        type="application/atom+xml;type=feed" 
        title="Changes" href="Changesets(113)/Changes" /> 
  <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/WorkItems" 
        type="application/atom+xml;type=feed"
        title="WorkItems" href="Changesets(113)/WorkItems" /> 
  <category term="Microsoft.Samples.DPE.ODataTFS.Model.Entities.Changeset" 
        scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" /> 
  <content type="application/xml">
    <m:properties>
      <d:Id m:type="Edm.Int32">113</d:Id> 
      <d:ArtifactUri>vstfs:///VersionControl/Changeset/113</d:ArtifactUri> 
      <d:Comment>Changeset description</d:Comment> 
      <d:Committer>Windows Live ID\commiter_mail@mail.com</d:Committer> 
      <d:CreationDate m:type="Edm.DateTime">2012-12-07T22:55:15.337+00:00</d:CreationDate> 
      <d:Owner>Windows Live ID\owner_mail@mail.com</d:Owner> 
      <d:Branch m:null="true" /> 
      <d:WebEditorUrl>

https://mydomain.visualstudio.com/web/cs.aspx?pcguid=95c4fe5e-057c-45ee-ab78-5e689ba82238&cs=113

      </d:WebEditorUrl> 
    </m:properties>
  </content>
</entry>

Finally, we can update our Windows Store app. Remember that in the MainPage.xaml we have defined a layout with two columns. We’ll use the second one to show the changesets of the selected project. So, Add the following code to XAML declarations:

<Border Grid.Column="1" BorderThickness="1" BorderBrush="LightGray" Margin="10,0,0,0">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <TextBlock x:Name="SelectedProjectTextBlock" Margin="10"                               
                   Style="{StaticResource SubheaderTextStyle}"></TextBlock>
        <GridView Grid.Row="1"
            x:Name="detailsGridView"
            SelectionMode="None"
            IsItemClickEnabled="True"
            ItemClick="detailsGridView_ItemClick">
            <GridView.ItemTemplate>
                <DataTemplate>
                    <StackPanel Height="140" Width="480" Margin="10">
                        <TextBlock Text="{Binding Name}" 
                                Style="{StaticResource TitleTextStyle}" Margin="5,5,0,0"/>
                        <TextBlock Text="{Binding Date}"
                                Style="{StaticResource ItemTextStyle}" Margin="5,5,0,0"/>
                        <TextBlock Text="{Binding Author}"
                                Style="{StaticResource ItemTextStyle}" Margin="5,5,0,0"/>
                        <TextBlock Text="{Binding Description}"
                                Style="{StaticResource BodyTextStyle}" Margin="5,5,0,0"
                                TextWrapping="Wrap" TextTrimming="WordEllipsis" />
                    </StackPanel>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>
    </Grid>
</Border>

We also need to update the definition of Project ListView in order to add the handler of the ItemClick event:

<ListView x:Name="itemsListView"
          SelectionMode="None"
          IsItemClickEnabled="True"
          ItemClick="itemsListView_ItemClick">

It’s the turn of the code in the MainPage.xaml.cs file. First, define the method that handles the itemsListView_ItemClick event:

private async void itemsListView_ItemClick(object sender, ItemClickEventArgs e)
{
    var project = e.ClickedItem as Project;
    SelectedProjectTextBlock.Text = "Changesets of " + project.Name;
    var changesets = await tfsConnector.GetChangesetsAsync(project.ChangesetsUri);
    detailsGridView.ItemsSource = changesets;
}

We get the clicked project and then we call the GetChangesetsAsync method on TfsConnector, using the Uri that we have retrieved when we obtained the project list.

Finally, we need to define also the handler for the detailsGridView_ItemClick method. When the user clicks a changeset, we want to open its Web page in the browser:

private async void detailsGridView_ItemClick(object sender, ItemClickEventArgs e)
{
    var changeset = e.ClickedItem as Changeset;
    await Windows.System.Launcher.LaunchUriAsync(changeset.Uri);
}

It’s all. Now we can start then app and tap a project to see its changesets:

TFS Changesets List

TFS Changesets List

This completes the second article about Team Foundation Service OData API in Windows Store apps. As usual, the app is available for download:

TfsOData_Part_Two

Next time we will take about builds.

About these ads
Follow

Get every new post delivered to your Inbox.

Join 32 other followers

%d bloggers like this: