Creazione di un risolutore personalizzato

In questo argomento viene illustrato un esempio di estensione della classe XmlUrlResolver per memorizzare un flusso nella cache sul disco rigido. Tutte le chiamate effettuate a GetEntity fanno in modo che il flusso restituito dal metodo GetEntity venga salvato nella directory c:\temp. Questa funzione risulta particolarmente utile quando la risoluzione delle risorse avviene su una rete. L'inserimento nella cache sostituisce il metodo GetEntity.

Poiché la classe XmlResolver personalizzata utilizza XmlUrlResolver anziché XmlSecureResolver disponibile in .NET Framework versione 1.1, non viene eseguito alcun controllo su più domini quando si verifica il reindirizzamento. Pertanto qualsiasi URI incorporato che implichi il reindirizzamento a causa di elementi include e import, di riferimenti a entità esterne e così via, leggerà i dati senza verificare la protezione dei dati stessi o del sito. Questo accade perché, quando si verifica il reindirizzamento, non vengono passate le credenziali e pertanto l'applicazione potrebbe risultare danneggiata da dati provenienti da un sito non protetto o anonimo.

Nell'esempio di codice che segue le informazioni relative agli URI risolti vengono memorizzate in una tabella statica Hashtable, denominata myHash. Quando un URI viene risolto per la prima volta, il flusso viene memorizzato in un file e viene restituito un flusso che rappresenta il file. Viene inoltre effettuata un'immissione nella Hashtable utilizzando l'URI come chiave, con il nome del file come valore. Ai tentativi successivi di risoluzione dell'URI, viene consultata la Hashtable e viene utilizzato il flusso attualmente memorizzato nella cache sul disco rigido. Se in diversi processi vengono eseguite più istanze di questa classe, sarà necessario codice aggiuntivo per assicurare che i nomi di file siano univoci. Nell'esempio di codice che segue, si presuppone l'esistenza della cartella c:\resolver_cache. Nell'esempio seguente viene illustrato il codice completo della classe.

Class CustomResolver
Inherits XmlUrlResolver
Public Shared myHash As New Hashtable()

Public Sub New()
End Sub 'New
      
Public Overrides Function GetEntity(absoluteUri As Uri, role As String, ofObjectToReturn As Type) As Object
If myHash.ContainsKey(absoluteUri) Then
    Console.Out.WriteLine(("Reading resource" + absoluteUri.ToString() + " from cached stream"))
    'Returns the cached stream.
    Return New FileStream(CType(myHash(absoluteUri), [String]), FileMode.Open, FileAccess.Read, FileShare.Read)
Else
    ' The filename that the cached stream is stored to.
    Dim filename As [String] = "c:\resolver_cache\resolve" + CStr(myHash.Count) + ".txt"
    Console.Out.WriteLine(filename)
    ' Create a new stream representing the file to be written to,
    ' and write the stream cache from the external
    ' location to the file.
    Dim fStream As New FileStream(filename, FileMode.Create)
    Dim sRead As New StreamReader(CType(MyBase.GetEntity(absoluteUri, role, ofObjectToReturn), Stream))
    Dim sWrite As New StreamWriter(fStream)
    sWrite.Write(sRead.ReadToEnd())
    ' Add the information about the cached Uri to the hashtable.
    myHash.Add(absoluteUri, filename)
    ' Close any open streams.
    sWrite.Close()
    sRead.Close()
    Return New FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read)
    End If
  End Function 'GetEntity
End Class 'CustomResolver
[C#]
class CustomResolver : XmlUrlResolver
{
public static Hashtable myHash=new Hashtable();
public CustomResolver()
{
}
override public object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
{
if(myHash.ContainsKey(absoluteUri))
    {
    Console.Out.WriteLine("Reading resource"+absoluteUri.ToString()+" from cached stream");
    // Returns the cached stream.
    return new FileStream((String)myHash[absoluteUri],FileMode.Open,FileAccess.Read,FileShare.Read);
    }
else
    {
    // The filename that the cached stream will be stored to.
    String filename = "c:\\resolver_cache\\resolve"+myHash.Count+ ".txt";
    Console.Out.WriteLine(filename);
    // Create a new stream representing the file to be written to,
    // and write the stream cache the stream
    // from the external location to the file.
    FileStream fStream = new FileStream(filename, FileMode.Create);
    StreamReader sRead = new StreamReader((Stream)base.GetEntity(absoluteUri, role, ofObjectToReturn));
    StreamWriter sWrite = new StreamWriter(fStream);
    sWrite.Write(sRead.ReadToEnd());
    // Add the information about the cached Uri to the hashtable.
    myHash.Add(absoluteUri,filename);
    // Close any open streams.
    sWrite.Close();
    sRead.Close();
    return new FileStream(filename, FileMode.Open,FileAccess.Read,FileShare.Read); 
    }
  }
}

Per creare un risolutore personalizzato per la risoluzione di risorse per cui vengono utilizzati protocolli diversi da http://, https:// ofile://, è necessario ignorare il metodo GetEntity per gestire la connessione.

Per utilizzare un URI diverso come baseUri, è necessario ignorare il metodo ResolveUri così da utilizzare un baseURI fisso, indipendentemente dai parametri passati nel metodo. Ad esempio, se si vuole fare in modo che tutti gli URI vengano risolti utilizzando un determinato baseURI, nell'esempio seguente viene illustrato come creare una nuova proprietà BaseURI.

Dim baseUri As Uri

Public Property BaseURI() As Uri
   Get
      Return baseUri
   End Get
   Set
      baseUri = value
   End Set
End Property
[C#]
Uri _baseUri;
public Uri BaseURI
{
    get{ return _baseUri;}
    set{ _baseUri = value;}
   }

Grazie a questa proprietà è possibile ignorare la proprietà ResolveUri nel modo seguente:

Public Overrides Function ResolveUri(baseUri As Uri, relativeUri As [String]) As Uri
   Return MyBase.ResolveUri(BaseURI, relativeUri)
End Function 'ResolveUri
[C#]
public override Uri ResolveUri(Uri baseUri, String relativeUri)
    {
        return base.ResolveUri(BaseURI,relativeUri);
    }

Vedere anche

Risoluzione di risorse XML esterne specificate da un URI | Risoluzione delle risorse mediante XmlResolver | Implementazione delle credenziali di autenticazione in XmlResolver quando si esegue la lettura da un file