giovedì 17 febbraio 2011

TFS2010 Object Model: TeamProjectPicker

L’object model di TFS 2010 mette a disposizione una finestra per permettere ai nostri utenti di selezionare un server TFS, una project collection o un progetto.

La finestra è implementata dalla classe TeamProjectPicker che si trova nel namespace Microsoft.TeamFoundation.Client (assembly Microsoft.TeamFoundation.Client.dll).

TeamProjectPicker permette una certa versatilità perché può servire per selezionare una project collection, un progetto o una serie di progetti.

Prima di vedere come si può ottenere ciò, vediamo come è strutturata la classe.

La classe ha tre costruttori che permettono di gestire la possibilità di scegliere cosa è possibile selezionare e quale provider di credenziali utilizzare.

In particolare, il costruttore più completo è il seguente:

  1. Public Sub New(ByVal mode As TeamProjectPickerMode,
  2.                 ByVal disableCollectionChange As Boolean,
  3.                 ByVal credentialsProvider As ICredentialsProvider)

L’argomento mode, di tipo TeamProjectPickerMode, permette di selezionare la modalità di selezione e può assumere i seguenti valori:

  • NoProject : è possibile selezionare server e project collection;
  • SingleProject : è possibile selezionare un solo progetto
  • MultiProject : si possono selezionare più progetti.

La seguente figura mostra come si presentano le differenti opzioni:

SNAGHTML11981afb

L’argomento disableCollectionChange permette di decidere se deve essere selezionata automaticamente la collezione di default (false) senza che possa essere modificata dall’utente oppure no (true).

Infine, l’argomento credentialsProvider permette di impostare il provider di credenziali da utilizzare nel caso in cui la connessione a TFS non disponga di credenziali valide. Il provider da noi impostato verrà richiamato nel momento in cui , a causa della mancanza di credenziali, l’utente clicca sul link “Use different credentials”.

La GUI, una volta istanziata, può essere personalizzata (a dire il vero non molto) utilizzando le seguenti proprietà:

  • AcceptButtonText: permette di impostare il testo che appare sul bottone di selezione;
  • HelpTopic: permette di impostare l’argomento della guida relativo al dialog;
  • Text: permette di impostare la caption del controllo.

e può essere mostrata all’utente con il metodo ShowDialog (come un usuale dialog windows forms).

La classe espone, infine, le due proprietà per recuperare la collection selezionata dall’utente (proprietà SelectedTeamProjectCollection di tipo TfsTeamProjectCollection) e i progetti (SelectedProjects di tipo ProjectInfo).

Il seguente pezzo di codice visualizza la dialog di selezione in modalità multi project e recupera i valori selezionati dall’utente:

  1. Dim pp = New TeamProjectPicker(TeamProjectPickerMode.MultiProject,
  2.                                False,
  3.                                New UICredentialsProvider())
  4. If pp.ShowDialog() = Windows.Forms.DialogResult.OK Then
  5.     Dim collection = pp.SelectedTeamProjectCollection
  6.     Dim projects = pp.SelectedProjects
  7.     '
  8.     '   Utilizzo di collection e projects
  9.     '
  10. End If

Prima di concludere il post vorrei segnalare il metodo SetDefaultSelectionProvider il cui scopo è quello di permettere di modificare la logica con cui il TeamProjectPicker recupera il server, la collezione e i progetti di default.

L’oggetto previsto come argomento del metodo è una qualsiasi classe che implementa l’interfaccia ITeamProjectPickerDefaultSelectionProvider. L’interfaccia prevede i seguenti metodi:

  • GetDefaultCollectionId : restituisce il GUID della collection di default del server il cui Uri è passto per argomento;
  • GetDefaultProjects : restituisce l’elenco degli Uri dei progetti relativi alla collection il cui Guid è passato per argomento;
  • GetDefaultServerUri : Restituisce l’Uri del server di default.

Questo ci permette di personalizzare la logica con cui il picker seleziona e propone i progetti all’utente.

Per concludere, il picker è un oggetto Windows Form, quindi è necessario referenziare l’assembly System.Windows.Forms.

 

mercoledì 16 febbraio 2011

101 Async samples

Vi segnalo un post di Alessandro Del Sole in cui viene riportata la notizia che sono disponibili, sul sito di Lucian Wischik un insieme di esempi sulle funzionalità di Async attualmente in CTP.

L’indirizzo del sito è il seguente: AsyncSamplesSilverlight

 

Tag di Technorati: ,

giovedì 10 febbraio 2011

VB.NET: recuperiamo gli assembly referenziati nella nostra applicazione

La classe Assembly prevede il metodo GetReferencedAssembly() per recuperare l’elenco degli AssemblyName ralativi agli assembly referenziati da un determinato assembly.

Il problema è che se abbiamo una struttura con più dll referenziate a catena, il metodo restituisce solo il primo livello della stessa catena.

Supponiamo di avere la seguente struttura:

image

ovvero il progetto AssemblyExtension referenzia la dll AssemblyExtensionLIB1 che, a sua volta, referenzia la AssemblyExtensionLIB2.

