Блокировка с помощью асинхронного httpwebrequest

У меня есть объект, который загружает файл с сервера, асинхронно сохраняет его в изолированном хранилище и предоставляет метод GetData для извлечения данных. Буду ли я использовать

IsolatedStorageFile storageObj; //initialized in the constructor

lock(storageObj)
{
   //save code
}

В ответ и

lock(storageObj)
{
   //load code
}

В методе GetData?

Изменить: я дам здесь некоторый контекст. Приложению (для Windows Phone) необходимо загружать и кэшировать несколько файлов с сервера, поэтому я создал тип, который принимает 2 строки (URI и имя файла), отправляет данные из заданного URI и сохраняет их. Этот же объект также имеет метод получения данных. Вот код (немного упрощенный)

public class ServerData: INotifyPropertyChanged
{
    public readonly string ServerUri;
    public readonly string Filename;
    IsolatedStorageFile appStorage;

    DownloadState _downloadStatus = DownloadState.NotStarted;
    public DownloadState DownloadStatus
    {
        protected set
        {
            if (_downloadStatus == value) return;
            _downloadStatus = value;
            OnPropertyChanged(new PropertyChangedEventArgs("DownloadStatus"));
        }
        get { return _downloadStatus; }
    }

    public ServerData(string serverUri, string filename)
    {
        ServerUri = serverUri;
        Filename = filename;
        appStorage = IsolatedStorageFile.GetUserStoreForApplication();
    }
    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, args);
    }

    public void RequestDataFromServer()
    {
        DownloadStatus = DownloadState.Downloading;
   //this first bit adds a random unused query to the Uri, 
   //so Silverlight won't cache the request
        Random rand = new Random();
        StringBuilder uriText = new StringBuilder(ServerUri);
        uriText.AppendFormat("?YouHaveGotToBeKiddingMeHack={0}", 
                             rand.Next().ToString());
        Uri uri = new Uri(uriText.ToString(), UriKind.Absolute);
        HttpWebRequest serverRequest = (HttpWebRequest)WebRequest.Create(uri);
        ServerRequestUpdateState serverState = new ServerRequestUpdateState();
        serverState.AsyncRequest = serverRequest;
        serverRequest.BeginGetResponse(new AsyncCallback(RequestResponse),
            serverState);
    }

    void RequestResponse(IAsyncResult asyncResult)
    {
        var serverState = (ServerRequestUpdateState)asyncResult.AsyncState;
        var serverRequest = (HttpWebRequest)serverState.AsyncRequest;
        Stream serverStream;
        try
        {
            // end the async request
            serverState.AsyncResponse = 
                (HttpWebResponse)serverRequest.EndGetResponse(asyncResult);
            serverStream = serverState.AsyncResponse.GetResponseStream();
            Save(serverStream);
            serverStream.Dispose();
        }
        catch (WebException)
        {
            DownloadStatus = DownloadState.Error;
        }

        Deployment.Current.Dispatcher.BeginInvoke(() =>
        {
            DownloadStatus = DownloadState.FileReady;
        });
    }

    void Save(Stream streamToSave)
    {
        StreamReader reader = null;
        IsolatedStorageFileStream file;
        StreamWriter writer = null;
        reader = new StreamReader(streamToSave);

        lock (appStorage)
        {
            file = appStorage.OpenFile(Filename, FileMode.Create);
            writer = new StreamWriter(file);
            writer.Write(reader.ReadToEnd());
            reader.Dispose();
            writer.Dispose();
        }
    }

    public XDocument GetData()
    {
        XDocument xml = null;
        lock(appStorage)
        {
            if (appStorage.FileExists(Filename))
            {
                var file = appStorage.OpenFile(Filename, FileMode.Open);
                xml = XDocument.Load(file);
                file.Dispose();
            }
        }
        if (xml != null)
            return xml;
        else return new XDocument();
    }
}

person Christopher Stevenson    schedule 14.03.2011    source источник
comment
если это так, почему бы не сделать это синхронно?   -  person Sanjeevakumar Hiremath    schedule 15.03.2011
comment
Это заблокировало бы поток пользовательского интерфейса   -  person Christopher Stevenson    schedule 16.03.2011


Ответы (2)


Ваш вопрос не дает очень много контекста, и с количеством предоставленной информации люди могут быть склонны просто сказать вам да, может быть, с небольшими, но уместными дополнениями.

Практика обычно видит, что блокировка происходит на экземпляре выделенного object, обязательно избегайте блокировки this, поскольку вы блокируете весь экземпляр текущего объекта, что вряд ли является намерением, если вообще когда-либо - но в вашем случае мы не знаю точно в полной мере, однако я вряд ли думаю, что блокировка вашего экземпляра хранилища - это путь.

Кроме того, поскольку вы упоминаете взаимодействие клиента и сервера, это не так просто.

В зависимости от нагрузки и многих других факторов, вы можете захотеть обеспечить многократные чтения файла с сервера, но только одну запись в любой момент времени на загружаемом клиенте; для этой цели я бы рекомендовал использовать класс ReaderWriterLockSlim, который предоставляет TryEnterReadLock, TryEnterWriteLock и соответствующие методы выпуска.

Для получения более подробной информации об этом классе см. эту ссылку MSDN .

Кроме того, не забывайте использовать try, catch и finally при кодировании в рамках блокировки, всегда снимая блокировку в блоке finally.

person Grant Thomas    schedule 14.03.2011
comment
Спасибо за совет, я расширим свой вопрос. - person Christopher Stevenson; 15.03.2011
comment
Да, и пока я не забыл, в этом приложении нет записи на сервер, аргументы для запрашиваемых данных строго указаны в uri. - person Christopher Stevenson; 15.03.2011
comment
К сожалению, ReaderWriterLockSlim не входит в состав Silverlight. - person Christopher Stevenson; 16.03.2011
comment
@Chris: В этом случае взгляните на Monitor - msdn.microsoft.com/en-us/library/ - person Grant Thomas; 16.03.2011
comment
Итак, разница между Monitor.Enter(Object) и Monitor.TryEnter(Object) в том, что TryEnter не будет блокироваться? Хм. Вы имеете в виду, если у меня есть несколько потоков, пытающихся одновременно прочитать файл, и они блокируют друг друга с помощью оператора блокировки (объекта). Теперь вопрос в том, как справиться с ситуацией TryEnter() == false. Хм... - person Christopher Stevenson; 17.03.2011
comment
Мой текущий план состоит в том, чтобы гарантировать, что весь доступ к файлам осуществляется на BackgroundWorkers, который можно было бы заблокировать, пока не произойдет взаимоблокировка. Вообще говоря, удержание только одной блокировки за раз должно предотвратить это. (Я перешел от использования объекта appData к частному объекту, созданному для этой цели. Я перепутал частный объект с частной ссылкой на объект. - person Christopher Stevenson; 17.03.2011

Какой класс содержит этот код? Это важно, поскольку важно, если он создается более одного раза. Если он создается один раз за время жизни процесса, вы можете сделать это, если нет, вы должны заблокировать экземпляр статического объекта.

Однако я считаю хорошей практикой создавать отдельный объект, который используется только для блокировки, я забыл почему. Например.:

IsolatedStorageFile storageObj; //initialized in the constructor
(static) storageObjLock = new object();
...
// in some method
lock(storageObjLock)
{
   //save code 
}
person steinar    schedule 14.03.2011