Home - About me - Browse by categories

[ASP.NET MVC] Multicast dans une application hébergée sur Azure avec AppFabric ServiceBus et NetEventRelayBinding

Il y a quelques semaines j’ai posté une astuce pour invalider un cache mémoire sur un changement de configuration d’instance Windows Azure. Bien que cette technique fonctionne, elle nécessite une intervention humaine, puisqu’à chaque fois que l’on souhaite invalider le cache, il faut modifier la configuration du service hébergé sur Azure.

Afin d’éviter de faire cela, je me suis penché sur l’utilisation d’AppFabric ServiceBus dans Azure et notamment du NetEventRelayBinding pour faire en sorte que lorsque je publie / supprime ou modifie un post, toutes les instances de mon blog soit notifiées et invalident leur cache mémoire.

Pour faire simple, j’expose un endpoint sur le service bus Azure, sur lequel toutes les instances vont s’abonner. Dès que l’une d’entre elle contact ce endpoint, toutes les autres sont notifiées.

Le bus des services permet de mettre en place un relai entre un client et un host de service WCF. Par exemple, il est possible d’avoir un service WCF qui soit hébergé sur un serveur IIS dans votre infrastructure et que ce service soit consommé depuis Azure ou une application totalement externe via le bus des services, évitant ainsi des problèmes de sécurité et de configuration de pare-feu.

L’autre scénario (mis en place ici) est le multicast ou le bus des services sert également de relai vers un host WCF, mais en mode multicast.

Pour mettre cela en place, il faut procéder en différentes étapes, décrites ci-après.

##

1. Activer un domaine sur le bus des services Windows Azure

Connectez-vous au portail d’administration Windows Azure sur http://windows.azure.com puis rendez-vous dans la section Bus des services, Contrôle d’accès et Cache via le menu de gauche :

image

Sélectionnez ensuite Bus des services dans le noeud AppFabric, puis cliquez sur Nouveau dans le ruban. Une popup s’ouvre alors, vous permettant d’ajouter un nouveau domaine sur lequel vous pourrez exposer vos services via AppFabric :

image

Choisissez votre espace de nom, la région dans laquelle exposer le bus des services, l’abonnement sur lequel vous souhaitez l’ajouter… puis valider la popup. Patientez jusqu’à ce que le Bus des services ajouté soit marqué comme Actif dans la liste.

image

2. Création du contrat de service et de l’implémentation du service

Comme AppFabric Service Bus sert de relais entre clients et host WCF, on utilise les mêmes mécanismes que WCF classique pour créer contrat de services et implémentations de services.

Dans mon cas, le contrat est ultra simple :

[ServiceContract(Name = "IRelayCacheInvalidationEventContract", Namespace = "http://www.juliencorioland.net/Services/")]
public interface IRelayCacheInvalidationEventContract
{
[OperationContract(IsOneWay = true)]
void InvalidateCache();
}

Attention toutefois à bien marquer toutes les OperationContract comme étant en mode One-Way, une condition nécessaire à l’utilisation du contrat sur le bus des services Azure.

J’ai également prévu une interface pour représenter le canal de communication WCF qui sera utilisé pour invalider le cache :

public interface IRelayCacheInvalidationEventChannel : IRelayCacheInvalidationEventContract, IClientChannel
{
}

A présent l’implémentation du service, une fois encore très simple ici puisqu’il s’agit d’implémenter l’interface IRelayCacheInvalidationEventContract :

public class CacheInvalidator : IRelayCacheInvalidationEventContract
{
public void InvalidateCache()
{
ICacheService cacheService = ServiceLocator.Current.GetInstance<ICacheService>();
if(cacheService != null)
{
cacheService.InvalidateCache();
}
}
}

###

###

3. Ajout du code pour hoster le service dans le Global.asax du rôle web ASP.NET MVC

Dans cette étape, il s’agit d’ajouter le code de création de l’host WCF qui sera exécuté par toutes les instances lors du démarrage de l’application web.

Pour cela, il faut dans un premier temps récupérer 3 informations : le domaine du bus des services, le nom l’émetteur par défaut (issuer name) et la clé partagée (shared secret). Pour récupérer ces informations, sélectionnez votre bus des services dans l’interface d’administration et cliquez sur le bouton Affichage de la zone** Clé par défaut**, à droite. Une popup s’affiche alors :

