Доска рекордов на WCF и RavenDB. Хранение данных

16.04.2014 at 19:32

В предыдущей части мы сделали сервис. Теперь напишем для него прокси, который будет использоваться в клиентском коде. Прокси для WCF сервисов можно генерировать прямо в студии: в контекстном меню на узле Refernces -> Add Service Reference, далее указываем адрес сервиса, нажимаем Go — и получаем сгенерированный прокси класс.


Можно оставить сгенерированный класс без изменений, но я решил удалить все лишнее.

/// <summary>
/// Клиент для доски рекордов.
/// </summary>
public class ScoreBoardClient : ClientBase<IScoreBoard>, IScoreBoard
{
  public ScoreBoardClient(string remoteAddress) :
    base(new NetTcpBinding(), new EndpointAddress(remoteAddress)) { }

  public List<ScoreBoardResult> GetTopResults(int count)
  {
    return base.Channel.GetTopResults(count);
  }
    
  public void AddResult(ScoreBoardResult result)
  {
    base.Channel.AddResult(result);
  }
}

Конструктор я добавил для большего удобства использования.

Хранение данных

Для хранения данных буду использовать RavenDB. Никаких особых причин для этого нет, просто давно хотелось попробовать. Идем на сайт ravendb.net и скачиваем последнюю версию в архиве. Распаковываем архив и добавляем в проект всю папку EmbeddedClient.
Создаем хранилище

this.documentStore = new EmbeddableDocumentStore 
{ 
  DataDirectory = "path_to_database_folder" 
};
this.documentStore.Initialize();     

После этого с хранилищем можно работать. Для добавления данных используется такой код:

lock (this.documentStore)
{
  using (var session = this.documentStore.OpenSession())
  {
    ScoreBoardResult record = session.Query<ScoreBoardResult>()
      .SingleOrDefault(r => r.Game == result.Game 
        && r.UserCode == result.UserCode);
    if (record != null)
    {
      if (record.Score < result.Score)
      {
        record.Score = result.Score;
        record.UserName = result.UserName;
        session.SaveChanges();
      }
    }
    else
    {
      session.Store(result);
      session.SaveChanges();
    }
  }
}

Здесь все просто — если в базе уже есть результат игрока, и новый результат лучше — перетираем результат. Если результата игрока нет в базе — добавляем его.
this.documentStore.OpenSession() — создание новой сессии работы с базой. Через созданную сессию происходят все обращения к базе (Unit Of Work).
session.Query() — получение данных из базы.
session.Store(result) — добавление объекта в базу.
session.SaveChanges() — сохранение результатов. В этот момент в хранилище попадут все изменения, сделанные через эту сессию.

Получение n лучших результатов еще легче:

using (var session = this.documentStore.OpenSession())
{
  return session.Query<ScoreBoardResult>()
    .OrderByDescending(r => r.Score)
    .Take(count)
    .ToList();
}

Запускаем, убеждаемся, что все работает, и чистим конфиг сервера (см. предыдущую статью). Должно остаться только это:

<system.serviceModel>
  <services>
    <service name="ScoreBoardServer.ScoreBoardService">
      <endpoint address="net.tcp://localhost:9876/"
                binding="netTcpBinding"
                contract="ScoreBoardServer.IScoreBoard" />
    </service>
  </services>
</system.serviceModel>

Впечатления от RavenDB

Очень удобно использовать. Типизированное хранилище без конфигурирования и маппинга. ORM не нужен совсем.
Встраиваемая база тормозит при инициализации. примерно секунд 5-10. Можно поднимать отдельный сервер RavenDB, но этот режим я не тестировал, возможно он будет производительнее.
Она платная. Лицензию не обязательно покупать при разработке, опенсорсные проекты могут получить лицензию бесплатно.

Полный код доски рекордов можно посмотреть на гитхабе.

Tags: