Cet article a fait l'objet d'une traduction automatique.
Silverlight
Créer des applications d'entreprise ligne de Business avec Silverlight, partie 1
Hanu Kommalapati
Cet article présente :
|
Cet article utilise les technologies suivantes : Silverlight 2 |
Téléchargement de code disponible de la bibliothèque de code MSDN
Parcourir le code en ligne
Contenu
Principes fondamentaux de Silverlight : CoreCLR
Runtime de Silverlight
Le scénario d'application
Pousser les notifications avec socket Server
Boucles d'E / S asynchrones
Boîtes de dialogue modales dans Silverlight
Exécute un push implémentation de notification
Accès entre domaines de services TCP
Stratégies entre domaines avec les services de TCP
Conclusion
Lorsque J'AI présenté un briefing direction sur les implications Entreprise de Silverlight à une grande entreprise dans Houston récemment, la réponse était lukewarm. Le cool explique que DeepZoom showcased, des images dans l'image et vidéo de qualité haute définition, et animations de haute qualité doivent avoir facilement heureux du groupe. Est lorsque j'interrogé les spectateurs sur leur intérêt limité, il devenu évident que pendant belle graphiques ont été très, il était peu conseils réelle disponible pour la qualité de l'entreprise, les données-centrée sur, les métier d'applications (LOB) avec Silverlight.
Aujourd'hui, classe d'entreprise applications nécessitent livraison sécurisé des informations MÉTIER au-delà des limites de réseau, généralement sur Internet, avec l'interface utilisateur basée sur les rôles et masquage de données appliqué pour le contexte d'entreprise. Exécution de Silverlight sur le client et Microsoft .NET Framework 3.5 sur le serveur fournit des capacités excellentes pour ces applications MÉTIER évolutif et sécurisé. Le runtime de Silverlight léger s'exécute dans un sandbox fournit bibliothèques framework pour l'intégration avec les services de données back-office. Pour créer des applications robustes avec Silverlight, les architectes et développeurs doivent comprendre le modèle de programmation Silverlight et ses fonctionnalités d'infrastructure dans le contexte d'une application réelle.
Mon principal objectif de cet article est de prendre un scénario d'entreprise et de créer une application dès le départ, illustrant les divers aspects de développement Silverlight sur la façon. La solution que j'aborderai est une application de centre d'appel ; son architecture logique est illustré figure 1 . Dans cet article, je me concentrerai sur écran pop notification, le modèle de programmation asynchrone, boîtes de dialogue Silverlight et implémentation du serveur entre domaines TCP stratégie. Dans la partie 2, j'aborderai sécurité des applications, Web Intégration du service, le partitionnement application et un certain nombre d'autres aspects de l'application.
Figure 1 Architecture logique du centre d'appels Silverlight
Principes fondamentaux de Silverlight : CoreCLR
Avant que je commencer, nous allons avoir un actualisateur des principes fondamentaux de Silverlight. J'AI tout d'abord un coup de dans le runtime de Silverlight pour vous pouvez obtenir mieux comprendre ce qui est possible avec Silverlight. Le CoreCLR est la machine virtuelle utilisée par Silverlight. Il est similaire au CLR qui alimente .NET Framework 2.0 et au-delà et contient des systèmes de collection (GC) type-chargement et garbage similaires.
Le CoreCLR possède un modèle de sécurité (CAS) de l'accès code très simple, plus simple que dans le CLR bureau Silverlight nécessite seulement d'appliquer des stratégies de sécurité au niveau de l'application. Cette est dû au fait que, en tant que client Web indépendant de la plate-forme, il ne peut pas dépendent toute entreprise spécifique ou stratégies d'ordinateur est en effet, et il ne doit pas autoriser un utilisateur à modifier les stratégies existantes. Il existe quelques exceptions, telles que OpenFileDialog et IsolatedStorage (modification du quota de stockage), où Silverlight doit consentement explicite de l'utilisateur pour rompre l'ensemble de règles sandbox par défaut. OpenFileDialog est utilisé pour accéder au système de fichiers, tandis que IsolatedStorage est utilisé pour accéder au stockage isolé méthode ADO éponyme à savoir et augmenter le quota de stockage.
Pour les applications de bureau, chaque exécutable charge exactement une copie du CLR et le processus du système d'exploitation contiendra qu'une application. Chaque application possède un domaine du système, un domaine partagé, un domaine par défaut et une multitude de domaines d'application (voir » explicitement crééJIT et exécuter : plonger dans .NET Framework Internals pour voir comment le CLR crée des objets de l'exécution"). Un modèle de domaine identique se trouve dans le CoreCLR. Dans le cas de Silverlight, plusieurs applications, éventuellement depuis des domaines différents, va s'exécuter en le même processus du système d'exploitation.
Dans Internet Explorer 8.0, chaque onglet s'exécute dans son propre processus isolé ; ainsi toutes les applications Silverlight hébergées dans le même onglet va être fonctionne dans le contexte de la même instance CoreCLR, comme illustré dans la figure 2 . Chaque application peut être d'un autre domaine d'origine, pour des raisons de sécurité, chaque application sera chargée dans son propre domaine d'application. Il y aura que plusieurs instances du CoreCLR comme il onglets actuellement hébergement d'applications Silverlight.
Comme pour le CLR de bureau, chaque domaine d'application obtient son propre pool des variables statiques. Chaque pool propres au domaine est initialisé lors de l'AppDomain démarrer le processus.
La figure 2 chaque exécuter Silverlight applications sera dans son propre domaine d'application
Applications Silverlight ne peut pas créer leurs propres domaines d'application personnalisée ; Utilisation interne cette capacité est réservée. Pour une étude plus détaillée de la CoreCLR, faire référence aux CLR Inside Out colonnes suivantes de l'équipe CLR: »Programme Silverlight avec CoreCLR« et »Sécurité dans Silverlight 2."
Runtime de Silverlight
Silverlight est conçu pour un large éventail d'applications qui nécessitent différents degrés de la structure et du support bibliothèque. Une application simple peut lire par exemple, uniquement des fichiers audio de quelques octets pour aider la prononciation des mots sur un site Web de dictionnaire ou afficher un enchaînement d'images. D'autre part, entreprise classe MÉTIER applications nécessitent une sécurité, confidentialité de données, gestion de l'état, intégration avec d'autres applications et services et instrumentation prise en charge, pour nommer quelques. En même temps, Silverlight doit disposer d'une exécution plus petite afin que le déploiement sur Internet ne soient pas un problème sur les connexions lentes.
Ces exigences semblent à entrer en conflit, mais l'équipe de Silverlight le géré par l'infrastructure de partitionnement dans l'affichage en couches, illustré figure 2 . CoreCLR + runtime de Silverlight est appelé le "complément, « les utilisateurs tout sont installent avant d'ils peuvent exécuter des applications. Le plug-in est suffisant pour la plupart des applications orientés consommateur. Si une application nécessite l'utilisation d'une bibliothèque de Kit de développement logiciel (SDK) (intégration WCF ou exécution DLR such as Iron Ruby) ou une bibliothèque personnalisée, l'application doit empaqueter ces composants dans le package XAP afin que Silverlight sachent comment résoudre les types nécessaires au moment de l'exécution (voirPointe dans ce numérode plus en XAPs).
Le runtime de Silverlight est environ 4 Mo de taille et, en plus CoreCLR bibliothèques comme agcore.dll et coreclr.dll, contient les bibliothèques nécessaires requis par les développeurs d'application. Cela inclut les bibliothèques fondamentales suivantes : mscorlib.dll, System.dll System.Net.dll, System.Xml.dll et System.Runtime.Serialization.dll. Le runtime qui prend en charge le plug-in de navigateur généralement est installé sous le répertoire C:\Program Files\Microsoft Silverlight\2.0.30930.0\. Il s'agit le répertoire obtient créé lorsqu'un ordinateur télécharge et installe Silverlight comme une partie de la navigation session Web.
Les développeurs qui générer et tester des applications sur le même ordinateur aura deux copies de l'exécution : une seule copie installée par le plug-in et l'autre à l'installation du Kit de développement logiciel (SDK). La copie de ce dernier peut se trouver dans les assemblys répertoire C:\Program Files\Microsoft SDKs\Silverlight\v2.0\Reference. Cette copie est utilisée par les modèles Visual Studio cadre de la liste des références temps compilation.
Le sandbox empêche l'application Silverlight d'interagir avec la plupart des ressources locales, qui est vrai pour toute application Web standard. Par défaut, une application Silverlight ne peut pas accéder un système de fichiers (autre que stockage isolé), les connexions socket, interagir avec les périphériques sont connectés à l'ordinateur ou installe les composants logiciels. Cela certainement impose certaines contraintes sur les types d'applications un pouvez construire sur la plate-forme de Silverlight. Toutefois, Silverlight a toutes les ingrédients nécessaires pour développer une classe d'entreprise, application d'entreprise pilotés par les données qui a besoin pour intégrer avec les processus d'entreprise back-end et les services.
Le scénario d'application
L'application MÉTIER que je vous créer ici, présente une architecture de contrôle d'appel tiers où un serveur centralisé taps dans une infrastructure PBX (change branche privé permettant de contrôler téléphones de manière centralisée. La mesure où mon objectif est de vous concentrer sur Silverlight en tant que la surface de l'interface utilisateur, je ne pas être passer trop de temps sur l'intégration téléphonie. Au lieu de cela, je vais utiliser simulator un simple appel pour générer un événement d'appel entrant. Le simulateur va ignorer un paquet de données qui représente l'appel dans une file d'attente du gestionnaire de call, qui déclenche le processus est central à ce projet.
Mon scénario fictif nécessite l'application Centre appel s'exécute dans un navigateur Web d'une manière indépendant de la plate-forme tout en fournissant l'interaction utilisateur riche qu'une application de bureau. Silverlight était le choix naturel que ActiveX n'est pas très populaire sur les environnements clients non Windows.
Examinons aspects Architecture de l'application. Vous devez être l'implémentation notifications de type Pousser, Intégration d'événements, intégration du service métier, la mise en cache, sécurité et intégration avec les services de nuage.
exécute un push de notifications Ils sont nécessaires car le système doit capturer les entrantes appel événement et de transfert vocale interactif réponse (IVR) données entré par l'appelant « pop écran », ou lors du remplissage de l'écran de l'interface utilisateur avec les informations d'appel entrant. En outre, l'utilisateur doit disposer possibilité accepter ou refuser l'appel.
événement flux Dans une application Web standard, le serveur Web présente toutes les connaissances des événements métier qu'il effectue l'essentiel du processus métier. Dans le cas d'une application de Internet riche (FINS), toutefois, l'implémentation de processus métier est partagée par les deux l'application s'exécute dans le navigateur Web et le serveur qui implémente des services Web métier. Cela signifie que des événements métier ainsi que des technologies événements générés dans l'application Silverlight doivent être envoyées au serveur via un ensemble de services Web spéciales.
Exemples des événements métier dans ce cas solution sont lorsque l'utilisateur (commercial) refuse l'appel ("commercial rejeté l'appel ») ou accepte l'appel (« a commercial accepté l'appel »). Événements de technologie standard sont « connexion au serveur d'appel Gestionnaire TCP a échoué » et « exception de service Web ».
Intégration du service métier La solution Centre appel, tout comme n'importe quelle application MÉTIER, doit être intégrée aux données qui peuvent être stockées dans une base de données relationnelle. Je vais utiliser services Web comme un moyen pour cette intégration.
la mise en cache Pour une meilleure expérience utilisateur, J'AI met en cache les informations localement en mémoire, ainsi que sur le disque. Les informations mises en cache peuvent inclure les fichiers XML qui indiquent prompter scripts le commercial et les autres données de référence qui peut ne changent pas souvent.
application de sécurité Sécurité est un impératif fondamental de ce type d'application. La sécurité inclut l'authentification, autorisation, confidentialité des données de vol et au reste et masquage des données en fonction de profil utilisateur.
Intégration avec les services de nuage Intégration avec un service de base en fonction de nuage, comme service de stockage, nécessite spéciales infrastructures côté serveur. Ceci est afin que l'utilisation de nuage services peut être étroitement contrôlée et Accélération responsabilité et des niveaux de service.
J'aborderai Intégration aux services métier, sécurité de l'application, stratégies interdomaine pour les services Web et applications de partitionnement dans la deuxième partie de cet article.
Pousser les notifications avec socket Server
Écran pop est une des exigences fondamentales d'une application de centre d'appel pour transfert contexte des appels à partir de l'infrastructure de téléphonie vers écran un agent. Le contexte d'appel transférées peut inclure aucune information vocales (pour les systèmes IVR) ou gérés par le client phone-in dans.
La notification peut être envoyée à l'application Silverlight dans le navigateur d'une des deux manières : par commande d'interrogation ou un serveur client. Interrogation est relativement facile à implémenter, mais il n'est peut-être pas le choix optimal pour les scénarios Centre appel où synchronisation état entre les événements de téléphonie et l'application cliente doit être précis. Il est pour cette raison que je vais utiliser les notifications de type Pousser à l'aide des sockets Silverlight.
Un des fonctionnalités importantes de Silverlight est la communication avec les sockets TCP. Pour raisons de sécurité, Silverlight autorise uniquement les connexions aux ports de serveur dans la plage de 4502 à 4532. Ceci est un des nombreuses stratégies de sécurité implémentés dans le sandbox. Une autre stratégie sandbox important est que Silverlight ne peut pas être un port d'écoute et, par conséquent, ne peut pas accepter des connexions entrantes socket. Pour ces raisons, je vais créer un serveur socket à l'écoute sur le port 4530 et de mettre à jour un pool de connexions à chaque connexion représentant un commercial Centre appels active.
Le runtime de socket Silverlight met en œuvre également des stratégies d'opt domaines sur le serveur pour toutes les connexions socket. Si Silverlight application code tente d'ouvrir une connexion à un point de terminaison IP sur un numéro de port autorisé, opaque le code utilisateur, le runtime s'établir une connexion à un point de terminaison IP sur la même adresse IP par le numéro du port 943. Ce numéro de port est hardwired à l'implémentation de Silverlight et ne peut pas être configuré par les applications ou modifié par le développeur d'applications.
la figure 1 indique où le serveur de stratégie tienne dans l'architecture. Lorsque Socket.ConnectAsync est appelée, la séquence de flux de message est comme illustré figure 3 . Par conception, les messages 2, 3 et 4 sont complètement opaques au code d'utilisateur.
La figure 3 Runtime de Silverlight demandes entre domaines stratégie automatiquement pour les connexions de socket
J'AI besoin d'implémenter un serveur de stratégie sur la même adresse IP que le serveur de Gestionnaire call. Je peut implémenter les deux serveurs dans un processus du système d'exploitation unique ; Cependant, pour sake de simplicité que je les implémenter dans deux programmes distincts console. Ces programmes console peuvent être facilement convertis en services Windows et apportées clusters-pour le basculement fournir fiabilité et disponibilité.
Boucles d'E / S asynchrones
.NET Framework 3.5 introduit asynchrone de nouvelle programmation API des sockets ; ils sont les méthodes qui se terminent par Async(). Les méthodes que j'utiliserai sur le serveur sont Socket.AcceptAsync, Socket.SendAsync et Socket.ReceiveAsync. Méthodes asynchrones sont optimisés pour serveur haut débit applications via l'utilisation de ports de fin d'E / S et efficace recevoir et envoyer gestion de mémoire tampon via la classe SocketAsyncEventArgs réutilisable.
Prend en raison du fait que Silverlight n'est pas autorisé à créer TCP ports d'écoute, la classe Socket uniquement en charge ConnectAsync, SendAsync et ReceiveAsync. Silverlight prend uniquement en charge un modèle de programmation asynchrone, et c'est non seulement pour les API socket mais pour aucune intervention de réseau.
Étant donné que j'utiliserai un modèle de programmation asynchrone sur le serveur, ainsi que sur le client, passons à l'aise avec les modèles de conception. Un modèle de conception périodique est la boucle d'E / S, qui est applicable à toutes les opérations asynchrones. Tout d'abord, j'allons étudier le type l'exécution synchrone du socket accepter la boucle, comme indiqué ici :
_listener.Bind(localEndPoint);
_listener.Listen(50);
while (true)
{
Socket acceptedSocket = _listener.Accept();
RepConnection repCon = new
RepConnection(acceptedSocket);
Thread receiveThread = new Thread(ReceiveLoop);
receiveThread.Start(repCon);
}
La synchronisation accepter est intuitive et facile à programmer et tenez à jour ; toutefois, cette implémentation n'est très évolutive pour les serveurs, qu'il existe des threads dédiés pour chaque connexion client. Cette implémentation peut facilement peak à plusieurs connexions si les connexions sont très bavardes.
Pour Silverlight fonctionner avec l'environnement d'exécution navigateur, elle doit intrude sur les ressources possible. Tous les appels dans le code pseudo "socket accepter" illustré précédemment bloquent les threads d'exécuter et ainsi avoir un impact négatif sur l'évolutivité. Pour cette raison, Silverlight est très restrictif de blocage des appels et, en fait, permet uniquement asynchrone interaction avec les ressources réseau. Boucles asynchrones nécessitent l'ajustement de votre modèle mentale pour visualiser une zone de message invisible qui doit avoir au moins une demande qu'elle contient tout le temps de la boucle travailler.
La figure 4 illustre une boucle de réception (une implémentation plus complète est dans le téléchargement de code). Il existe sans boucle infinie constructions de programmation tels que le temps boucle (vrai) que vous l'avez vu dans le socket synchrone accepter pseudo code précédemment. L'obtention utilisé pour ce type de programmation est essentielle pour un développeur de Silverlight. Pour que la boucle de réception continuer à réception de données, après qu'un message a été reçu et traité, il doit être au moins une demande de la file d'attente sur le port de fin d'E / S associée le socket connecté. Une boucle asynchrone classique est illustrée par la figure 5 et est applicable à ConnectAsync, ReceiveAsync et SendAsync. AcceptAsync peuvent être ajoutés à cette liste sur le serveur où vous utilisez .NET Framework 3.5.
Figure 4 asynchrone Envoi/réception boucles avec les sockets de Silverlight
public class CallNetworkClient
{
private Socket _socket;
private ReceiveBuffer _receiveBuffer;
public event EventHandler<EventArgs> OnConnectError;
public event EventHandler<ReceiveArgs> OnReceive;
public SocketAsyncEventArgs _receiveArgs;
public SocketAsyncEventArgs _sendArgs;
//removed for space
public void ReceiveAsync()
{
ReceiveAsync(_receiveArgs);
}
private void ReceiveAsync(SocketAsyncEventArgs recvArgs)
{
if (!_socket.ReceiveAsync(recvArgs))
{
ReceiveCallback(_socket, recvArgs);
}
}
void ReceiveCallback(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
{
return;
}
_receiveBuffer.Offset += e.BytesTransferred;
if (_receiveBuffer.IsMessagePresent())
{
if (OnReceive != null)
{
NetworkMessage msg =
NetworkMessage.Deserialize(_receiveBuffer.Buffer);
_receiveBuffer.AdjustBuffer();
OnReceive(this, new ReceiveArgs(msg));
}
}
else
{
//adjust the buffer pointer
e.SetBuffer(_receiveBuffer.Offset, _receiveBuffer.Remaining);
}
//queue an async read request
ReceiveAsync(_receiveSocketArgs);
}
public void SendAsync(NetworkMessage msg) { ... }
private void SendAsync(SocketAsyncEventArgs sendSocketArgs)
{
...
}
void SendCallback(object sender, SocketAsyncEventArgs e)
{
...
}
}
La figure 5 modèle de boucle socket asynchrones
Dans l'implémentation de boucle réception illustrée figure 4 , ReceiveAsync est un wrapper à la méthode réentrants ReceiveAsync(SocketAsyncEventArgs recvArgs) est la demande sur le port de terminaison d'E / S du socket file d'attente. SocketAsyncEventArgs, introduite dans .NET Framework 3.5, a un rôle similaire dans l'implémentation de socket Silverlight et peut être réutilisé entre plusieurs demandes, ce qui évite le nombre de collection garbage. Il sera la responsabilité de la routine de rappel pour extraire le message, déclencher un événement de traitement de messages et enqueue suivant recevez article pour poursuivre la boucle.
Pour gérer les cas de réception du message partielle, ReceiveCallback ajuste le tampon de file d'attente avant une autre requête. NetworkMessage est encapsulé dans une instance de ReceiveArgs et transmise au gestionnaire d'événements externes pour traiter le message reçu.
La mémoire tampon est réinitialisé à chaque réception complète de la NetworkMessage après la copie du message partiel, cas échéant, au début de la mémoire tampon. Un modèle similaire est utilisé sur le serveur, mais réelles implémentations peuvent tirer parti de mémoires tampon circulaire.
Pour implémenter le scénario « appel acceptation » illustré dans le diagramme de séquence (voir La figure 6 ), vous devez créer une architecture extensible message qui vous permet de sérialiser et désérialiser les messages qui contiennent contenu arbitraire sans nécessité la réécriture de la logique de sérialisation pour chaque nouveau message.
La figure 6 mise en page des types NetworkMessage avec numéro de série
L'architecture du message est assez simple : chaque objet enfant de le NetworkMessage déclare sa signature au moment instanciation avec MessageAction appropriée. Implémentations NetworkMessage.Serialize et Deserialize fonctionnera sur Silverlight et .NET Framework 3.5 (sur le serveur) en raison de la compatibilité de niveau de code source. Le message avec numéro de série aura la mise en page illustré figure 6 .
Au lieu d'insérer la longueur au début du message, vous pouvez utiliser les indicateurs « début » et « fin » avec les séquences d'échappement appropriée. Codage de longueur dans le message est beaucoup plus simple pour traiter les tampons.
Les quatre premiers octets de chaque message sérialisé va inclure le nombre d'octets de l'objet sérialisé suivant les 4 octets. Silverlight prend en charge XmlSerializer situé dans System.Xml.dll dont fait partie le Kit de développement Silverlight. Le code de sérialisation est inclus dans le téléchargement de code. Vous remarquerez qu'il n'a pas les dépendances directes sur les classes enfant, telles que RegisterMessage ou les autres messages y compris UnregisterMessage et AcceptMessage. Une série d'annotations XmlInclude permettra le sérialiseur pour résoudre correctement les types .NET lors de la sérialisation les classes enfant.
L'utilisation de NetworkMessage.Serlialize et Deserialize est illustrée ReceiveCallback et SendAsync dans la figure 4 . Dans la boucle de réception, le traitement de message réel est effectué par le gestionnaire d'événements lié à l'événement NetworkClient.OnReceive. Je peut a traitée le message à l'intérieur CallNetworkConnection, mais vous associez le Gestionnaire de réception pour traiter le message est aider l'extensibilité par découplage le Gestionnaire de CallNetworkConnection au moment du design.
la figure 7 illustre l'application Silverlight RootVisual qui démarre le CallNetworkClient (illustré figure 4 ). Tous les contrôles Silverlight sont associés à un thread d'interface utilisateur unique, et les mises à jour l'interface utilisateur ne peuvent être effectués lorsque le code s'exécute dans le contexte de ce thread d'interface utilisateur. Le modèle de programmation asynchrone de Silverlight exécute le code d'accès réseau et les gestionnaires de traitement sur le pool de threads threads. Tous des classes dérivé de FrameworkElement (tels que le contrôle, bordure, Panneau de configuration et la plupart des éléments d'interface utilisateur) héritent de la propriété de Répartiteur (à partir de DispatcherObject), qui peut exécuter du code sur le thread d'interface utilisateur.
Dans la figure 7 , le cas MessageType.RegisterResponse met à jour l'interface utilisateur avec appel Centre équipe détails l'agent à un délégué anonyme. L'INTERFACE de mise à jour résultant de l'exécution de délégué est illustré figure 8 .
La figure 7 Silverlight UserControl qui traite les messages entrants
public partial class Page : UserControl
{
public Page()
{
InitializeComponent();
ClientGlobals.socketClient = new CallNetworkClient();
ClientGlobals.socketClient.OnReceive += new
EventHandler<ReceiveArgs>(ReceiveCallback);
ClientGlobals.socketClient.Connect(4530);
//code omitted for brevity
}
void ReceiveCallback(object sender, ReceiveArgs e)
{
NetworkMessage msg = e.Result;
ProcessMessage(msg);
}
void ProcessMessage(NetworkMessage msg)
{
switch(msg.GetMessageType())
{
case MessageAction.RegisterResponse:
RegisterResponse respMsg = msg as RegisterResponse;
//the if is unncessary as the code always executes in the
//background thread
this.Dispatcher.BeginInvoke(
delegate()
{
ClientGlobals.networkPopup.CloseDialog();
this.registrationView.Visibility = Visibility.Collapsed;
this.callView.Visibility = Visibility.Visible;
this.borderWaitView.Visibility = Visibility.Visible;
this.tbRepDisplayName.Text = this.txRepName.Text;
this.tbRepDisplayNumber.Text = respMsg.RepNumber;
this.tbCallServerName.Text =
respMsg.CallManagerServerName;
this.tbCallStartTime.Text =
respMsg.RegistrationTimestamp.ToString();
});
break;
case MessageAction.Call:
CallMessage callMsg = msg as CallMessage;
//Code omitted for brevity
if (!this.Dispatcher.CheckAccess())
{
this.Dispatcher.BeginInvoke(
delegate()
{
ClientGlobals.notifyCallPopup.ShowDialog(true);
});
}
break;
//
//Code omitted for brevity
//
default:
break;
}
}
}
La figure 8 enregistrement avec le serveur de centre d'appels est en cours
La figure 9 écran d'enregistrement initial ’s représentant
Boîtes de dialogue modales dans Silverlight
Lorsqu'un commercial de centre d'appel se connecte, il serez invité à démarrer le travail d'équipe en enregistrement avec le serveur central call. Le processus d'enregistrement sur le serveur va enregistrer la session indexée par le numéro de commercial. Cette session sera utilisée pour pop écran suivantes et les autres notifications. La transition d'écran de l'application Centre appel pour le processus d'enregistrement est illustrée aux figures 8 et 9 . Je vais utiliser une boîte de dialogue modale qui montre la progression de l'envoi de réseau. Applications MÉTIER standard d'entreprise utiliser boîtes de dialogue contextuelle, modal et non modale, tout à fait liberally. Comme il est sans DialogBox intégré dans le Kit de développement Silverlight, vous verront comment développer dans Silverlight pour une utilisation dans cette application.
Jusqu'à ce que Silverlight, ne survenu aucun moyen simple pour créer une boîte de dialogue modal, comme il ne était aucun moyen simple d'empêcher les événements de clavier en cours pumped dans l'interface utilisateur. Interaction de la souris peut être désactivée indirectement en définissant UserControl.IsTestVisible = false. Partir RC0 paramètre Control.IsEnabled = false empêche les contrôles d'interface utilisateur de recevoir les événements de clavier ou souris. Je vais utiliser System.Windows.Controls.Primitives.Popup pour afficher la boîte de dialogue l'interface utilisateur du contrôle existant.
la figure 10 illustre un contrôle SLDialogBox base avec les méthodes abstraites GetControlTree, WireHandlers et WireUI. Ces méthodes sont ignorées par les classes enfant, comme illustré à la figure 11 . Primitives.Popup nécessite une instance de contrôle ne fait pas partie de l'arborescence de contrôle à laquelle le menu contextuel sera joint. Dans le code dans la figure 10 , la méthode ShowDialog(true) va désactiver l'arborescence de tout contrôle de manière récursive afin qu'aucun des contrôles contenus recevra les événements souris ou clavier. Car mon dialogue contextuelle doit être interactif, le Popup.Child doit être défini d'une nouvelle instance de contrôle. L'implémentation GetControlTree dans les classes enfant va servir une fabrique de contrôle et fournir une nouvelle instance d'un contrôle utilisateur approprié pour les besoins de l'interface utilisateur de la boîte de dialogue.
La figure 10 contextuel DialogBox dans Silverlight
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
namespace SilverlightPopups
{
public abstract class SLDialogBox
{
protected Popup _popup = new Popup();
Control _parent = null;
protected string _ caption = string.Empty;
public abstract UIElement GetControlTree();
public abstract void WireHandlers();
public abstract void WireUI();
public SLDialogBox(Control parent, string caption)
{
_parent = parent;
_ caption = caption;
_popup.Child = GetControlTree();
WireUI();
WireHandlers();
AdjustPostion();
}
public void ShowDialog(bool isModal)
{
if (_popup.IsOpen)
return;
_popup.IsOpen = true;
((UserControl)_parent).IsEnabled = false;
}
public void CloseDialog()
{
if (!_popup.IsOpen)
return;
_popup.IsOpen = false;
((UserControl)_parent).IsEnabled = true;
}
private void AdjustPostion()
{
UserControl parentUC = _parent as UserControl;
if (parentUC == null) return;
FrameworkElement popupElement = _popup.Child as FrameworkElement;
if (popupElement == null) return;
Double left = (parentUC.Width - popupElement.Width) / 2;
Double top = (parentUC.Height - popupElement.Height) / 2;
_popup.Margin = new Thickness(left, top, left, top);
}
}
}
La figure 11 NotifyCallPopup.xaml apparence
//XAML Skin for the pop up
<UserControl
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
Width="200" Height="95">
<Grid x:Name="gridNetworkProgress" Background="White">
<Border BorderThickness="5" BorderBrush="Black">
<StackPanel Background="LightGray">
<StackPanel>
<TextBlock x:Name="tbCaption" HorizontalAlignment="Center"
Margin="5" Text="<Empty Message>" />
<ProgressBar x:Name="progNetwork" Margin="5" Height="15"
IsIndeterminate="True"/>
</StackPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" >
<Button x:Name="btAccept" Margin="10,10,10,10"
Content="Accept" HorizontalAlignment="Center"/>
<Button x:Name="btReject" Margin="10,10,10,10"
Content="Reject" HorizontalAlignment="Center"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</UserControl>
GetControlTree peuvent être implémentées pour instancier un contrôle UserControl Silverlight qui est compilé dans le package d'applications ou un contrôle peut être créé à partir d'un fichier XAML (Application Markup Language) eXtensible à l'aide de XamlReader.LoadControl. En règle générale, les boîtes de dialogue peuvent facilement être implémentées dans apparences à laquelle les gestionnaires de compilé peuvent être associés au moment de l'exécution. la figure 11 illustre une apparence XAML comporte les boutons btAccept et btReject. La méthode LoadControl lancera une exception si vous laissez l'attribut class (<userControl class="AdvCallCenter.NotifyCallPopup"…> … </usercontrol>) dans le fichier XAML après votre tâche de conception Microsoft Expression Studio ou de Visual Studio. Les attributs de gestionnaire d'événement l'interface utilisateur doivent être supprimés pour analyse réussie à l'aide de LoadControl.
Pour créer apparences, vous pouvez ajouter l'objet UserControl Silverlight au projet, créer dans l'expression et supprimer les « classe » attribut et événement Gestionnaire de noms, Si éventuel lié aux contrôles à partir du fichier XAML. Les gestionnaires de clic peuvent être partie de la classe enfant pop-up, comme illustré figure 12 , ou également une bibliothèque distincte Gestionnaire peut être créé que peut être câblé les contrôles de l'utilisation de la réflexion.
La figure 12 NotifyCallPopup implémentation
public class NotifyCallPopup : SLDialogBox
{
public event EventHandler<EventArgs> OnAccept;
public event EventHandler<EventArgs> OnReject;
public NotifyCallPopup(Control parent, string msg)
: base(parent, msg)
{
}
public override UIElement GetControlTree()
{
Return SLPackageUtility.GetUIElementFromXaml("NotifyCallPopup.txt");
}
public override void WireUI()
{
FrameworkElement fe = (FrameworkElement)_popup.Child;
TextBlock btCaption = fe.FindName("tbCaption") as TextBlock;
if (btCaption != null)
btCaption.Text = _caption;
}
public override void WireHandlers()
{
FrameworkElement fe = (FrameworkElement)_popup.Child;
Button btAccept = (Button)fe.FindName("btAccept");
btAccept.Click += new RoutedEventHandler(btAccept_Click);
Button btReject = (Button)fe.FindName("btReject");
btReject.Click += new RoutedEventHandler(btReject_Click);
}
void btAccept_Click(object sender, RoutedEventArgs e)
{
CloseDialog();
if (OnAccept != null)
OnAccept(this, null);
}
void btReject_Click(object sender, RoutedEventArgs e)
{
CloseDialog();
if (OnReject != null)
OnReject(this, null);
}
}
Les gestionnaires de peuvent être dans n'importe quel projet bibliothèque de Silverlight, car ils seront automatiquement compilés dans le package XAP en raison de la dépendance de projet. Pour les fichiers apparence à inclure dans le package XAP, ajoutez le projet Silverlight en tant que fichiers XML et modifiez l'extension en XAML. L'action de génération par défaut pour les fichiers avec une extension XAML consiste à compiler les dans l'application DLL. Étant donné que je veux ces fichiers pour être empaquetés en tant que fichiers texte, les attributs suivants à partir des fenêtres Propriétés doivent être définis :
- BuildAction = « contenu »
- Copie vers le répertoire de sortie = « ne pas copier »
- Outil personnalisé = < désactivez une valeur existante >
L'analyseur XAML (XamlReader.Load) ne charge pas sur l'extension ; Toutefois, avec l'extension .XAML sera plus intuitif et commercial du contenu. SLDialogBox est uniquement responsable indiquant, en fermant la boîte de dialogue. Les implémentations enfant va être personnalisées en fonction des besoins de l'application.
Exécute un push implémentation de notification
Une application de centre d'appel doit pouvoir faire un pop d'écran avec les informations de l'appelant. Un jour ouvré Centre appel commence par le commercial enregistrement avec le serveur central call. Notifications de type Pousser sont implémentées avec les sockets orienté connexion. L'implémentation entière appel Gestionnaire de serveur ne figure pas dans les chiffres mais est disponible dans le téléchargement de code. Lorsque le client Silverlight effectue une connexion de socket sur le serveur, un nouvel objet RepConnection renvoie ajouté à la RepList. Le RepList est une liste générique indexée par un nombre représentant unique. Si un appel est, vous utiliserez cette liste pour trouver un commercial disponible et, l'utilisation de la connexion de socket associées à la RepConnection, avertir l'agent avec les informations d'appel. RepConnection utilise ReceiveBuffer, comme illustré à la figure 13 .
La figure 13 RepConnection utilise ReceiveBuffer
class SocketBuffer
{
public const int BUFFERSIZE = 5120;
protected byte[] _buffer = new byte[BUFFERSIZE]
protected int _offset = 0;
public byte[] Buffer
{
get { return _buffer; }
set { _buffer = value; }
}
//offset will always indicate the length of the buffer that is filled
public int Offset
{
get {return _offset ;}
set { _offset = value; }
}
public int Remaining
{
get { return _buffer.Length - _offset; }
}
}
class ReceiveBuffer : SocketBuffer
{
//removes a serialized message from the buffer, copies the partial message
//to the beginning and adjusts the offset
public void AdjustBuffer()
{
int messageSize = BitConverter.ToInt32(_buffer, 0);
int lengthToCopy = _offset - NetworkMessage.LENGTH_BYTES - messageSize;
Array.Copy(_buffer, _offset, _buffer, 0, lengthToCopy);
offset = lengthToCopy;
}
//this method checks if a complete message is received
public bool IsMessageReceived()
{
if (_offset < 4)
return false;
int sizeToRecieve = BitConverter.ToInt32(_buffer, 0);
//check if we have a complete NetworkMessage
if((_offset - 4) < sizeToRecieve)
return false; //we have not received the complete message yet
//we received the complete message and may be more
return true;
}
}
Vous allez utiliser un simulateur appel Silverlight pour supprimer un appel dans le CallDispatcher._callQueue à déclencher le processus pop écran. Le CallDispatcher ne figure pas dans un des chiffres, mais il est disponible dans le code téléchargeable. Il s'attache un gestionnaire à _callQueue.OnCallReceived et va obtenir notifié lorsque le simulateur enqueues le message à la _callQueue dans l'implémentation ProcessMessage. En tirant parti des boîtes de dialogue contextuelles que J'AI abordé précédemment, le client affiche la notification accepter/rejeter, comme illustré à la figure 14 . Voici la ligne de code qui est responsable affichant la boîte de dialogue notification réel 8 :
ClientGlobals.notifyCallPopup.ShowDialog(true);
La figure 14 entrant appel notification
Accès entre domaines de services TCP
Contrairement au support et les applications Affichage annonce, classe d'entreprise réels MÉTIER applications nécessitent Intégration avec une variété de service-hébergement environnements. Par exemple, l'application de centre d'appel est hébergée sur un site Web (advcallclientweb hébergé à localhost:1041), utilise un socket avec état serveur sur un autre domaine (localhost:4230) pour écran pop et atteint données MÉTIER via des services hébergés sur un autre domaine (localhost:1043). Il utilise un autre domaine pour la transmission de données d'instrumentation.
Le sandbox Silverlight ne, par défaut, autorise l'accès réseau à aucun domaine autre que le domaine d'origine, advcallclientweb (localhost:1041). Lorsque l'accès réseau est détectée, le runtime de Silverlight vérifie les stratégies opt-en établies par le domaine de destination. Voici une liste typique des scénarios d'hébergement de service qui doivent prendre en charge les demandes de stratégie de domaines par le client :
- Services hébergés dans le nuage
- Services Web hébergés dans un processus du service
- Les services Web hébergés dans IIS ou autre Web serveurs
- Ressources HTTP comme balise XAML et packages XAP
- TCP services hébergés dans un processus de service
Bien qu'il soit simple à implémenter des stratégies entre domaines pour les ressources HTTP et points de terminaison de service Web hébergés dans IIS, les autres cas requièrent la connaissance de la sémantique de demande/réponse de stratégie. Dans cette section, je brièvement implémenter l'infrastructure de stratégie nécessaire pour le serveur pop de écran TCP, qui est appelé Gestionnaire d'appel dans la figure 1 . Les autres scénarios de domaines seront abordés dans la deuxième partie de cet article.
Stratégies entre domaines avec les services de TCP
Tout accès au service TCP dans Silverlight est considéré comme une demande de domaines, et le serveur a besoin implémenter un écouteur TCP sur la même adresse IP est liée au port 943. Le serveur de stratégie illustré figure 3 est le port d'écoute implémentée pour cela. Ce serveur implémente un processus demande/réponse de transmission en continu des stratégies déclaratives nécessaires par le runtime de Silverlight avant d'autoriser la pile de mise en réseau sur le client pour se connecter au serveur pop écran (Gestionnaire appel à la figure 3 ).
Pour sake de simplicité, je n'ordinateur hôte le serveur de Gestionnaire call dans une application de console. Cette application de console peut facilement être convertie en un service Windows pour les implémentations réels. la figure 3 illustre l'interaction avec un serveur de stratégie classique ; le runtime de Silverlight va se connecter au serveur sur le port 943 et envoyer une demande de stratégie qui contiendra une seule ligne de texte: « <policy-file-request/> ».
Les stratégies basé sur XML permettent le scénario illustré figure 3 . La section ressource socket peut spécifier un groupe de ports dans la plage autorisée de 4502 à 4534. Le raisonnement de restriction à une plage consiste à réduire le vecteur d'attaque, ainsi limiter le risque d'accidentelles faiblesses dans la configuration du pare-feu. Étant donné que le serveur de centre d'appel (Gestionnaire appel à la figure 1 ) écoute sur le numéro de port 4530, la ressource de socket est configurée comme suit :
<access-policy>
<policy>
<allow-from> list of URIs</allow-from>
<grant-to> <socket-resource port="4530" protocol="tcp"/></grant-to>
</policy>
</access-policy>
Vous pouvez également configurer <socket-resource> pour autoriser tous les numéros ports autorisés en spécifiant port = « 4502–4534 ».
Pour gagner du temps, je vais réorienter le code du serveur de Gestionnaire call dans l'implémentation du serveur de stratégie. Un client de Silverlight se connecte au serveur de stratégie, envoie une demande et lit la réponse. Serveur de stratégie ferme la connexion une fois que la réponse de stratégie est envoyée avec succès. Le contenu de stratégie est lus par le serveur de stratégie à partir d'un fichier local, clientaccesspolicy.xml, qui est inclus dans le téléchargement.
L'implémentation d'écouteur TCP de serveur de stratégie est illustrée figure 15 . Celui-ci utilise la même asynchrone en boucle motif évoqué précédemment pour acceptation TCP. Clientaccesspolicy.XML est lu dans un tampon et réutilisé pour l'envoi à tous les clients de Silverlight. Le ClientConnection encapsule le socket accepté et le tampon de réception qui seront associé à l'objet SocketAsyncEventArgs.
La figure 15 TCP stratégie Server Implementation
class TcpPolicyServer
{
private Socket _listener;
private byte[] _policyBuffer;
public static readonly string PolicyFileName = "clientaccesspolicy.xml";
SocketAsyncEventArgs _socketAcceptArgs = new SocketAsyncEventArgs();
public TcpPolicyServer()
{
//read the policy file into the buffer
FileStream fs = new FileStream(PolicyServer.PolicyFileName,
FileMode.Open);
_policyBuffer = new byte[fs.Length];
fs.Read(_policyBuffer, 0, _policyBuffer.Length);
_socketAcceptArgs.Completed += new
EventHandler<SocketAsyncEventArgs>(AcceptAsyncCallback);
}
public void Start(int port)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
//Should be within the port range of 4502-4532
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, port);
_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections
try
{
_listener.Bind(ipEndPoint);
_listener.Listen(50);
AcceptAsync();
}
//code omitted for brevity
}
void AcceptAsync()
{
AcceptAsync(socketAcceptArgs);
}
void AcceptAsync(SocketAsyncEventArgs socketAcceptArgs)
{
if (!_listener.AcceptAsync(socketAcceptArgs))
{
AcceptAsyncCallback(socketAcceptArgs.AcceptSocket,
socketAcceptArgs);
}
}
void AcceptAsyncCallback(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success)
{
ClientConnection con = new ClientConnection(e.AcceptSocket,
this._policyBuffer);
con.ReceiveAsync();
}
//the following is necessary for the reuse of _socketAccpetArgs
e.AcceptSocket = null;
//schedule a new accept request
AcceptAsync();
}
}
L'exemple de code illustré figure 15 utilise SocketAsyncEventArgs entre plusieurs TCP accepte. Pour cela, e.AcceptSocket doit être définie à null dans AcceptAsyncCallback. Cette approche empêchera le nombre de catalogue global sur le serveur avec les exigences évolutivité élevée.
Conclusion
Implémentation de notifications de type Pousser est un aspect important d'une application Centre appel et est un outil du processus pop écran. Silverlight facilite l'implémentation pop écran beaucoup que la AJAX ou infrastructures similaires. Étant donné que le serveur de programmation et le client modèles de programmation sont similaires, je pouvais obtenir certains réutilisabilité au niveau de code source. Dans le cas du centre d'appel, je peut utiliser les définitions de message et recevoir des abstractions de la mémoire tampon dans le serveur et les implémentations côté client.
J'implémenter en principe Intégration du service Web, sécurité, Intégration cloud-service et application partitionnement dans la partie 2 de cette série. J'espère que cet effort resonates correctement avec certains des scénarios MÉTIER que vous soyez sur, et J'AI hâte vos commentaires.
Je serait comme remercier Dave Murray et postes de charge DeSeranno Shane de Microsoft pour proposer des conseils sur les données internes de Silverlight socket implémentation, avec Robert Brooks, un expert de domaine lors de l'appel de la discussion pop écran.
Hanu Kommalapati est un Gestionnaire de stratégie de plate-forme chez Microsoft et dans son rôle actuel il avertit des clients d'entreprise dans la création des applications évolutives de métier sur des plates-formes Silverlight et services Azure.