image

Personnellement, j’ai choisi de rajouter ces éléments au fichier de configuration du mon instance Azure, ce qui me permet de les récupérer de la sorte :

string serviceNamespace = RoleEnvironment.GetConfigurationSettingValue("CacheInvalidationRelayDomainNamespace");
string issuerName = RoleEnvironment.GetConfigurationSettingValue("CacheInvalidationRelayIssuerName");
string issuerSecret = RoleEnvironment.GetConfigurationSettingValue("CacheInvalidationRelayIssuerSecret");

Ensuite, vous devez créer une EndpointBehavior pour identifier l’appel sur le bus des services. Cela s’effectue à l’aide d’un TokenProvider et d’une instance de la classe TransportClientEndpointBehavior :

TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
TransportClientEndpointBehavior relayCredentials = new TransportClientEndpointBehavior(tokenProvider);

Pour avoir accès à ces classes, il vous faut référencer la librairie Microsoft.ServiceBus.dll.

A présent, utilisez l’api du service bus pour créer l’Uri qui hostera le relais vers le service :

Uri relayAddress = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "/CacheInvalidation/");

Puis comme vous l’auriez fait en WCF, crééez le ServiceHost et ajoutez lui l’endpoint behavior comme cela :

_serviceHost = new ServiceHost(typeof(CacheInvalidator), relayAddress);
foreach (var endpoint in _serviceHost.Description.Endpoints)
{
endpoint.Behaviors.Add(relayCredentials);
}
_serviceHost.Open();

###

###

Remarquez que l’endpoint behavior est rajoutée sur tous les endpoints configurés pour le service CacheInvalidator.

A présent, toutes les instances peuvent être atteintes via du multicast et donc pourront invalider leur cache mémoire !

4. Ajout du code pour récupérer un canal WCF et lancer l’invalidation de cache

Comme en WCF, on utilise un ChannelFactory pour récupérer un canal de communication. Pour pouvoir accéder au bus des services, il faut récupérer les mêmes informations que précédemment à savoir espace de noms, émetteur et clé partagé. Il faut également créer la behavior permettant d’authentifier l’appel

string serviceNamespace = RoleEnvironment.GetConfigurationSettingValue("CacheInvalidationRelayDomainNamespace");
string issuerName = RoleEnvironment.GetConfigurationSettingValue("CacheInvalidationRelayIssuerName");
string issuerSecret = RoleEnvironment.GetConfigurationSettingValue("CacheInvalidationRelayIssuerSecret");

TokenProvider tokenProvider = TokenProvider.CreateSharedSecretTokenProvider(issuerName, issuerSecret);
TransportClientEndpointBehavior relayCredentials = new TransportClientEndpointBehavior(tokenProvider);
Uri relayAddress = ServiceBusEnvironment.CreateServiceUri("sb", serviceNamespace, "/CacheInvalidation/");

A partir de là, il est possible de créer la ChannelFactory et de récupérer un canal de communication de type IRelayCacheInvalidationEventChannel pour invalider le cache :

ChannelFactory<IRelayCacheInvalidationEventChannel> channelFactory =
new ChannelFactory<IRelayCacheInvalidationEventChannel>("CacheInvalidationEndpoint",
new EndpointAddress(relayAddress));
channelFactory.Endpoint.Behaviors.Add(relayCredentials);
_cacheInvalidationChannel = channelFactory.CreateChannel();

_cacheInvalidationChannel.Open();
_cacheInvalidationChannel.InvalidateCache();

Pensez à bien fermer le canal lorsque vous n’en n’avez plus besoin :

_cacheInvalidationChannel.Close();

Le code étant en place, il ne reste plus qu’à configurer le service WCF, dans le Web.config du rôle web ASP.NET MVC !

###

5. Configuration du service WCF

Comme toujours la configuration d’un service WCF se passe dans la section system.serviceModel du fichier de configuration de l’application : ici le Web.config du rôle web !

Tout d’abord, il faut ajouter les extensions propres à l’utilisation du bus des services :

