Студопедия
Случайная страница | ТОМ-1 | ТОМ-2 | ТОМ-3
АрхитектураБиологияГеографияДругоеИностранные языки
ИнформатикаИсторияКультураЛитератураМатематика
МедицинаМеханикаОбразованиеОхрана трудаПедагогика
ПолитикаПравоПрограммированиеПсихологияРелигия
СоциологияСпортСтроительствоФизикаФилософия
ФинансыХимияЭкологияЭкономикаЭлектроника

Визначення контракту зворотнього виклику

Читайте также:
  1. Contract language мова контракту
  2. CONTRACT КОНТРАКТУ
  3. Fulfilment of contract, performance виконання контракту
  4. II. Знайдіть відповідне визначення для кожного терміну.
  5. II. Знайдіть відповідне визначення для кожного терміну.
  6. II. Знайдіть відповідне визначення для кожного терміну.
  7. II. Знайдіть відповідне визначення для кожного терміну.

Як було вказано в контракті інтерфейс зворотнього виклику називається IChatServiceCallback. Даний інтерфейс повинен бути реалізований клієнтською частиною, бо саме його методи буде викликати хост для взаємодії в асинхронному режимі з клієнтом. Даний інтерфейс визначатиме дві операції – прийом повідомлення та повідомлення про зміну списку клієнтів. Реалізація:

IChatServiceCallback
  public interface IChatServiceCallback { [OperationContract(IsOneWay = true)] void ReceiveMessage(ChatMessage message);   [OperationContract(IsOneWay = true)] void ChattersListChanged(); }  
  Параметр атрибуту OperationContract IsOneWayповідомляє що дане з’єднання є одностороннє і даний метод нічого не має повертати серверу, інакше буде згенеровано виключну ситуацію.  

 

3.1.3. Реалізація класів, через які здійснюватиметься обмін

Класами, які будуть учасниками обміну між клієнтом та хостом є повідомлення та системне повідомлення. Перший буде містити інформацію про відправника та отримувача та текст повідомлення. Другий буде передавати інформацію щодо виклику тих чи інших методів контракту сервісу.

Всі класи які беруть участь в обміні повідомленнями мають бути позначені атрибутом DataContract, а їх члени атрибутами DataMember полів та властивостей та EnumMember для елементів перелічуваного типу.

Реалізація:

SystemMessage
  [DataContract] public class SystemMessage { [DataContract] public enum SystemMessageType { [EnumMember] Good, [EnumMember] Warning, [EnumMember] Error }   [DataMember] public string Message { get; set; }   [DataMember] public SystemMessageType Status { get; set; }   public override string ToString() { return string.Format("{0} - {1}", Status, Message); } }  

 

ChatMessage
  [DataContract] public class ChatMessage { [DataContract] public enum ChatMessageType { [EnumMember] Input, [EnumMember] Output, [EnumMember] Error }   [DataMember] public ChatMessageType Type { get; set; }   [DataMember] public string Message { get; set; }   [DataMember] public string From { get; set; }   [DataMember] public string To { get; set; } }  

 

3.1.4. Реалізація контракту

Даний етап є досить тривіальним – реалізувати IChatService, але є декілька особливостей, які варто розглянути: перше це атрибут ServiceBehavior для реалізації контракту, друге деталі реалізації.

Реалізація описана з атрибутом у такому вигляді:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)],

де ConcurrencyMode вказує що даний контракт підтримує багатопотоковий доступ до своїх ресурсів. InstanceContextMode вказує що буде створюватися окремий контекст для кожного сеансу (окремий канал для кожного клієнта).

Деталі реалізації:

Всі дані про підключених клієнтів будуть зберігатися у двох колекціях: перша буде Dictionary, що містить нікнейм клієнта як ключ та інтерфейс зворотнього виклику для цього клієнта як значення. Саме завдяки цій колекції сервіс виконує свою роботу по надсиланню повідомлень. Друга колекція – список усіх активних (онлайн) клієнтів, їх нікнеймів. Ці дві колекції є статичними тому що є спільними для всіх створених сесій. Також кожна сесія містить нікнейм клієнта, з яким з’єднана.

Реалізація:

 

ChatService: IChatService
  [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerSession)] public class ChatService: IChatService { private static readonly Dictionary<string, IChatServiceCallback> Chatters = new Dictionary<string, IChatServiceCallback>();   private static readonly List<string> ChattersNicknames = new List<string>(); private string _nickname;   public SystemMessage Enter(string nickname) { if (!Chatters.ContainsKey(nickname)) { _nickname = nickname; ChattersNicknames.Add(nickname); Chatters.Add(nickname, OperationContext.Current.GetCallbackChannel<IChatServiceCallback>()); ChattersListChanged(nickname); return new SystemMessage { Status = SystemMessage.SystemMessageType.Good, Message = string.Format("Привіт, {0}!", nickname) }; } else { return new SystemMessage { Status = SystemMessage.SystemMessageType.Error, Message = "Error! Користувач з таким ніком вже є мережі." }; } }   public SystemMessage Leave() { if (Chatters.ContainsKey(_nickname)) { Chatters.Remove(_nickname); ChattersNicknames.Remove(_nickname); ChattersListChanged(null); return new SystemMessage { Status = SystemMessage.SystemMessageType.Good, Message = "Користувач з ніком " + _nickname + " вийшов!" }; } return new SystemMessage { Status = SystemMessage.SystemMessageType.Error, Message = "Error! Користувач з таким ніком не є мережі." }; }   public SystemMessage SendMessage(ChatMessage message) { string target = message.To; try { if (Chatters.ContainsKey(target)) { message.Type = ChatMessage.ChatMessageType.Input; Chatters[target].ReceiveMessage(message); return new SystemMessage { Message = "Повідомлення надіслано!", Status = SystemMessage.SystemMessageType.Good }; } } catch { return new SystemMessage { Message = "Помилка надсилання..!", Status = SystemMessage.SystemMessageType.Error }; } return new SystemMessage { Message = "Проблема підчас надсилання..!", Status = SystemMessage.SystemMessageType.Warning }; }   public List<string> GetChattersList() { return ChattersNicknames; }   private static void ChattersListChanged(string nickname) { var badLeavedClientsList = new List<string>(); foreach (var chatter in Chatters) { try { if (chatter.Key!= nickname) chatter.Value.ChattersListChanged(); } catch { badLeavedClientsList.Add(chatter.Key); } } badLeavedClientsList.ForEach(delegate(string s) { ChattersNicknames.Remove(s); Chatters.Remove(s); }); } }  

 

Вираз OperationContext.Current.GetCallbackChannel<IChatServiceCallback>()) отримує сам об’єкт клієнта з відкритого контексту з’єднання (згадайте атрибут ServiceBehavior та властивість InstanceContextMode), власне після цього вся взаємодія між сервісом та клієнтом мало відрізняється від двохпоточної програми, хоча насправді це лише абстракція.

 

 

Хост

Сервіс реалізовано, залишилось реалізувати простий хост, який буде керувати підключеннями до сервісу.


Дата добавления: 2015-11-16; просмотров: 62 | Нарушение авторских прав


<== предыдущая страница | следующая страница ==>
WCF вступ та принцип ABC.| 1 страница

mybiblioteka.su - 2015-2024 год. (0.006 сек.)