Oggetti remotizzabili

Si tratta di oggetti che funzionano perfettamente in un ambiente ampiamente distribuito. Esistono due tipi principali di oggetti remotizzabili:

  • Oggetti con marshalling per valore, che vengono copiati e passati all'esterno del dominio applicazione.
  • Oggetti MBR, per i quali viene creato un proxy utilizzato dal client per accedere all'oggetto in modalità remota.

Oggetti con marshalling per valore

Gli oggetti con marshalling per valore (MBV, Marshal-by-value) dichiarano le proprie regole di serializzazione, mediante l'implementazione di ISerializable per implementare la propria serializzazione o mediante la decorazione con SerializableAttribute che comunica al sistema di serializzare l'oggetto automaticamente, ma non estendono MarshalByRefObject. Il sistema di comunicazione remota crea una copia completa di questi oggetti e la passa al dominio applicazione che effettua la chiamata. Una volta che la copia si trova nel dominio applicazione del chiamante, le chiamate vengono indirizzate direttamente a quella copia. Inoltre, gli oggetti MBV passati come argomenti vengono passati anche per valore. Oltre alla dichiarazione dell'attributo SerializableAttribute o all'implementazione di ISerializable, non occorre eseguire altre operazioni per far sì che le istanze della classe vengano passate per valore oltre i limiti di applicazione o contesto.

Nota   A partire dalla versione 1.1 di .NET Framework, nell'infrastruttura remota non vengono deserializzati automaticamente alcuni tipi nel server. Se in uno specifico scenario si verifica tale situazione, affinché il server sia in grado di deserializzare e utilizzare l'oggetto MBV, è necessario impostare il livello di deserializzazione del server su Full. Per informazioni dettagliate, vedere Deserializzazione automatica in .NET Remoting.

È opportuno utilizzare gli oggetti MBV quando, per ragioni di prestazioni o elaborazione, è preferibile spostare lo stato completo dell'oggetto e qualsiasi funzionalità eseguibile nel dominio applicazione di destinazione. In molti scenari, questa soluzione riduce i lunghi percorsi di andata e ritorno oltre i limiti di rete, processi e domini applicazione, percorsi che richiedono un uso intenso delle risorse. Gli oggetti MBV vengono anche utilizzati direttamente dall'interno del dominio applicazione originale dell'oggetto. In questo caso, poiché non viene effettuato il marshalling, non vengono create copie e l'accesso è estremamente efficiente.

D'altra parte, se gli oggetti pubblicati sono molto grandi, il passaggio di una copia intera su una rete occupata può rivelarsi una scelta errata. Inoltre, le modifiche apportate allo stato dell'oggetto copiato non vengono mai comunicate all'oggetto di origine nel dominio applicazione originale. A un livello astratto, questo scenario è simile a quello di una pagina HTML statica richiesta da un browser client. Il file viene copiato, scritto in un flusso, inviato, quindi dimenticato dal server. Qualsiasi richiesta successiva è semplicemente una richiesta di un'altra copia.

Nel sistema di comunicazione remota vengono ampiamente utilizzati gli oggetti serializzabili. Un riferimento a un oggetto in un altro dominio applicazione, rappresentato nel sistema di comunicazione remota dalla classe ObjRef, è esso stesso serializzabile ed è possibile copiarlo esattamente e inviarne la copia a una richiesta. Lo stesso vale per gli oggetti messaggio che implementano IMessage, poiché si tratta di contenitori generici di informazioni sulle chiamate e di qualsiasi altro riferimento necessario agli oggetti. Gli oggetti che trasferiscono semplicemente i dati, inoltre, sono spesso serializzabili. DataSet, ad esempio, estende MarshalByValueComponent, che implementa ISerializable.

Eccezioni remote definite dall'utente

Le eccezioni definite dal sistema sono tutti tipi con marshalling per valore, da cui viene implementata l'interfaccia ISerializable. Se generate da un oggetto remoto, verranno copiate automaticamente nel chiamante purché le configurazioni remote lo consentano. A partire dalla versione 1.1 di .NET Framework, l'elemento <customErrors> deve essere impostato su off per attivare il passaggio delle eccezioni al chiamante.

Per creare tipi di eccezione personalizzati, generabili da oggetti remoti e intercettabili da chiamanti remoti, attenersi alla procedura riportata di seguito.

  1. Implementare ISerializable.
  2. Impostare l'attributo SerializableAttribute per la classe.
  3. Implementare un costruttore di deserializzazione che utilizzi come parametri un oggetto SerializationInfo e un oggetto StreamingContext.

Nell'esempio di codice C# riportato di seguito viene fornita una semplice implementazione che, se configurata in modo corretto, viene copiata sul chiamante quando viene generata dall'oggetto server remoto.

[Serializable]
public class CustomRemotableException : RemotingException, ISerializable {
   private string _internalMessage;

   public CustomRemotableException(){
      _internalMessage = String.Empty;
   }
   
   public CustomRemotableException(string message){
      _internalMessage = message;
   }
   
   public CustomRemotableException(SerializationInfo info, StreamingContext context){
      _internalMessage = (string)info.GetValue("_internalMessage", typeof(string));
   }