<system.serviceModel>
<extensions>
<bindingExtensions>
<add name="netEventRelayBinding" type="Microsoft.ServiceBus.Configuration.NetEventRelayBindingCollectionElement, Microsoft.ServiceBus, Version=1.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</bindingExtensions>
</extensions>
</system.serviceModel>

Ensuite il faut ajouter la définition du binding netRelayEventBinding (toujours dans system.serviceModel) :

<bindings>
<netEventRelayBinding>
<binding name="default" />
</netEventRelayBinding>
</bindings>

Puis le endpoint du service :

<services>
<service name="MetroBlog.Bll.CacheInvalidator">
<endpoint name="CacheInvalidationEndpoint"
contract="MetroBlog.Interfaces.IRelayCacheInvalidationEventContract"
binding="netEventRelayBinding"
bindingConfiguration="default" />
</service>
</services>

Pour terminer par la configuration du client :

<client>
<endpoint name="CacheInvalidationEndpoint"
contract="MetroBlog.Interfaces.IRelayCacheInvalidationEventContract"
binding="netEventRelayBinding"
bindingConfiguration="default"
/>
</client>

Et voilà ! Si vous avez bien suivi toutes les étapes, vos instances sont toutes capables d’invalider leur cache grâce au multicast de AppFabric Service Bus !

A bientôt image

read more

[EN] [Windows Phone] Best practices for periodic tasks with background agents

As you probably already know Windows Phone 7.1 SDK (Mango) allows to create background agents to realize some operations when the application is not running.

There are two types of tasks : periodic tasks and long running tasks. This post is about periodic tasks that are executed each 30 minutes by the operating system. There are some limitations with the API that may be used in background agent. For further information please go to this MSDN page.

There are some constraints with background periodic tasks :

  • automatically executed by the OS each 30 minutes
  • the operation can’t exceed 25 seconds per run
  • if the phone switch to battery saver mode the background agent may not be executed
  • on some devices only 6 background agents may be planned simultaneously
  • agents can’t use more that 6MB of memory
  • agents have to be re-planned each 2 weeks
  • an agent that crashes two times is automatically disabled by the system

Avoid exception propagation in background agent

Because two crashes will disable the background agent exception handling is really important in the development. For example, common errors occur when using a WebRequest  : the agent creates an HTTP request, the connection is lost, the callback throws an exception that is uncatched ! To avoid this, you can use the following code :

try
{
var httpWebRequest = WebRequest.CreateHttp("http://www.monsite.com/service.aspx");
httpWebRequest.BeginGetRequestStream(asyncResult =>
{
try
{
var responseStream = httpWebRequest.EndGetRequestStream(asyncResult);
//do stuff with the response
}
catch (Exception exception)
{
OnError(exception);
}
}, null);
}
catch (Exception exception)
{
OnError(exception);
}

Schedule a background agent

Background agents are automatically disabled after two weeks : you have to re-schedule them. Windows Phone 7.5 has a centralized interface to manage all background agents that are available on the system so the user can disable an agent without run your application. If you try to schedule a periodic task with a disabled background agent an InvalidOperationException is thrown. You have to take care of this case and catch the exception as demonstrated bellow.

The first step is to get the periodic task by its name :

var periodicTask = ScheduledActionService.Find("AgentDemo") as PeriodicTask;

Next, delete the periodic task if it exists :

if (periodicTask != null)
{
try
{
ScheduledActionService.Remove(PeriodicTaskName);
}
catch (Exception) { }
}

Re-create the periodic task and set the description (it’s mandatory) :

periodicTask = new PeriodicTask("AgentDemo");
periodicTask.Description = "Agent description";

Try to schedule the periodic task :

try
{
ScheduledActionService.Add(periodicTask);
}
catch (InvalidOperationException ioe)
{
if (ioe.Message.Contains("BNS Error: The action is disabled"))
{
//agent is disabled for the application
}
}

Now the agent can be run by the system if it’s not disabled image

Memory usage limit

Background agent can’t use more than 6MB of memory. You can get the current memory usage using the following snippet :

var memory = DeviceStatus.ApplicationMemoryUsageLimit
- DeviceStatus.ApplicationCurrentMemoryUsage;

Hope this helps image

read more

[Windows Phone] Bonnes pratiques dans une tâche périodique avec un background agent

