Taoffi's blog

prisonniers du temps

Another TFS pause: moving your stuff

As I already said (I should not be the only one to sayJ): TFS is a precious tool for project management. The problem with TFS is the tedious processes to install and troubleshoot specific issues.

This has greatly been changed in TFS 2010 to become much less tedious (thanks to the TFS team and to Brian Harry for all the useful information) but IT IS, still, quite tedious!

For instance: One of the usual tasks we do from time in the real world is to move our stuff from somewhere to somewhere else!

Don't expect this to be as easy as you may think in TFSJ

 

The context

Let's say we have a whole TFS installation somewhere (configuration / collections databases… etc.) and we want (or need) to move everything to another machine.

At a first glance, that should be straightforward:

  • Install TFS (and SQL server) on the new machine;
  • Attach (or restore) TFS databases to the new machine;
  • Tell the new TFS where to find the databases;
  • Done!

 

Yes, it is a good path… but somewhat tortuous!

 

The recipe

On the new machine:

SQL configuration and settings

  • Install SQL Server (2008 or 2008R2). Note the following elementary observations:
    • During installation, you should select a CI AS (case insensitive / accent sensitive) collation (either Windows or SQL);
    • Prefer a 'default instance' installation
  • Attach (or restore) all TFS databases (configuration database, collections and datawarehouse databases.
  • Install latest SQL server updates and Service Packs.

 

TFS configuration and settings

  • Install TFS
  • DON'T click Configure at the end of the install process
  • Launch TFS admin console
    • Click Application Tier node
    • Click Configure Installed Features
    • Select the 'Application-Tier only' Wizard
    • Click List Available Databases.
      • This will display detected TFS configuration databases on the SQL server. If none is detected, then you have to go back to SQL configuration and see what is missing
    • Select the configuration database
    • Select the account service
    • Check and correct errors and warnings. You may need to go back to SQL configuration steps.
    • Click Configure

 

Problems encountered?

If you encounter problems (this is often the case with TFSJ), you may need to uninstall and restart the Application-Tier configuration:

  • Open a command prompt (Run As Administrator)
  • Go to TFS tools directory (%program files%\Microsoft Team Foundation Server 2010\Tools)
  • Uninstall the Application Tier: Type the following command:

tfsconfig setup /uninstall:ApplicationTier

  • Restart the above TFS configuration steps at Launch TFS admin console

 

Security configuration issues

Original SQL server configuration, TFS and various service accounts may not match the new machine's configuration. This may generate some errors that can be corrected using SQL server management studio and, in case, TF admin console (Administer security option). It is sometimes necessary to go through TFSSecurity command line utility.

 

Please note: all this should be considered as "useful hints" to solve TFS migration from machine to machine. You should be armed with patience and try find other simple and reliable paths for your specific problems.

Anyway, Hope this may help!

Object Visibility and learning cycle… just a vision of

In everyday work, we come through new tools or new versions of tools we knew before.

The cycle of playing with and manipulating these tools’ objects to attain a reasonable level of mastering… is often daunting!

To minimize the learning cycle of tools, some helpful features have been introduced: like documentation, tooltips… etc.

Documentation is of course important, but, for me, tooltips are much more helpful. They just appear when I need them in the context of using the object or the property.

The thing is: when you manipulate an object for the first time, you really know few things about its composition and, even less, about its role in the global mechanics of the tool in question. You just know it is there, and it should be there for some reason and that you should spend some time to understand: its role, its structure, and finally how can it be useful for you (if at all it could be!)

One way to shorten this learning cycle is to let others show you how to use the tool and its object. Quite useful, but, on one hand, this occults some side of self-experience (important)… and also negatively interferes in your critical view of the tool (which is often useful for the tool’s enhancement itself)

What we do to know about (most) simple toys seems more rational: You just set something on or off (left/right or up/down…)… then put the toy on work and see... after some cycles you end up by figuring out what is the ‘best’ position for your needs (or mood!).

Another representation, which may also give an interesting slant related to this subject, is the DeepZoom technology used in maps applications where you can first see the whole world map, and then, zooming-in on the map you get more details about a given country, city, streets, buildings… etc.

A good path for reducing the time and effort needed to learn a subject or a tool would be:

  • To be able to see (explore) the global image of the subject or tool’s structure in action;
  • Be able to zoom-in on its objects and see their properties (progressively detailed according to your zoom level);
  • Be able to change the value of a give object’ property… and perceive the impact of the change on the global behavior.

This proposed path cannot of course be applied in all situations or contexts, but can be useful in many (most) cases.

We may, for instance, need to create a simulation context inside which we can ‘run’ the specific tool or object. An approach which may also be useful for product tests and benchmarking.

Some interesting works have been done on some aspects (like The Property Grid project)… More is to be done on the visualization of objects and properties by zoom level. Will try to write a sample on this in a future post.

 

A dive into the undocumented TFS meta-model – Part II

 

In a previous post, I started exploring the TFS configuration database. Let's continue here by having a look at some more configuration objects and relationships.

TFS Config security objects

 

Referenced table

Primary column

Table

Foreign column

tbl_security_identity_cache

tf_id

tbl_gss_group_membership

member_id

tbl_security_identity_cache

tf_id

tbl_security_domain_groups

group_id

tbl_security_identity_cache

tf_id

tbl_security_membership_cache

container_id

tbl_security_identity_cache

tf_id

tbl_security_membership_cache

member_id

tbl_gss_groups

tf_id

tbl_gss_group_membership

parent_group_id

tbl_security_domain

domain_number

tbl_security_domain_groups

domain_number

tbl_security_domain

domain_number

tbl_security_projects

domain_number

tbl_security_identity_type

type_id (int)

tbl_security_identity_cache

type (tinyint)

The relationship diagram above suggests that we can query user logins, group-membership for specific projects by a query like the following:


SELECT TOP (100) PERCENT
    login.display_name  AS user_name,
    proj.scope_name     AS project,
    login_grp.display_name AS user_group

FROM dbo.tbl_security_membership_cache AS membership INNER JOIN
  dbo.tbl_security_identity_cache AS
login ON membership.member_id = login.tf_id INNER JOIN
  dbo.tbl_security_projects AS proj INNER JOIN
     dbo.tbl_security_domain AS domain INNER JOIN
       dbo.tbl_security_domain_groups AS grp ON domain.domain_number = grp.domain_number
       ON proj.domain_number = domain.domain_number
     ON
membership.container_id = grp.group_id INNER JOIN
  dbo.tbl_security_identity_cache AS
login_grp ON grp.group_id = login_grp.tf_id

ORDER
BY user_name, project

 

The above query may give us results similar to the following

user_name

project

user_group

Administrator

Research education "agile

Administrators

Administrator

Research education "agile

[TEAM FOUNDATION]\Team Foundation Service Accounts

Administrator

SourceSafeProjects

[TEAM FOUNDATION]\Team Foundation Service Accounts

Administrator

SourceSafeProjects

Administrators

Administrator

DefaultCollection

[TEAM FOUNDATION]\Team Foundation Service Accounts

Administrator

DefaultCollection

Administrators

 

TFS database pause: Change set quantitative statistics sample

Where to find change-sets information?


TFS source control maintains change-sets for projects in the corresponding collection database. Each change-set is of course composed of the modified project files at the time of the Check-in.

Change-set information is stored in the tbl_ChangeSet table of the project collection database. That is: if you have a project collection 'Default Collection' stored in a database named tfs_default_collection, you will find change-sets information in the table tfs_default_collection.dbo.tbl_ChangeSet.

Files information is stored in tbl_files table, and file-versions information in tbl_Version table.

So, to obtain the list of files of a change-set number 861, for instance, you can execute a query similar to the following:


SELECT TOP (100) percent
    chg_set.CreationDate,
    chg_set.ChangeSetId,
    v.FullPath

FROM
    dbo.tbl_ChangeSet (nolock)AS chg_set INNER JOIN
    
dbo.
tbl_Version (nolock)AS v ON chg_set.ChangeSetId = v.VersionFrom LEFT OUTER JOIN
    
dbo.
tbl_File (nolock) AS f ON v.FileId = f.FileId


WHERE (chg_set.ChangeSetId = 861)

ORDER BY chg_set.CreationDate, v.FullPath

 

 

Which may produce results like the following:

CreationDate

ChangeSetId

FullPath

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\commands\UniConvertCommandModel.cs\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\MainWindow.xaml.cs\

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\MainWindow.xaml\

 

How many bytes changed?


As you may have noticed from the figure above, change-set file information contains a FileLength column. This suggests that we can obtain the number of changed bytes of a given file between two change-sets… through the following query results we can know that the file grew 696-551 = 145 bytes:

CreationDate

ChangeSetId

FullPath

FileLength

2012-04-30 22:33:10.040

843

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

551

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

696

 

Who changed what?


The change-set table provides an CommitterId column through which we can know who made a given check-in. As this column contains an ID (integer refering tbl_identity.IdentityId), this is not straight forward information. We have to join other tables to obtain something useful.

In fact, the committer user name is stored in the Constants table. So, we have to join the Change-set's CommitterId column to tbl_identity.IdentityId, and then join tbl_identity.TeamFoundationId to Constants.TeamFoundationId… we can then get the user name in the Constants.DisplayPart column (or Constants.String column)

 

 

This can be presented by the following change in our initial view diagram:

 

CreationDate

ChangeSetId

FullPath

FileLength

DisplayPart

2012-04-30 22:33:10.040

843

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

551

Taoffi

2012-05-05 20:22:31.800

861

$\Research education "agile\SimpleUniConverter\Convert.xaml.cs\

696

Taoffi

 

Changed bytes tracking generalization


It would, ideally, be beneficial to integrate such information into the TFS analytical database.

We still can do some turnaround by directly querying the database tables.

The idea is to list all change-set files in the order of their respective check-in date. To handle the probability of identical dates / files, we can use a row number to distinguish changes. This may be done like in the following view:


CREATE VIEW [dbo].[xtfs_changeset_files_qry]
AS
SELECT
TOP (2147483647)
    ROW_NUMBER() over( ORDER BY chg_set.CreationDate) as row_number,
    chg_set.CreationDate,

    const.DisplayPart        as user_name,
    chg_set.ChangeSetId,

    v.FullPath,
    f.FileLength

FROM dbo.tbl_ChangeSet (nolock)    AS chg_set INNER JOIN
dbo.tbl_Identity (nolock)    AS login ON chg_set.CommitterId = login.IdentityId INNER JOIN
dbo.tbl_Version (nolock)    AS v ON chg_set.ChangeSetId = v.VersionFrom LEFT OUTER JOIN
dbo.tbl_File (nolock)        AS f ON v.FileId = f.FileId inner join
Constants (nolock)        AS const ON const.TeamFoundationId=login.TeamFoundationId

ORDER
BY chg_set.
CreationDate, v.FullPath


GO

 

We can then refer the view to itself (current version / previous version) obtain row-relative quantitative changes:

SELECT v1.row_number,
       v1.CreationDate,
       v1.user_name,
       v1.FullPath AS v1FilePath,
       v1.FileLength AS v1_length,
       v_next.FileLength AS v2_length,
       v_next.FullPath AS v2FilePath,
       ISNULL(v_next.FileLength, 0)
          - ISNULL(v1.FileLength, 0) AS changed_bytes

FROM dbo.xtfs_changeset_files_qry AS v_next RIGHT OUTER JOIN
     dbo.xtfs_changeset_files_qry AS v1 ON v_next.FullPath = v1.FullPath
        AND v_next.row_number = v1.row_number + 1
        OR v_next.FullPath IS NULL
        AND v_next.row_number IS NULL

 

A dive into the undocumented TFS meta-model – Part I

TFS… introduction to this series


Microsoft TFS (Team Foundation Server… recently renamed to ALM: Application Lifecycle Management) is a great project management platform.

TFS is built on meta-model abstractions (that were first seen, in Microsoft's products, in SharePoint).

TFS, like SharePoint, is composed of several software components which operate around several databases: the configuration database and one or more content databases.

Configuration and content databases' elements (tables, views, functions, stored procedures… etc.) represent the meta-models (schemas and business logic for each related feature) which govern and control much of the software components' behaviors.

TFS is often presented as a software project management solution. In my view, this seems a little reductive of its value. Because TFS features truly span a much larger project management scope.

Many useful literatures have been written about TFS: its features, usage, guidance, troubleshooting… etc. Few have enlightened its meta-model structures and, as of my knowledge, none has put some clear light about its (undocumented) databases' structures. That is what I will try to do in this series, more to value TFS abstractions than to nude its internal mechanics. And also to enforce, again, the meta-model approach as a rational basis for software solutions.

 

TFS logical architecture

 

For its contents, TFS maintains a database per project-collection.

Each collection may contain one or more projects. And each project can be managed according to a selected methodology (Agile / Scrum / CMMI… etc.). In fact, TFS applies and operates the selected methodology through the provided methodology project management template. Ultimately, this means you can build your own methodology and use it to manage your project with TFS. All what you need is to provide the desired methodology template.

Managing a project with TFS consists of recording and following-up specific Work items (defined by the methodology template)… those can be items like: Tasks, Bugs, Change requests, User story… etc.

As TFS was initially brewed to manage software projects, a common item in each project is the Source control repository which helps developers to maintain their source code versions and branches in a very efficient architecture composed of 'change sets'.

 

 

To discover and figure out its components' data and their required behaviors, TFS uses a configuration database. A first look at the configuration database will be the subject of this first article in the series.

 

The configuration database


Like SharePoint, TFS databases are delivered without documentation or relational diagrams. They simply don't contain any explicit Foreign-keys or relationships. Whatever the reason behind this choice, that seems a little surprising of a product whose main aim is projects' transparency and documentationJ.

That said, to discover, understand and correctly interpret the role of each TFS database item and their inter-relationships you should do a deep dive and be armed with some patience and empiric methods!

 

Hosts and processes


Let's have a look at three important tables:

  • tbl_ServiceHost contains the list of services' host information. This includes the item's name, the database connection string (when relevant), the Virtual directory and Resource directory…
  • tbl_ServiceHostProcess contains information about current processes. Machine name, Process name, Identity under which the process is running, start time…
  • tbl_ServiceHostInstance contains the list of processes' instances per host (Process Id / Host Id / Start time).

 

In my case, the table tbl_ServiceHost contained 3 entries for:

  • Team Foundation: root item (parentless… see diagram ParentHostId column). Connected to the configuration database.
  • Two child entries each for one of my TFS Project collections:
    • Default collection.
    • Training collection.

 

The above relational schema allows us to query the tables and obtain results like the following about current running services:


SELECT TOP (100) PERCENT
svcHost.Name         AS host,
svcHost.VirtualDirectory,
svcHost.ConnectionString,
process.MachineName    AS machine,
process.ProcessName,
process.StartTime


FROM dbo.tbl_ServiceHostInstance AS instance INNER JOIN
dbo.tbl_ServiceHost AS svcHost ON instance.HostId = svcHost.HostId LEFT OUTER JOIN
dbo.tbl_ServiceHostProcess AS process ON instance.ProcessId = process.ProcessId LEFT OUTER JOIN
dbo.tbl_ServiceHost AS hostParent ON svcHost.ParentHostId = hostParent.HostId

ORDER BY process.StartTime DESC, hostParent.Name, host

 

Sample results

host 

VirtualDirectory 

ConnectionString 

machine

ProcessName 

StartTime 

TEAM FOUNDATION 

NULL 

Data Source= hp10\SqlTfs;Initial Catalog=Tfs_Configuration;Integrated Security=True

HP10 

w3wp.exe 

2012-05-21 20:18:09.997 

DefaultCollection 

~/DefaultCollection/ 

Data Source=hp10\sqltfs;Initial Catalog=tfs_defaultcollection;Integrated Security=True 

HP10 

w3wp.exe 

2012-05-21 20:18:09.997 

Training collection 

~/Training collection/ 

Data Source=hp10\SqlTfs;Initial Catalog="Tfs_Training collection";Integrated Security=True

HP10 

w3wp.exe 

2012-05-21 20:18:09.997 

TEAM FOUNDATION 

NULL 

Data Source=hp10\SqlTfs;Initial Catalog=Tfs_Configuration;Integrated Security=True 

HP10 

TfsJobAgent.exe 

2012-05-21 06:51:37.870 

DefaultCollection 

~/DefaultCollection/ 

Data Source=hp10\sqltfs;Initial Catalog=tfs_defaultcollection;Integrated Security=True 

HP10 

TfsJobAgent.exe 

2012-05-21 06:51:37.870 

Training collection 

~/Training collection/ 

Data Source=hp10\SqlTfs;Initial Catalog="Tfs_Training collection";Integrated Security=True

HP10 

TfsJobAgent.exe 

2012-05-21 06:51:37.870 

 

Ressources and services

Again, let's follow up the following tables:

  • tbl_CatalogResourceType stores a list of resource types. Like: 'Machine', 'Infrastructure Root', 'Project Server', 'Team Foundation Project Collection Database'… etc. Here is some sample entries:

Identifier 

DisplayName 

Description 

9FB288AE-9D94-40CB-B5E7-0EFC3FE3599F 

Default location for team project portals 

By default, each team project Web site will be a sub-site of this location.

0584A4A2-475B-460E-A7AC-10C28951518F 

Machine 

A machine that exists as part of the TFS deployment. 

14F04669-6779-42D5-8975-184B93650C83 

Infrastructure Root 

The root of the catalog tree that describes the physical makeup of the TFS deployment.

1B6B5931-69F6-4C53-90A0-220B177353B7 

Team Foundation Project Collection Database 

The database that houses the information for a Team Foundation Project Collection. 

526301DE-F821-48C8-ABBD-3430DC7946D3 

Team Foundation Configuration Database

The database that houses the information for a Team Foundation Application Instance. 

289DD275-CECA-4698-8042-38D2E86FC682 

Project Server 

Project Server Information 

3DADD190-40E6-4FC1-A306-4906713C87CE 

SharePoint Web Application 

A SharePoint Web application that has been configured to support team project portals.

3C856555-8737-48B6-8B61-4B24DB7FEB15 

Test Controller 

This is a test controller type in Catalog Service. 

26338D9E-D437-44AA-91F2-55880A328B54 

Team Project Collection 

A Team Project Collection that exists within the TFS deployment.

450901B6-B528-4863-9876-5BD3927DF467 

Project Portal 

A Web site or SharePoint site that provides a portal for a team project. 

15DA1594-45F5-47D4-AE52-78F16E67EB1E 

Process Guidance 

A Web site or SharePoint library that provides process guidance for a team project.

47FA57A4-8157-4FB5-9A64-A7A4954BD284 

Team Web Access 

Team Web Access Location 

48577A4A-801E-412C-B8AE-CF7EF3529616 

Team Project 

A Team Project that exists within the TFS deployment. 

 

  • tbl_CatalogResource stores resources (each referring to one of the types in the above tbl_CatalogResourceType table. Sample entries:

 

Identifier 

ResourceType 

DisplayName 

Description 

7462A882-741B-4F91-885F-1405A22256DF 

1B6B5931-69F6-4C53-90A0-220B177353B7 

Tfs_Training collection

 

C5CD36C5-8373-4BF7-B3FA-16199DAFF106 

48577A4A-801E-412C-B8AE-CF7EF3529616 

cmmi project 

cmmi training project 

16480162-C502-4197-872A-4DDDFE49BA90 

1B6B5931-69F6-4C53-90A0-220B177353B7 

tfs_defaultcollection 

 

DCC270E7-6EC7-45BF-A827-53BBB5386606

14F04669-6779-42D5-8975-184B93650C83 

Infrastructure Root 

The root of the catalog tree that describes the physical makeup of the TFS deployment. 

2F8C7D1C-EB1F-4058-B34D-60FA2F6CA7DC 

48577A4A-801E-412C-B8AE-CF7EF3529616 

Agile project 

 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7

47FA57A4-8157-4FB5-9A64-A7A4954BD284 

Team Web Access 

 

4B812279-A7A6-4A8A-92A4-7AA208589FEB 

EB1E0B3B-FAA1-49D2-931A-FDC373682BA5 

SQLTFS 

 

F69EFD2B-51C6-461B-9E49-8089DF86C9A3 

0584A4A2-475B-460E-A7AC-10C28951518F 

hp10 

 

5242DBFC-06C8-4CAD-A27B-99212BEEE999

526301DE-F821-48C8-ABBD-3430DC7946D3 

Tfs_Configuration 

 

713FF18A-E0E8-4192-A7B9-A0900F50A5BC 

26338D9E-D437-44AA-91F2-55880A328B54 

DefaultCollection 

 

 

  • tbl_ServiceDefinition stores a list of predefined services (classes) and the web access page for each. Sample entries (among other things, you may note curly braces which are place holders for some url parameters in the RelativePath column):

 

ServiceType 

Identifier 

DisplayName 

RelativePath 

AdministrationService 

C18D6E34-68E8-40D2-A619-E7477558976E

Administration Service 

/TeamFoundation/Administration/v3.0/AdministrationService.asmx 

Annotate 

74B15E02-0AC2-414F-A9B9-30268659D3B5 

Team Web Access (Annotate) 

/web/ann.aspx 

AnnotateSourceControlItem

D271E722-C261-4BC2-B0F7-1C8A9E13F907 

Team Web Access (AnnotateSourceControlItem) 

/web/ann.aspx?pcguid={projectCollectionGuid}&path={itemPath}&cs={itemChangeset} 

CatalogService 

C2F9106F-127A-45B7-B0A3-E0AD8239A2A7 

Catalog Service 

/TeamFoundation/Administration/v3.0/CatalogService.asmx

ChangesetDetail 

D40EF625-CCA7-4E73-B9EC-86CBE1534CE0 

Team Web Access (ChangesetDetail) 

/web/cs.aspx 

CreateWorkItem 

14CD69C6-88F9-4C8C-A259-D2441D77D1AF

Team Web Access (CreateWorkItem) 

/web/wi.aspx?puri={projectUri}&wit={workItemType} 

Difference 

2B84D900-1F08-486C-9C47-0E6AF371D03C 

Team Web Access (Difference) 

/web/diff.aspx 

Eventing 

C424AE04-8C6F-4516-8B2D-238FFFCA3081 

Event Service 

/TeamFoundation/Administration/v3.0/EventService.asmx

IdentityManagementService 

3DE26348-00BE-4B82-8E4A-E5AD004CFECD 

Identity Management Service 

/TeamFoundation/Administration/v3.0/IdentityManagementService.asmx 

JobService 

DA1C0184-14FE-4E13-B7FC-6EAA07D84BE8 

TFS Background Job Service 

/TeamFoundation/Administration/v3.0/JobService.asmx 

 

  • tbl_CatalogServiceReference stores per-resource services' entries. (Resource Identifier / Service Identifier…).

 

ResourceIdentifier 

AssociationKey 

ServiceIdentifier 

ServiceType 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

ChangesetDetail 

D40EF625-CCA7-4E73-B9EC-86CBE1534CE0

ChangesetDetail 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

CreateWorkItem 

14CD69C6-88F9-4C8C-A259-D2441D77D1AF 

CreateWorkItem 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

Difference 

2B84D900-1F08-486C-9C47-0E6AF371D03C 

Difference 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7

DiffSourceControlItems 

5E91C4DA-0013-4EBB-943D-CC77F5ADB82D 

DiffSourceControlItems 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

DiffSourceControlShelvedItem 

4C81A44D-67AB-4D23-9CBE-339C9102993B 

DiffSourceControlShelvedItem 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

ExploreSourceControlPath

AC0770BC-1DD6-4B8E-A811-5A03690DF44F 

ExploreSourceControlPath 

D7121DA7-3E32-49C3-BCB1-68C83C4383B7 

Home 

0F9CED5D-89F9-4743-BAB8-FA511FF09A8C 

TSWAHome 

 

This allows us to query the services in a way similar to the following:

SELECT resType.DisplayName AS ResourceType,
svc.DisplayName AS Service,
svc.Description AS serviceDescription
FROM dbo.tbl_ServiceDefinition AS svc INNER JOIN
dbo.tbl_CatalogServiceReference AS svcRef ON svc.Identifier = svcRef.ServiceIdentifier
INNER JOIN
dbo.tbl_CatalogResource AS Res ON svcRef.ResourceIdentifier = Res.Identifier
INNER JOIN
dbo.tbl_CatalogResourceType AS resType ON Res.ResourceType = resType.Identifier

 

 

Sample results:

ResourceType

Service

serviceDescription

Team Web Access

Team Web Access (Annotate)

 

Team Web Access

Team Web Access (AnnotateSourceControlItem)

 

Team Web Access

Team Web Access (ChangesetDetail)

 

Team Web Access

Team Web Access (CreateWorkItem)

 

Team Web Access

Team Web Access (Difference)

 

Team Web Access

Team Web Access (DiffSourceControlItems)

 

Team Web Access

Team Web Access (DiffSourceControlShelvedItem)

 

Team Web Access

Team Web Access (DiffSourceControlShelvedItem)

 

Team Web Access

Team Web Access (ExploreSourceControlPath)

 

Team Project Collection

Location Service

Location Service for Visual Studio Team Foundation Server.

Team Project Collection

Location Service

Location Service for Visual Studio Team Foundation Server.

Team Foundation Server Instance

Location Service

Location Service for Visual Studio Team Foundation Server.

Team Web Access

Team Web Access (OpenWorkItem)

 

 

More about TFS meta-models in following posts!

WPF and a ComboBox dilemma (again!)

Sometime ago, I discussed a ComboBox mouse scroll issue in Silverlight. I, again, had a new problem with the ComboBox control… this time in a WPF application.

The ItemsSource update problem

In my case, I had a ComboBox whose ItemsSource was bound to a list of items which was updated dynamically, and its SelectedItem bound to one item of the list. The problem was that the ComboBox was correctly updating the SelectedItem, while the drop-down list continued to display the older list of items! ... Here is a sample illustration:

 

Figure 1: This is the first context:

 

Figure 2: The item list changed… the ComboBox correctly displays the selected item (2.476563)… which doesn’t exist at all in the items list. The drop-down list still displays the old items list!

 

Such odd situations make you feel that either there should be an error somewhere in your code… or that the CombBox itself is a control that you should reinvent yourself!

 

Check your code!

Here is my Xaml code… that really seems so ‘standard’


<ComboBox x:Name="combobox_rates"
    ItemsSource="{Binding Combinations, Mode=OneWay}"
    SelectionChanged="combobox_rates_SelectionChanged"
    Height="24"
    Width="280"
    ItemTemplate="{DynamicResource combi_list_template}"
    SelectedItem="{Binding Path=SelectedCombination}" />

According to someone advice, let-s add a IsSynchronizedWithCurrentItem=”True”:


<ComboBox x:Name="combobox_rates"
    IsSynchronizedWithCurrentItem="True"
    

Desperately, that doesn’t solve the problem!
Another advice: Bind the ItemsSource to an ObservableCollection<T> (instead of a List<T>): nothing changes…
A third one: add an UpdateSourceTrigger=PropertyChanged to the Binding… let’s just try

ItemsSource="{Binding Combinations, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"

 

The solution

Still, we didn’t try this… let’s use the IsAsync Binding attribute:

ItemsSource="{Binding Combinations, IsAsync=True, Mode=OneWay}"

Oh… that seems to work great!
Is sofware development a Science, an Art, or Craftsmanship?!

The piteous story of FBI vs. LulzSec!

Few days ago, many press articles exposed what was supposed to be spectacular action of the FBI against LulzSec.

The main ‘spectacular’ action this time was that the FBI succeeded in gaining the ‘cooperation’ of one young man who was, more or less, part of the young people's movement.

The ‘cooperation’ of this poor scared young person, lasted 10 months… from June 2010 to March 2011, where he sometimes worked ‘full nights’ for the FBI to deliver his colleagues and friends in the best (illegal) conditions!

According to the press news (relating FBI personnel declarations), the operation ended up by arresting 4 suspected persons (all over the worldJ).

Apparently not hoping for many more suspects through its new agent, the FBI decided to throw him away by revealing his identity to the press! (Not very much encouraging collaborating with those people… isn’t it?)

Well… by any simple arithmetic logic: 10 months of cooperation of such a great agent to simply have 4 suspects… that really seems pitiful.

Finally: The story seems in fact more about the recurrent failure of organizations like FBI to do their job (whatever this job may be!)

The end of Internet (browsers, and search engines at least!)

Communication is a vast and ancient field which ran through many evolution phases, experiments and research. Internet, as we know it today, is one of the outcomes of this human work.

In this story, no one technology proved eternal or ever-lasting. Cycles of evolution produced some usable and convenient forms of communication at a time. Internet seems to be just one of these.

But now, each time I look at a web page, I feel that just cannot last much longer (at least I hope so:)): these elastic regions, shapeless tables, unexpected fonts changes, images and colors… hazardous page reloads and other ‘partial updates’ (sometimes even more annoying)… the whole mess of plug-ins, add-ins and other artifacts…

That really doesn’t seem to be an ever-lasting model!

Searching for something on Internet is even worse. Just go search for the word ‘sequence’ and you will find yourself with a non-classified mess of subjects ranging from cinema to molecular biology!

Looking for a solution of a problem?... you may find many, often ten or fifteen years old… which rarely relates to you current question.

To keep some ‘Lasting Value’ for old archived articles, many publishers no more mention the articles’ publication date… and search engines don’t help much in finding out a time-classification of a search result. All these ‘partners’ (publishers / search engines) are happy with this. As long as the consumer (you and I) don’t complain, the business just continue to run with minimal costs!

The appropriateness between what is needed and what is offered seems to be near a break-point.

In parallel, the great rise of technologies like web services and the wide range of their implementations may just allow us to hope for something new to emerge: new stable and appealing content explorers / new relevant and coherent search engines.

ShrekPoint

shrek With a little refactoring, this presentation can be quite good for SharePoint 2010:

“In this fully computer-animated fantasy from the creators of Antz, we follow the travails of Shrek […], a green ogre who enjoys a life of solitude. Living in a faraway swamp, he is suddenly invaded by a hoard of fairy tale characters, such as the Big Bad Wolf, the Three Little Pigs, and Three Blind Mice, all refugees of their homes who have been shunned by the evil Lord Farquaad […]. They want to save their homes from ruin, and enlist the help of Shrek, who is in the same situation…”

 

“While simultaneously embracing and subverting fairy tales, the irreverent Shrek also manages to tweak Disney's nose, provide a moral message to children, and offer viewers a funny, fast-paced ride.”

 

Back to earth: DBNull and ConetxtMenuStrip target TreeView node

 

It is time now to set concepts aside for some more practical problems!

Last days, through the work on two different projects, I encountered DBNull twice, and faced a funny problem about locating the target TreeNode of a contextual menu!

Let us start by the first one:

DBNull in Silverlight and Windows Forms

I encountered a DBNull problem two times (in three days… that seems a bit much). The first time was in the context of a WCF service intended to feed a Silverlight application, and the second was in the context of a GridView control in a Windows Forms application.
For your information, DBNull is a .NET Type defined in namespace System (mscorlib.dll).

The first issue emerged with what appeared to be a communication problem between a Silverlight application and one related WCF service. After some research, DBNull was reported to be an unknown Type in XML serialization. The service was transmitting data read through a SQL Server database… We had a Cell class. Its Data member was an object.
A bit more research made it visible that the following code as the source of the annoyance:

cell.Data = data_reader.GetValue(cell_index)

 

In fact, when the field at cell_index was null, data_reader.GetValue() returned DBNull. Which was assigned as the cell’s Data. Serialized by WCF, DBNull was not recognized by the receiving Silverlight application.

Though the time needed to discover the source of the problem was quite long, the solution was quite simple:

 

cell.Data = data_reader.IsDBNull(cell_index)

                  ? null :data_reader.GetValue(cell_index)

// Which clearly means:

if(data_reader.IsDBNull(cell_index))

    cell.Data = null;

else

    cell.Data = data_reader.GetValue(cell_index)

Now that the cell content is null, everything goes right (because null is a recognize Type).
It will be a great day when DBNull (which implements the ISerializable Interface) will simply be serialized as null… let us just wait.

Yet another DBNull problem!

Once the Silverlight DBNull problem solved… precisely: the next day J, I just found myself again confronted by another DBNull. This time in a Windows Forms application.
In this new case, I had a DataGridView control which was filled using a DataTable and I wanted to programmatically add a row to those displayed in the DataGridView control.
Obtaining the row’s data was simple (calling a web service or by directly querying a database).
The task was then to add the obtained data as a new row of the DataTable used as the source of the control. The problem was again related to the cells containing null values in the new added row.

In fact, if you assign the row’s cells data through a DataRow object you may not have a particular issue. Issues appear when you try to assign an object’s properties values to the row cells.

In this particular case, we had an object with some properties of nullable types: for instance int?  parent_id. The code below generated an error:

DataRow row = table.NewRow()

row["parent_id"] = obj.parent_id;  // an error here when obj.parent_id == null

Some solutions are proposed in several forums. They mainly propose to handle some special events of the DataGridView (like DataError event) and/or play with custom interpretation of DBNull…
The solution I used seems more simple. It is based on the fact that when the row was created (using table.NewRow() method) it contained all required cells… each of which, a priori, filled with something (a sort of ‘null’ thing… we don’t really care about its type). So, we simply may assign cell values only if the data to be assigned is NOT null:

DataRow row = table.NewRow()

if( obj.parent_id != null)

       row["parent_id"] = obj.parent_id;

That seems to work!

Contextual menus… yes! but where is the target node?

TreeView control is a nice and useful control to show many data domains.
One nice and efficient thing of TreeView control is that it allows the developer to handle many aspects of tree nodes by their level in the tree hierarchy. You can for instance choose the icon of items according to their nest level in the tree hierarchy
Among the customizations you can do is to choose a specific contextual menu for each hierarchy level… very cool and simple to do.
When the user right clicks a node in the tree, he or she would see the assigned contextual menu and be able to execute operations in relation to the type of the node.
The thing is, when a menu is clicked, you developer should find out which node was selected when this menu was clicked… Curiously, this is not as simple as we may expect.

I naively thought, a contextual menu object will contain some relevant information about its Target object (in our case: the target Node)… unfortunately this was not true!
So, you simply find yourself with a command to execute (the menu clicked)… but don’t know on which object of the tree should you execute this command!
Few solutions are proposed to solve this problem, and none, of what I read, seemed sustainable.
Here again, we should ‘reinvent the wheel’…

Reinventing the contextual wheel!

The problem seems to be: “Locating the target tree node”. The problem’s definition starts by “Locate”… so let us think “location”.
I first started by trying to locate the mouse cursor at the moment of the click event (using MousePosition which returns the point of the current mouse position in screen coordinates)… but that seemed random, not always related to the node position (and also quite difficult to debugJ).
The next step was to think “location of controls”.
In fact, a contextual menu is a control and as such, it should have a location… hopefully relative to its parent control (which is the TreeView).
Our Click event is received from a contextual menu item (ContextMenuStrip object) which is located into a parent control (the contextual menu box), itself is a child control of the TreeView control containing the node.
The following figure illustrates this disposition 

 

The Owner property of the menu strip contains its parent menu control information. Through this information, we are able to obtain the location of the menu box, and thus, the location  of the first menu strip relative to the TreeView control. With some more simple arithmetic, we can finally locate the right-clicked node (the target node) using the TreeView control GetNodeAt(Point point) method :

 

 

static TreeNode LocateContextMenuTargetNode(

             TreeView            tree_view,

             ToolStripMenuItem   menu_item)

{

       // check entries

       if( tree_view == null || menu_item == null || menu_item.Owner == null)

             return null;

 

       ToolStrip           menu  = menu_item.Owner;

       // top most menu item

       ToolStripMenuItem   first = (ToolStripMenuItem) menu.Items[0];

 

       // obtain the enclosing rectangle of the menu box

       Rectangle           menu_rect   = menu.RectangleToScreen(menu.ClientRectangle);

       // obtain the rectangle relative to the TreeView control

       Rectangle           tv_rect     = tree_view.RectangleToClient(menu_rect);

       // obtain the optimal point that corresponds to the right-clicked node

       Point               point       = newPoint(

                                    first.ContentRectangle.X + tv_rect.X,

                                    first.ContentRectangle.Y + tv_rect.Y);

 

       // finally, get the right-clicked node

       return tree_view.GetNodeAt(point);

 

}

 

 That works fine for contextual menus with few elements and in a ‘normal’ screen resolution.
If the contextual menu contains many items, the first item may be quite far away from the target node!...So, what?
Let us look for a more sustainable way to locate our item… we may again, rethink ‘mouse location’!

In this solution, we will keep track of the current ‘right-clicked node by responding to the MouseDown event of the TreeView.


TreeNode     m_context_menu_target_node; 

void treeView1_MouseDown(object sender, MouseEventArgs e)
{
    // if this is not a right-click: do nothing
    if (e.Button != System.Windows.Forms.MouseButtons.Right)
    {
        m_context_menu_target_node = null;
        return;
    }
 
    Point point = e.Location;

    m_context_menu_target_node = treeView1.GetNodeAt(point);
}

 

Now, when a contextual menu is clicked, we can first see if the target node is not null… execute the command and reset the target node to null (until the next time): 

 
       TreeNode node = m_context_menu_target_node;

       if (node == null)
             return;

       // reset the target node to null
       m_context_menu_target_node = null; 

       // execute the command on the node