In questo caso, il metodo GetReferencedAssembly(), applicato sull’assembly AssemblyExtension, restituisce il seguente elenco:

SNAGHTML4498867

Come si può vedere non c’è traccia della AssemblyExtensionLIB2.

Il seguente metodo di estensione provvede ad eseguire un algoritmo ricorsivo per recuperare una lista di AssemblyName contenente tutte le reference dell’assembly:

  1. Imports System.Runtime.CompilerServices
  2. Imports System.Reflection
  3.  
  4. Module AssemblyExtension
  5.  
  6.     <Extension()> _
  7.     Public Sub GetAllReferenceAssemblies(ByVal sourceAssembly As Assembly,
  8.                                          ByVal allowGacAssembly As Boolean,
  9.                                          ByVal list As ICollection(Of AssemblyName))
  10.         If sourceAssembly Is Nothing Then Throw New ArgumentNullException("Source Assembly")
  11.         If list Is Nothing Then Throw New ArgumentNullException("Destination List")
  12.         list.Add(sourceAssembly.GetName())
  13.         If allowGacAssembly OrElse Not sourceAssembly.GlobalAssemblyCache Then
  14.             Dim assemblies = sourceAssembly.GetReferencedAssemblies()
  15.             For Each assemblyName In assemblies
  16.                 Dim query = From a In list _
  17.                             Where a.FullName = assemblyName.FullName _
  18.                             Select a
  19.                 If query.Count = 0 Then
  20.                     Dim assembly As Assembly = assembly.Load(assemblyName.FullName)
  21.                     assembly.GetAllReferenceAssemblies(allowGacAssembly, list)
  22.                 End If
  23.             Next
  24.         End If
  25.     End Sub
  26. End Module

Il metodo di estensione è applicabile su un qualsiasi assembli e i parametri sono:

  • allowGacAssembly: indica se eseguire la ricerca delle referenze all’interno delle dll contenute nella GAC;
  • list: è la lista che conterrà gli AssemblyName risultato della ricerca.

Se nel progetto precedente scriviamo:

  1.  
  2. Dim list = New List(Of AssemblyName)
  3. Assembly.GetEntryAssembly().GetAllReferenceAssemblies(True, list)

Otteniamo:

SNAGHTML46ed88a

Mentre se impostiamo allowGacAssembly=false:

SNAGHTML46fb735

Attenzione: il metodo GetReferencedAssembly restituisce gli assembly effettivamente referenziati (cioè quelli per i quali c’è almeno un tipo utilizzato) e non quelli inseriti nelle referenze di Visual Studio.

 

lunedì 7 febbraio 2011

TFS2010 Object Model: gestiamo le project collections

In questo post vorrei porre l’attenzione su come utilizzare l’object model di TFS per gestire le Project Collection, cioè come utilizzare  da codice i servizi messi a disposizione dalla piattaforma TFS per creare, eseguire il detach o l’attach delle project collections del nostro server.

L’object model di TFS mette a disposizione l’interfaccia ITeamProjectCollectionService implementata da quelle classi che hanno la capacità di gestire le project collections.

Per prima cosa recuperiamo questa classe, utilizzando il metodo GetService (ereditato dalla classe TfsConnection) della TfsConfigurationServer:

  1. Public Sub GetTeamProjectService()
  2.     tpcService = CType(tfs.GetService(Of ITeamProjectCollectionService)(), ITeamProjectCollectionService)
  3.     Console.WriteLine("ITeamProjectCollectionService ricavato!")
  4. End Sub

dove tfs è un’istanza di TfsConfigurationServer ricavata tramite il seguente pezzo di codice:

  1. Public Sub CreateTFSInstance(ByVal server As String)
  2.     Try
  3.         tfs = TfsConfigurationServerFactory.GetConfigurationServer(New Uri(server),
  4.                                                                  New UICredentialsProvider())
  5.         tfs.EnsureAuthenticated()
  6.         Console.WriteLine("Instanza di TFS creata!")
  7.     Catch ex As Exception
  8.         Console.WriteLine("Errore nella connessione a tfs: {0}", ex.Message)
  9.     End Try
  10. End Sub

Una volta recuperata l’istanza del servizio che implementa ITeamProjectCollectionService abbiamo a disposizione una serie di metodi che ci permettono di “giocare” col le project collections.

Creare una collezione di progetti

I metodi di gestione delle collezioni di progetti sono, generalmente, metodi la cui esecuzione può anche durare molto ed è per questo che viene introdotto il concetto di ServicingJobDetail e di accodamento delle operazioni.

Di fatto il metodo che possiamo utilizzare per la creazione di una project collection è il metodo QueueCreateCollection che “accoda” l’operazione di creazione della collection e restituisce un oggetto di tipo ServicingJobDetail che possiamo interpellare per avere conoscenza delleo stato di avenzamento dell’operazione stessa.

Un esempio di codice per la creazione di una collezione è il seguente:

  1. Dim job = tpcService.QueueCreateCollection(collName,
  2.                                            String.Format("{0} - creata da codice", collName),
  3.                                            False,
  4.                                            String.Format("~/{0}", collName),
  5.                                            Microsoft.TeamFoundation.Framework.Common.TeamFoundationServiceHostStatus.Started,
  6.                                            Nothing)
  7.  
  8. Dim tpcoll = tpcService.WaitForCollectionServicingToComplete(job)