Vous le savez certainement déjà, la version 7.1 du SDK Windows Phone (Mango) offre la possibilité de créer des Background Agent, c’est à dire des tâches de fond exécutées par l’OS à interval régulier (en moyenne, selon certains paramètres, cf. plus bas).

Il existe deux types de tâches : périodique et traitement long. Dans ce post, nous nous intéresserons uniquement au premier type.

Dans ces tâches, il n’est pas possible de faire tout et n’importe quoi, seules certaines API sont autorisées (cf. cette page de la MSDN). Cependant des scénarios assez sympa sont rendus possibles, notamment la mise à jour des Live Tile.

Quelques éléments importants sur les backgrounds agents :

  • ils sont exécutés toutes les 30 minutes - il est possible d’y exécuter du code pendant 25 secondes, pas plus! - si le téléphone passe en mode d’économie de batterie, ils sont succeptibles de ne pas se lancer - sur certain device, seuls 6 background agents peuvent être actif en simultanés - ils ne doivent pas utiliser plus de 6MB de mémoire - ils doivent être replannifié toutes les deux semaines - un agent qui crash 2 fois est désactivé par l’OS

Cela fait pas mal de règles assez contraignantes mais il est vraiment possible de tirer profit de ces background agents en respectant quelques bonnes pratiques.

Eviter la propagation d’exception dans un Background Agent

Comme vu plus tôt, un background agent qui crash 2 fois est automatiquement désactivé par l’OS. Vous devez à tout prix être attentif à ne pas laisser passer d’exception. Un scénario de crash assez courant et la mauvaise gestion des connexions et appels réseaux.

Par exemple, votre background agent lance une requête HTTP vers un service, la connexion est coupée, l’exception n’est pas catchée dans la callback => l’agent plante (il vous reste une vie!).

try
{
var httpWebRequest = WebRequest.CreateHttp("http://www.monsite.com/service.aspx");
httpWebRequest.BeginGetRequestStream(asyncResult =>
{
try
{
var responseStream = httpWebRequest.EndGetRequestStream(asyncResult);
//gestion de la réponse
}
catch (Exception exception)
{
OnError(exception);
}
}, null);
}
catch (Exception exception)
{
OnError(exception);
}

Comme il est possible de le constater dans l’extrait de code ci-dessus, il est important d’intercépter les exceptions lors de la création de la requête HTTP, mais également lors de la récupération de la réponse, dans la callback !

Plannifier un Background Agent

Comme vu précédemment, les background agents sont automatiquement désactivés au bout de 2 semaines. Il est donc nécessaire de les replannifier fréquemment.

Lorsque l’on plannifie un background agent, il est possible que celui-ci ait été désactivé par l’utilisateur depuis l’interface du téléphone prévue à cet effet (dans les paramètres du téléphone). Dans ce cas une InvalidOperationException est levée lors de la tentative de plannification => il faut penser à catcher cette exception et éventuellement sauvegarder le fait que le background agent soit désactivé dans un fichier de configuration, par exemple.

La première étape consiste à récupérer une tâche périodique via son nom :

var periodicTask = ScheduledActionService.Find("AgentDemo") as PeriodicTask;

Ensuite, on la supprime si elle existe (il est préférable de la supprimer et de la replannifier, afin de palier à la désactivation au bout de 2 semaines!) :

if (periodicTask != null)
{
try
{
ScheduledActionService.Remove(PeriodicTaskName);
}
catch (Exception) { }
}

Il faut ensuite recréer la tâche et lui passer une description (obligatoire!) :

periodicTask = new PeriodicTask("AgentDemo");
periodicTask.Description = "Description de l'agent";

Ensuite on tente la plannification (gare à l’InvalidOperationException si l’utilisateur a désactivé le background agent dans les paramètres de Windows Phone!) :

try
{
ScheduledActionService.Add(periodicTask);
}
catch (InvalidOperationException ioe)
{
if (ioe.Message.Contains("BNS Error: The action is disabled"))
{
//mise à jour conf
}
}

Enfin, pour déboguer, il est possible de demander le lancement de l’agent après un temps donné (lorsque l’application est quittée via le bouton démarrer, pour concerver le débogueur attaché.)

