Stiamo sviluppando un servizio WCF per lo streaming di una grande quantità di dati, pertanto abbiamo scelto di utilizzare la funzionalità WCF Streaming combinata con una serializzazione protobuf-net.Serializzazione di oggetti pigri e basati su stream con protobuf-net
Contesto:
In generale l'idea è di serializzare gli oggetti nel servizio, scriverli in un flusso e inviare. All'altro capo il chiamante riceverà un oggetto Stream e può leggere tutti i dati.
Così attualmente il codice di metodo di servizio sembra un po 'come questo:
public Result TestMethod(Parameter parameter)
{
// Create response
var responseObject = new BusinessResponse { Value = "some very large data"};
// The resposne have to be serialized in advance to intermediate MemoryStream
var stream = new MemoryStream();
serializer.Serialize(stream, responseObject);
stream.Position = 0;
// ResultBody is a stream, Result is a MessageContract
return new Result {ResultBody = stream};
}
L'oggetto BusinessResponse è serializzato a un MemoryStream e che viene restituito da un metodo. Sul lato client il codice chiamante appare così:
var parameter = new Parameter();
// Call the service method
var methodResult = channel.TestMethod(parameter);
// protobuf-net deserializer reads from a stream received from a service.
// while reading is performed by protobuf-net,
// on the service side WCF is actually reading from a
// memory stream where serialized message is stored
var result = serializer.Deserialize<BusinessResponse>(methodResult.ResultBody);
return result;
Così, quando serializer.Deserialize()
si chiama legge da un flusso methodResult.ResultBody
, allo stesso tempo sul WCF lato servizio sta leggendo un MemoryStream, che è stato restituito da a TestMethod
.
Problema:
Quello che vorremmo raggiungere è quello di sbarazzarsi di un MemoryStream
e prima serializzazione di tutto l'oggetto sul lato di servizio in una sola volta. Dato che usiamo lo streaming vorremmo evitare di tenere un oggetto serializzato in memoria prima di inviarlo.
Idea:
La soluzione ideale sarebbe quella di restituire un, oggetto Stream misura vuoto (da TestMethod()
) con un riferimento a un oggetto che deve essere serializzato (oggetto 'BusinessResponse' nell'esempio). Quindi, quando WCF chiama un metodo Read()
del mio stream, internizzo in serie un pezzo di un oggetto usando protobuf-net e lo restituisco al chiamante senza memorizzarlo nella memoria.
E ora c'è un problema, perché ciò di cui abbiamo effettivamente bisogno è la possibilità di serializzare un oggetto pezzo per pezzo nel momento in cui viene letto lo stream. Capisco che questo è un modo totalmente diverso di serializzazione: invece di spingere un oggetto su un serializzatore, vorrei richiedere un contenuto serializzato pezzo per pezzo.
Questo tipo di serializzazione è in qualche modo possibile utilizzando protobuf-net?
Questo è un oggetto? O una serie di oggetti (una collezione)? Se vale la pena guardare questo dipende in realtà dalla configurazione di WCF - nella maggior parte delle configurazioni memorizzerà sempre l'intero messaggio in memoria * comunque * - quindi potrebbe essere facile non cambiare nulla. –
Hi Marc, WCF è configurato per non utilizzare affatto il buffering - questo è il punto di streaming - Voglio ridurre il footprint di memoria sul lato server. Inoltre, se mi piacerebbe serializzare la raccolta di oggetti, userei 'SerializeWithLengthPrefix()' ogni volta che il Client chiama 'Read()' e il mio buffer sottostante è più piccolo della quantità di dati richiesta. Il problema qui è che mi piacerebbe essere in grado di dividere la serializzazione di un singolo oggetto. –
domanda interessante. I * think * questo può essere generalizzato, essenzialmente a un flusso di spoof che rende la lettura e la scrittura lavoro come co-routines. Se non ti dispiace avere un Thread in più, potrebbe essere fatto con un semplice gate, tuttavia iirc Jon ha avuto alcune idee interessanti. Dovrò dare un'occhiata e tornare da te. Tuttavia, posso dire senza dubbio che non intendo hackerare il nucleo di protobuf-net allo scopo :) –