La versione del metodo QueueCreateCollection che stiamo utilizzando prevede i seguenti argomenti:

  • name : è il nome che intendiamo dare alla nostra collection;
  • description : è la descrizione della collection;
  • isDefault : indica se la collection che stiamo creando è quella di default o meno;
  • virtualDirectory : è la virtual directory in cui posizionare la collezione. nel nostro caso specifico utilizziamo il nome della collection preceduto da “~/”;
  • state : indica lo stato in cui la collezione deve essere creata. Nel nostro caso lo stato è Started;
  • servicingTokens : si tratta di un IDictionary(Of String,String) che può contenere parametri accessori utili alla crazione della collezione.

Nel momento in cui usciamo dal metodo precedente, possiamo metterci in attesa del completamento dell’operazione di creazione della collezione grazie al metodo WaitForCollectionServicingToComplete. Quest’ultimo terminerà nel momento in cui l’operazione sarà conclusa e restituirà un oggetto di classe TeamProjectCollection con le informazioni sulla collectionì stessa.

E’ interessante osservare l’operazione di creazione della collection utilizzando la console di amministrazione di TFS:

image

Detach di una project collection

Un’altra funzionalità esposta dall’interfaccia che stiamo esaminando è quella del detach di una project collection.

Per eseguire il detach di una collezione di progetti è necessario avere a disposizione o l’istanza della TeamProjectCollection o il Guid della collezione e richiamare l’overload opportuno del metodo QueueDetachCollection sull’interfaccia ITeamProjectCollectionService.

Il seguente pezzo di codice mostra come recuperare una TeamProjectCollection a partire dal nome della collezione di progetti ed eseguire il detach:

  1. Dim collection = (From c In tpcService.GetCollections().ToList()
  2.                      Where c.Name = collName
  3.                      Select c).FirstOrDefault()
  4. If collection IsNot Nothing Then
  5.     Console.WriteLine("Detach collezione iniziato!")
  6.     Try
  7.         Dim connectionString As String = Nothing
  8.         Dim job = tpcService.QueueDetachCollection(collection,
  9.                                                    Nothing,
  10.                                                    "Sto fermando la collection!!",
  11.                                                    connectionString)
  12.  
  13.         Dim tpcoll = tpcService.WaitForCollectionServicingToComplete(job)
  14.         Console.Write("Detach Collezione Ok: connectionstring={0}", connectionString)
  15.     Catch ex As Exception
  16.         Console.Write("Errore nel detach della collection : {0}", ex.Message)
  17.     End Try
  18.     Console.WriteLine()
  19. Else
  20.     Console.WriteLine("La collezione non esiste!")
  21. End If

Anche in questo caso, il metodo QueueDetachCollection restituisce un oggetto di classe ServicingJobDetail grazie al quale siamo in grado di comprendere quando l’operazione ha termine.

I parametri utilizzati nella chiamata al metodo di detach sono:

  • teamProjectCollection : è l’istanza di TeamProjectCollection che identifica la collezione da sganciare;
  • servicingTokens : si tratta di un IDictionary(Of String,String) che può contenere parametri accessori utili al detach della collezione;
  • collectionStoppedMessage : è il messaggio di avvertimento che appare, ad esempio, nella console di amministrazione di TFS durante l’operazione di detach;
  • detachedConnectionString : è un valore restituito al chiamante e contenente la stringa di connessione del database “sganciato” da TFS che può essere, eventualmente, riagganciato in un altro TFS.

Attach di una project collection

La funzione inversa di una detach per una project collection è l’attach che permette di agganciare un databese (contenente una collezione di progettI) al server TFS.

Il metodo utilizzato per questa operazione è QueueAttachCollection che prevede un paio di overload il piuù semplice dei quali ha tre parametri:

  • databaseConnectionString : è la stringa di connessione del database contenente la collezione di progetti;
  • servicingToken : si tratta di un IDictionary(Of String,String) che può contenere parametri accessori utili al detach della collezione;
  • cloneCollection : indica se eseguire o meno un clone della collezione.

Il seguente pezzo di codice mostra come si possa eseguire l’attach di una collezione data la connectionString:

  1. Dim job = tpcService.QueueAttachCollection(databaseConnectionString,
  2.                                            Nothing,
  3.                                            True)
  4.  
  5. Dim tpcoll = tpcService.WaitForCollectionServicingToComplete(job)

Come visto in precedenza possiamo sfruttare il job restituito dal metodo di attach  per capire quando il lavoro è concluso.

Tra i metodi messi a disposizione dall’interfaccia vista in questo post abbiamo anche il metodo che può essere utilizzato per eseguire l’attach di un database di TFS precedente alla versione 2010.

A compendio di questo post vorrei allegare un esempio di console sviluppata con Visual Studio 2010 che permette di integrare le funzioni viste.

La console prevede che il nome del server TFS, nella forma http://server:8080/tfs , venga passato come argomento.