ScheduledActionService.LaunchForTest("DemoAgent", TimeSpan.FromSeconds(10));

Votre agent est prêt et fonctionnel !!

Eviter de dépasser la limite mémoire autorisée

Une des règles à respecter dans un background agent est de ne pas dépasser 6MB de mémoire ! Si vous dépassez cette limite, l’agent est intérrompu et il est considéré comme planté, donc désactivé au bout de 2 fois. Tout au long du traitement, il est possible de tester la mémoire consommée par l’agent à l’aide de l’instruction :

var memory = DeviceStatus.ApplicationMemoryUsageLimit
- DeviceStatus.ApplicationCurrentMemoryUsage;

Voilà quelques règles à respecter pour faire des background agents qui resteront actifs !

A bientôt Winking smile

read more

[Azure] Invalidation de settings ou de cache à l’aide d’une clé de configuration

Dans ce post je vais vous expliquer une technique que j’ai utilisée pour invalider le cache / recharger les settings sur toutes les instances du rôle Web qui héberge mon blog (en vrai il n’y en a qu’une seule, mais je trouve l’astuce sympa image)

Le constat est simple : mes posts et les settings du blog (email, smtp, etc…) sont persistés dans le stockage table de Windows Azure. Afin d’éviter les aller-retours vers le stockage par table, je monte tout en cache mémoire (le nombre de transaction est facturé et en plus du coup ça envoi du lourd en terme de perf).

Problème : si je change un settings dans mon storage, comment est-ce que je demande à mon service de recharger les données ? Idem si pour une raison x ou y je souhaite vider le cache de posts, je dois avoir une solution. Si on se place dans un contexte Windows Azure multi-instances (cas très fréquent) c’est une couche de complexité supplémentaire qui se rajoute car il faut notifier chaque instance !

La solution la plus simple est d’utiliser un setting Windows Azure et de faire en sorte que vos instances écoutent les changements de configuration. Dès lors, il suffit de détecter le changement de la bonne clé de settings, ConfigVersion dans mon cas (ou CléBidon si vous voulez) et de reinitialiser vos différents services (ici mon service de cache et mon service de settings).

Tout cela se passe dans le fichier WebRole.cs du webRole, via l’événement Changed de RoleEnvironment :

public class WebRole : RoleEntryPoint
{
public override bool OnStart()
{
// For information on handling configuration changes
// see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
RoleEnvironment.Changed += OnRoleEnvironmentChanged;
return base.OnStart();
}

private void OnRoleEnvironmentChanged(object sender, RoleEnvironmentChangedEventArgs e)
{
if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange)) {
foreach (var change in e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()) {
if (change.ConfigurationSettingName == "ConfigVersion")
{
var cacheService = UnityRoot.Container.Resolve<ICacheService>();
cacheService.InvalidateCache();
var settingsManager = UnityRoot.Container.Resolve<ISettingsManager>();
settingsManager.Reload();
}
}
}
}
}

A bientôt image

Technorati Tags: [windows](http://technorati.com/tags/windows),[windows](http://technorati.com/tags/windows),[windows](http://technorati.com/tags/windows)
read more

[Livre] MVVM : De la découverte à la maîtrise

Un billet rapide pour vous présenter un ouvrage dédié au pattern MVVM et à son utilisation dans le cadre de projets WPF/Silverlight et Silverlight pour Windows Phone.

image

Coécrit par deux collègues et amis Jonathan Antoine et Jonathan Antoine, ce livre s’adresse à toutes personnes désireuses de découvrir MVVM ou d’approfondir leurs connaissances sur le sujet.

Bien que je n’ai pas encore lu tout l’ouvrage (sorti aujourd’hui même), j’ai eu l’occasion de participer à la relecture de certains chapitres de celui-ci et j’ai énormément apprécié l’approche des auteurs : du pratique, du concret et la réalité du terrain concernant MVVM !

Pour en savoir plus c’est par là : http://www.digitbooks.fr/catalogue/mvvm-antoine-lebrun.html

Bravo à Jon et Tom, et surtout, bonne lecture à tous !

A bientôt ! image

Technorati Tags: [livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre),[livre](http://technorati.com/tags/livre)
read more