Сохранение состояния на уровне сервиса - PullRequest
3 голосов
/ 07 октября 2011

У меня есть базовый класс обслуживания, и у меня есть набор служб, является ли хорошей / плохой практикой хранение данных в классе обслуживания?

Например:

public interface IFunkyService
{
  void AddComment(int quoteid, string comment);
  void SetProirirty(int quoteid, Importance proirity);
}

public class FunkyService : CustomServiceBase, IFunkyService
{

 private readonly IRepo _repo;
 private readonly IUserSession _user;
 public FunkyService(IRepo repo, IUserSession user)
 {
  _repo = repo;
  _user = user;
 }


     public void SetProirirty(int quoteid, Important priority)
     {

      //get quote object then persists

     } 

    public void AddComment(int quoteid, string comment)
     {

      //get quote object then persists

     }

}

Могу ли я просто иметь приватный метод, который хранит объект кавычки в классе?например,

private Quote _quote {get;set;} //store on the class???

private void GetQuote(int quoteid)
{
 _quote = _repo.single(quoteid); //or whatever
}

Ответы [ 3 ]

2 голосов
/ 07 октября 2011

Обратите внимание, что значение в классе будет жить столько же, сколько сам объект службы.Сервисный объект создается и уничтожается при каждом запросе к сервису, поэтому Quote будет жить только в течение одного запроса.Единственная цель, которую я вижу для чего-то подобного, - это кэш для каждого запроса (т. Е. Во время одного запроса вы обращаетесь к объекту Quote пять раз. Вам нужно только один раз просмотреть его из резервного хранилища).

  1. Клиент делает запрос к серверу
  2. Сервер создает FunkyService класс
  3. Клиентские вызовы GetQuote
  4. Сервер заполняет Quote в классе.
  5. Клиент завершает вызов.
  6. Сервер завершает запрос, удаляет объект FunkyService из (2).
  7. Значение Quote больше не сохраняется в классепотому что объект исчез.

Редактировать: Похоже, что вы хотите сделать это так, чтобы получение объекта цитаты было сделано в одном месте, но это не таквызываться снова и снова (т. е. делать несколько запросов к базе данных, когда нужен только один).Вы можете реализовать шаблон проектирования кешируемых свойств, чтобы иметь кеш для каждого запроса без использования переменной класса.Это будет выглядеть примерно так:

private Dictionary<int, Quote> _quoteCache = 
    new Dictionary<int, Quote>(); // cache storage - NEVER ACCESS DIRECTLY

public Quote GetQuote(int quoteid)
{
    // cache is invalid, so populate
    if (!_quoteCache.ContainsKey(quoteid))
    {
        _quoteCache.Add(quoteid, _repo.single(quoteid));
    }

    // return back to caller
    return _quoteCache[quoteid];
}

В приведенном выше примере в кеше хранятся все уникальные цитаты, извлеченные из базы данных.Поэтому, если вы вызываете GetQuote(5) пять раз подряд, он извлекается из базы данных только через _repo один раз.Однако если вы позвоните GetQuote(6), то он снова попадет в базу данных, потому что эта кавычка недоступна из кэша.После этого и 5, и 6 по-прежнему сохраняются в кэше до тех пор, пока запрос на обслуживание не будет завершен и ликвидирован.

Edit2: В приведенном вами примере:

var t = GetTags(_quote);
// then do something with t, I may pass to another method:
if(IsClosed(_quote)){} 

Вместо того, чтобы ссылаться на переменную класса, пусть ваш репозиторий вернет объект Quote и передаст эту ссылку, например:

private Quote GetQuote(int quoteid)
{
    return _repo.single(quoteid); //or whatever
}

// other code
var q = GetQuote(quoteid); // get the quote once
var t = GetTags(q);  // q doesn't have to retrieve from repo again
if (IsClosed(q)) {}
// etc.
1 голос
/ 08 октября 2011

Не уверен, применимо ли это в вашем случае, но при переключении службы без сохранения состояния (или вообще любого компонента) на состояние с полным состоянием необходимо рассмотреть несколько вопросов:

  1. Потокобезопасность - вы должны сделатьсостояние неизменяемое для обеспечения потокового доступа к этому состоянию.Также имейте в виду, что большинство отслеживающих (отслеживающих состояние) ORM не так хорошо работают, когда одни и те же экземпляры доступны из нескольких потоков.
  2. Рассмотрите возможность развертывания службы в нескольких экземплярах (скажем, для балансировки нагрузки) в будущем.Если состояние не является неизменяемым, вы можете получить не синхронизированные экземпляры для одной и той же сущности.
  3. Если причиной этого является улучшение кэширования и производительности, вы можете разработать стратегию ортогонального кэширования, позволяющую избежать вышеуказанных проблем.- Например, используя поставщика кеша NHibernate или кешируя данные на прикладном уровне.

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

0 голосов
/ 07 октября 2011

Проблема с сохранением состояния в ваших службах заключается в том, что необходимо учитывать срок службы экземпляра класса Service.

Например, если ваша служба предоставляется через WCF, то режим экземпляра по умолчанию «per call» будет сводить на нет любое состояние между вызовами метода, поскольку каждый вызов будет означать, что для каждого вызова от клиента создается новый экземпляр службы , Однако вы можете использовать InstanceContextMode.PerSession для «поддержания» соединения между клиентом и службой между вызовами, что даст вам некоторое преимущество в состоянии, хотя у него также есть и обратная сторона: масштабируемость может быть ограничена, поскольку ваш клиент в конечном итоге теперь имеет контроль над ресурсами сервера, используемыми в вашем штате.

@ Мелламокб замечателен тем, что одним из распространенных применений состояния в SOA является кэширование.

...