Постоянство данных WCF между сессиями
Мы разрабатываем систему на основе WCF. В процессе мы пытаемся заблокировать некоторые данные от изменения более чем одним пользователем. Поэтому мы решили создать структуру данных, которая будет содержать необходимую информацию для выполнения логики блокировки (например, путем сохранения идентификатора заблокированных объектов).
Проблема, которую мы имеем, заключается в сохранении этих данных между сессиями. Есть ли в любом случае, мы можем избежать выполнения дорогостоящих вызовов базы данных? Я не уверен, как мы можем сделать это в WCF, поскольку он может сохранять данные (в памяти) только во время открытого сеанса.
4 ответа
Статические члены класса, реализующего сервис, распределяются между сеансами и вызовами.
Один из вариантов - использовать статические элементы, как сказал Джимми МакНалти. У меня есть служба WCF, которая открывает сетевые подключения на основе указанного пользователем IP-адреса. Мой сервис настроен на режим экземпляра сервиса PerCall. В каждом сеансе я проверяю статическую структуру данных, чтобы увидеть, открыто ли сетевое соединение для указанного IP-адреса. Вот пример.
[ServiceContract]
public interface IMyService
{
[OperationContract]
void Start(IPAddress address);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class MyService : IMyService
{
private static readonly List<IPAddress> _addresses = new List<IPAddress>();
public void Start(IPAddress address)
{
lock(((ICollection)_addresses).SyncRoot)
{
if (!_addresses.Contains(address)
{
// Open the connection here and then store the address.
_addresses.Add(address);
}
}
}
}
В соответствии с настройкой, каждый вызов Start() происходит в своем собственном экземпляре службы, и каждый экземпляр имеет доступ к статической коллекции. Поскольку каждый экземпляр службы работает в отдельном потоке, доступ к коллекции должен быть синхронизирован.
Как и в случае со всей синхронизацией, выполняемой в многопоточном программировании, обязательно минимизируйте время, затрачиваемое на блокировку. В показанном примере, как только первый абонент захватывает блокировку, все остальные абоненты должны ждать, пока блокировка не будет снята. Это работает в моей ситуации, но может не работать в вашей.
Другой вариант - использовать режим экземпляра единой службы, а не режим экземпляра службы PerCall.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class MyService : IMyService
{ ... }
Однако из всего, что я прочитал, PerCall выглядит более гибким.
Вы можете перейти по этой ссылке для различия между ними.
И не забывайте, что класс, который реализует ваш сервис - это просто класс. Это работает как все классы C#. Вы можете добавить статический конструктор, свойства, обработчики событий, реализовать дополнительные интерфейсы и т. Д.
Создайте второй класс и установите его InstanceContextMode в single и переместите туда все дорогие методы, а затем в своем исходном классе используйте эти методы.