   public override void GetObjectData(SerializationInfo info, StreamingContext context){
      info.AddValue("_internalMessage", _internalMessage);
   }

   // Returns the exception information. 
   public override string Message{
      get {
            return "This is your custom remotable exception returning: \"" 
      + _internalMessage 
      + "\"";
      }
   }
}

Oggetti con marshalling per riferimento

Gli oggetti con marshalling per riferimento (MBR, Marshal-by-reference) sono oggetti remotizzabili che estendono almeno System.MarshalByRefObject. A seconda del tipo di attivazione dichiarato, quando un client crea un'istanza di un oggetto MBR nel dominio applicazione di appartenenza, dall'infrastruttura di .NET Remoting viene creato un oggetto proxy nel dominio applicazione del chiamante che rappresenta l'oggetto MBR e restituisce al chiamante un riferimento a tale proxy. Il client effettua quindi chiamate sul proxy. Dalla comunicazione remota viene effettuato il marshalling di tali chiamate, queste ultime vengono inviate nuovamente al dominio applicazione di origine e viene richiamata la chiamata sull'oggetto effettivo.

Nota   Se il client si trova nello stesso dominio applicazione dell'oggetto MBR, un riferimento diretto all'oggetto MBR viene restituito al client dall'infrastruttura, evitando in tal modo di causare overhead nel marshalling.

Se un MarshalByRefObject viene passato come parametro, diventa un proxy nell'altro dominio applicazione quando arriva la chiamata. I valori restituiti MBR e i parametri out funzionano allo stesso modo.

Nota   A partire dalla versione 1.1 di .NET Framework, nell'infrastruttura remota non vengono deserializzati automaticamente alcuni tipi nel server. Per ottenere supporto per gli oggetti MBR passati come parametri, ad esempio, è necessario impostare il livello di deserializzazione del server su Full affinché il server sia in grado di deserializzare e utilizzare l'oggetto MBV. Per informazioni dettagliate su questo e altri scenari, vedere Deserializzazione automatica in .NET Remoting.

Utilizzare gli oggetti MBR quando è necessario che stato dell'oggetto ed eventuali funzionalità eseguibili rimangano nel dominio applicazione in cui sono stati creati. È necessario, ad esempio, che un oggetto in cui un campo interno è un handle del sistema operativo estenda MarshalByRefObject, poiché l'handle non avrebbe significato in un altro dominio applicazione, in un altro processo o in un altro computer. Talvolta le dimensioni di un oggetto possono essere eccessive per essere inviate via cavo a un modem da 33,6 kbps, benché non creino problemi su un server potente.

Oggetti associati al contesto

Si tratta di oggetti MBR che ereditano da System.ContextBoundObject, che a sua volta eredita da System.MarshalByRefObject. Un contesto può essere considerato come una suddivisione di un dominio applicazione che fornisce un ambiente complesso agli oggetti che vi risiedono durante l'esecuzione. Un contesto può garantire, ad esempio, che non sia possibile accedere all'oggetto contemporaneamente da più thread. Ogni dominio applicazione dispone di un contesto predefinito. Nella maggior parte del codice gestito gli oggetti vengono creati e i membri chiamati direttamente dall'interno dello stesso dominio applicazione mediante tale contesto predefinito, senza problemi legati al contesto. Tutti i tipi che ereditano da ContextBoundObject sono esposti come proxy ad altri contesti, che si trovino o meno nello stesso dominio.

Si supponga, ad esempio, di avere un metodo su un tipo che fa parte di una transazione ed è pertanto associato in base alle regole specifiche del contesto in cui è stato creato. È necessario che tale tipo erediti da ContextBoundObject, in modo che l'accesso all'oggetto avvenga dal contesto dello stesso e che possano essere attivate le regole inerenti alle transazioni associate a tale oggetto e ai relativi metodi. Se un oggetto ContextBoundObject viene chiamato da un altro contesto all'interno dello stesso dominio applicazione, viene creato un proxy per il chiamante, ma la comunicazione intercontesto non consente di attraversare il sistema del canale e ciò aumenta l'efficienza della chiamata nella situazione in questione.

Poiché la suddetta operazione richiede tempo di elaborazione, è utile determinare i limiti che l'oggetto deve attraversare per decidere a quale tipo di oggetto remotizzabile il server dovrà corrispondere. È possibile accedere direttamente agli oggetti specifici di un determinato contesto solo da tale contesto. Lo stesso vale per gli oggetti specifici di un determinato dominio applicazione. Per utilizzare in modalità remota uno di questi oggetti, il sistema di comunicazione remota deve riuscire ad attraversare un limite di contesto, un limite di applicazione o entrambi prima di richiamare l'oggetto server dall'interno del limite di cui è specifico. Se non occorre un controllo di contesto per chiamare l'oggetto, sarà bene evitare che il tipo remoto estenda ContextBoundObject, poiché ciò consentirà a MarshalByRefObject di offrire prestazioni migliori. Se invece il controllo di contesto è necessario, ContextBoundObject dovrà essere esteso, tenendo presente che prima che la chiamata venga effettuata sull'oggetto dovrà essere attraversato il limite aggiuntivo.

Vedere anche

Oggetti remotizzabili e non remotizzabili | ContextBoundObject | Oggetti non remotizzabili