Continuo la serie di post che ha riscosso un
inatteso successo tornando a parlare di Monad e dei suoi provider. Come promesso
la precedente puntata ecco finalmente un po' di codice che spiega come
implementare un provider che risponda ad un device fittizio che chiameremo sql:\
ottenendo il risultato di consentirci di navigare lo schema del database come se
fosse un filesystem.
Per chiarire l'obbiettivo che ci poniamo
innanzitutto proviamo a spiegare in che modo avverrà la navigazione all'interno
di SqlServer. Se pensiamo ad un database server Sql, possiamo individuare una
sorta di gerarchia riconducibile ad un path analogo a quello del filesystem. Al
primo livello avremo il server, poi il database, poi ancora le tabelle ed infine
i campi che compongono una singola tabella. La scelta in effetti è arbitraria in
quanto è evidente che si sarebbe potuto scegliere un diverso modo di ordinare
gli oggetti, ma allo scopo del post, quanto appena descritto è più che
sufficiente.
Quindi scrivendo il seguente path dovremmo poter
raggiungere i campi della tabella Employees nel database Northwind del server
locale:
sql:\(local)\Northwind\Employees
Per ottenere questo risultato il primo passo da
compiere è quello di creare una classe, che chiameremo SqlCmdletProvider che
eredita da NavigationCmdletProvider. Questa classe dovrà inoltre essere decorata
dall'attributo CmdletProviderAttibute oltre naturalmente a implementare l'unico
metodo astratto di tale classe. Ecco un breve spezzone di codice:
using System;
using System.Management.Automation;
using System.Management.Automation.Provider;
[CmdletProvider("SqlCmdletProvider", ProviderCapabilities.None)]
public class SqlCmdletProvider : NavigationCmdletProvider
{
protected override bool IsValidPath(string path)
{
return true;
}
}
Dovremo naturalmente ricordarci di importare i namespace di Monad,
e di referenziare i relativi assembly che troveremo nella directory di
installazione. Ora il nostro provider compila, ma anche ammettendo di
installarlo scopriremo che non è in grado di compiere alcuna azione. In
particolare manca la possibilità di "agganciarsi" al drive fittizio sql: come
richiesto dai requisiti che abbiamo espresso poco fa. E' qui che entrano in
gioco la serie di metodi virtuali, esposti dalla classe
NavigationCmdletProvider, facendo l'override dei quali si potranno iniziare ad
ottenere i comportamenti richiesti. Per poter assegnare il drive sql: al nostro
provider dovremo sovrascrivere il metodo InitializeDefaultDrives() il quale
dovrà tornare una collection dei drive cui il nostro provider fa capo; Eccone
l'implementazione:
protected override Collection<System.Management.Automation.DriveInfo> InitializeDefaultDrives()
{
Collection<System.Management.Automation.DriveInfo> drives =
new Collection<System.Management.Automation.DriveInfo();
drives.Add(
new System.Management.Automation.DriveInfo(
"sql",
this.ProviderInfo,
"\\",
"Sql MSH Navigation Provider",
null));
return (drives);
}
Come già detto questo metodo informerà il runtme di quali drive
fanno capo al nostro provider. Una volta installato il provider potremmo
assicurarci che esso risponda correttamente lanciando la cmdlet get-provider per
ottenere quelo che segue:
MSH C:\> get-provider
Name Capabilities Drives
---- ------------ ------
SqlCmdletProvider None {sql}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess {C, D, E, F, G}
Function ShouldProcess {Function}
Registry ShouldProcess {HKLM, HKCU}
Variable ShouldProcess {Variable}
Certificate ShouldProcess {cert}
Tra i provider installati è elencato anche il nostro e se proviamo
a scrivere "cd sql:\" il nostro provider accetterà il percorso specificato così
come qualunque altro dato che nel metodo IsValiPath() abbiamo ritornato
semplicemente true.
Ora, prima di chiudere il post e lasciarvi per la prossima puntata, è
opportuno che spieghi come si fa ad installare il provider in Monad. In effetti
questa è la parte se volete più oscura alla qualeho trovato una sola soluzione,
ma sospetto che ve ne siano altre che mi sono bellamente sfuggite. Quello
che ho fatto io è stato di compilare una nuova shell includendo l'assembly
del mio provider ottenendo così un nuovo eseguibile compatto che supporta
anche il mio provider; Ecco la linea di comando MSH che ho utilizzato
per lo scopo: