C # POCO для потока / байта [] и обработки во время чтения с клиентом Silverlight 4 через WCF - PullRequest
1 голос
/ 11 марта 2011

Для меня одной из досадных частей Silverlight является то, что он не позволяет вам возвращать Stream напрямую, поскольку Silverlight превратит его в Byte[] даже при использовании TransferMode.StreamedResponse.Используя эту технику, можно обработать что-то вроде FileStream потоковым способом из клиента Silverlight ( см. Код ниже ).

Однако я хотел бы сделать что-то подобное с действительно большими C # POCO.Если бы я мог получить Stream, я мог бы использовать что-то вроде сериализации XML на обоих концах и обрабатывать записи по мере их чтения.Однако, поскольку возвращаемое значение должно быть Byte[], я должен прочитать до конца массива, прежде чем смогу его обработать.Этот метод, по крайней мере, позволяет мне предоставить некоторую обратную связь пользователю.

Я предложил две возможности возможных решений.Можно было бы написать свой собственный сериализатор или, по крайней мере, десериализатор, где я обрабатываю данные во время их чтения (я имею в виду текст с разделителями).Другая мысль заключалась бы в создании некоторого типа переменного бита Stream класса, который, я считаю, потребовал бы от меня крутой кривой обучения.Я ищу любые идеи или ссылки на возможности о том, как обрабатывать значения в Byte[] во время их чтения.

Сервисный контракт:

public static class Action {
    public static string val = "http://tempuri.org/stream";
}

// Share contract between client and server
[ServiceContract]
public interface IFileService {
#if SILVERLIGHT
    [OperationContract(AsyncPattern = true, Action = Action.val, ReplyAction = Action.val)]
    IAsyncResult BeginReadFile(Message request, AsyncCallback callback, object AsyncState);
    system.ServiceMode.Channels.Message EndReadFile(IAsyncResult result);
#else
    [OperationContract(AsyncPattern = true, Action = Action.val, ReplyAction = Action.val)]
    IAsyncResult BeginReadFile(string filePath, AsyncCallback callback, object AsyncState);
    system.IO.Stream EndReadFile(IAsyncResult result);
#endif
}

[DataContract(Name = "ReadFile", Namespace = "http://tempuri.org/")]
public class StreamRequest
{
    [DataMember(Order = 1)]
    public string FileName;
}

Внедрение услуги:

public IAsyncResult BeginReadFile(string filePath, AsyncCallback callback, object AsyncState) {
    return new CompletedAsyncResult<Stream>(File.OpenRead(filePath));
}

public Stream EndReadFile(IAsyncResult result) {
    return ((CompletedAsyncResult<Stream>)result).Data;
}

Клиент:

public void ReadFile( string filePath ) {
    BackToUIThread backToUIThread = byteCount => {
        this.OnBytesReceived(this, new AsyncEventArgs<object>(byteCount));
    };

    StreamRequest request = new StreamRequest() { FileName = "C:\\test.txt" };
    Message mIn = Message.CreateMessage(
        _myFactory.Endpoint.Binding.MessageVersion, Action.val, request);

    _myService.BeginReadFile(mIn,
        (asyncResult) =>
        {
            Message mOut = _myService.EndReadFile(asyncResult);
            System.Xml.XmlDictionaryReader r = mOut.GetReaderAtBodyContents();
            r.ReadToDescendant("ReadFileResult"); // move to stream
            r.Read(); // move to content

            int bytesRead = 1;
            long totalBytesRead = 0;
            byte[] buffer = new byte[100];
            do {
                bytesRead = r.ReadContentAsBase64(buffer, 0, buffer.Length);
                totalBytesRead += bytesRead;
                if (bytesRead > 0) {
                    System.Windows.Deployment.Current.Dispatcher.BeginInvoke(
                        backToUIThread, totalBytesRead);
                }
            } while (bytesRead > 0);
            r.Close();
            mOut.Close();                
        }, null);
}

1 Ответ

0 голосов
/ 11 марта 2011

Ваше приложение Silverlight может передать смещение и количество байтов, которые вы хотите прочитать в вашем сервисе.

У вас может быть что-то вроде

int offset = 0;  
int length = 1024;  
List<byte> bytes = new List<bytes>();  

_myService.ReadFileComplete += (s, e)=>  
{  
    bytes.Add(e.Result.Bytes);  
    if(asyncResult.Result.HasMore)  
    {  
        offset += length;  
        _myService.ReadFileAsync(fileName, offset, length);  
    }  
    else  
    {  
        DoSomethingWithBytes(bytes);  
    }  
}

_myService.ReadFileAsync(fileName, offset, length);

Тогда в вашей службе WCFПросто используйте метод Stream.Read с заданным смещением и длиной.

Вы можете улучшить это, если служба вернет следующее смещение для чтения.

...