Vous consultez une page technique concernant le logiciel de gestion Mercator. Celle-ci contient des informations spécifiques destinées aux professionnels de Mercator. Souhaitez-vous être redirigés vers des informations plus générales ?


   Ne plus poser cette question

10 points d'attention pour une intégration Mercator ASP.net réussie

0000002957     -      07/01/2020

Nous énumérons ici quelques points d'attention afin d'optimiser un développement ASP.net effectué autour de Mercator, avec les outils de développement de Mercator.

 

1. L'environnement de Mercator ne doit être instancié qu'une seule fois, lors du démarrage de l'application web. En effet, ce démarrage prend un peu de temps (le même temps que le démarrage de l'application Mercator sur votre poste).

 

2. Pour obtenir les prix adéquats, le plus efficace est d'utiliser le BillingEngine et d'effectuer un InsertItem avec cet article pour ce client. Il suffit ensuite de récupérer les données de BillingEngine.LignesVRecords pour connaitre le prix unitaire, la remise, ... Si BillingEngine.LignesVRecords[...].PROMOSOLDE vaut true, alors cet article est en promotion.

 

3. Dans le prolongement du point précédent, utilisez cette signature de la méthode InsertItem. Le dernier paramètre à true permet de ne pas alimenter la DataTable BillingEngine.STOCK.

Zoom
billingEngine.InsertItem(drStock, billingEngine.LIGNES.Rows[nLigne], 1, true, true, true, true, true, true, true);

Dans le cas contraire, si vous utilisez un ou plusieurs paniers statiques pour calculer les prix des pages catalogues de votre site, cette DataTable contiendra finalement tous vos articles. La mémoire consommée par votre application web pourra dès lors rapidement devenir trop importante.

 

4. Cette signature présente aussi l'avantage de recevoir directement une DataRow correspondant à l'article (table STOCK). Ceci permet de regrouper la sélection des informations articles et de ne pas se connecter pour chaque article au serveur SQL. Effectuez donc un seul select ... from STOCK pour tous les articles d'une page catalogue en cours de présentation. Appelez ensuite InsertItem pour chaque DataRow de ce résultat.

Plutôt qu'effectuer un select * from STOCK, préférez ceci afin de ne pas alourdir les données extraites du serveur SQL :

Zoom
MercatorUi.Sig.Sig sigStock = MercatorUi.Sig._SigsStatic.SigByModule(MercatorUi.Sig._SigEnum.STOCK);
string reqSql = string.Format("select {0} from STOCK", sigStock.FieldsListForSelectRtrimNoBytes);

 

5. Ne perdez pas de vue qu'une application web est multi-thread. Or, un BillingEngine, puisqu'il repose essentiellement sur un DataSet, n'est pas thread-safe. Cela veut dire qu'il faut toujours prendre garde à ce qu'un seul thread ne puisse modifier un BillingEngine à la fois. Cela peut se faire facilement avec ce code qui va créer automatiquement une file d'attente.

Zoom
lock (billingEngine)
{
    // ... diverses modifications sur le BillingEngine
    billingEngine.UpdateAmounts();
}

 

6. Pour optimiser l'aspect "file d'attente", il peut être intéressant de travailler avec différents BillingEngines statiques et de les utiliser à tour de rôle.

Zoom
private int indexForBillingEnginesForGetInfoArtAndNotLoggedCustomer = 0;
private int maxForBillingEnginesForGetInfoArtAndNotLoggedCustomer = 3;
internal MercatorUi.Engine.Gescom.BillingEngine[] billingEnginesForGetInfoArtAndNotLoggedCustomer = ... (créer ici 3 BillingEngines) ;
public MercatorUi.Engine.Gescom.BillingEngine BillingEngineForGetInfoArtAndNotLoggedCustomer
{
    get
    {
        MercatorUi.Engine.Gescom.BillingEngine ret = billingEnginesForGetInfoArtAndNotLoggedCustomer[indexForBillingEnginesForGetInfoArtAndNotLoggedCustomer];
        indexForBillingEnginesForGetInfoArtAndNotLoggedCustomer++;
        if (indexForBillingEnginesForGetInfoArtAndNotLoggedCustomer >= maxForBillingEnginesForGetInfoArtAndNotLoggedCustomer)
            indexForBillingEnginesForGetInfoArtAndNotLoggedCustomer = 0;
        if (ret.PiedsVRecord.DATE != DateTime.Today)
            ret.PiedsVRecord.DATE = DateTime.Today;
        return ret;
    }
}

 

7. Une application ASP.net est susceptible d'être recyclée à tout instant. Un recycle est ici équivalent à un redémarrage de Mercator. Si vous maintenez le lien vers les paniers des internautes sous cette forme, il est nécessaire de s'assurer que le BillingEngine que l'on souhaite utiliser est encore ouvert. Si ce BillingEngine n'existe plus, il faudra le rouvrir via la méthode BillingEngine.InitExisting.

Zoom
bool isNew;
MercatorUi.Interfaces.IEngine engine;
MercatorUi.Engine.Gescom.BillingEngine billingEngine = null;
if ((HttpContext.Current.Session["CurrentEngineKey"] != null) && MercatorUi.Globals.EnginesUsedByExtApp.TryGetValue(HttpContext.Current.Session["CurrentEngineKey"].ToString(), out engine))
{
    billingEngine = (MercatorUi.Engine.Gescom.BillingEngine)engine;
    isNew = false;
}
else
{
    isNew = true;
    billingEngine = MercatorUi.Engine.Gescom.BillingEngine.InitExisting(MercatorUi.Engine.Gescom.Billing.TypeVAEnum.V, 4, Id, Journal, Piece);
    if ((billingEngine.DataSet != null) && (!billingEngine.ReadOnly))
    {
        billingEngine.PiedsVRecord.DATE = DateTime.Today;
        HttpContext.Current.Session["CurrentEngineKey"] = billingEngine.UniqueIdForExtApp;
    }
    else
        billingEngine = null;
}

 

8. Vous allez probablement stocker les références d'un panier (id, journal, piece) dans un cookie afin que lorsque l'internaute revient sur le site, il puisse à nouveau en disposer. Si ce panier n'est pas déjà ouvert dans le site web, cela se fait facilement grâce à la méthode BillingEngine.InitExisting. Par contre, il est nécessaire de tester la propriété ReadOnly de ce BillingEngine. En effet, ce document peut être en cours de modification par un utilisateur de Mercator. Dans ce cas, il ne sera pas possible de permettre à l'internaute de disposer de son panier pour le modifier.

 

9. Economisez les accès au serveur SQL et n'hésitez pas à mettre en cache des éléments souvent calculés de façon identique. Par exemple, le contenu de votre homepage, qui varie peu et qui est très souvent demandé. Cette mise en cache va permettre de diminuer le TTF de votre page (time to first byte) parce que plusieurs connexions au serveur SQL auront été économisées. Pour cela, il faut s'assurer d'utiliser une collection qui est aussi thread-safe. Par exemple, un ConcurrentDictionary :

Zoom
private static System.Collections.Concurrent.ConcurrentDictionary<string, CacheHolder> dicoCache = new System.Collections.Concurrent.ConcurrentDictionary<string, CacheHolder>();

Zoom
if (dicoCache.ContainsKey(MasterPage.Langue) && dicoCache.TryGetValue(MasterPage.Langue, out cacheHolder))
{
    cacheHolder.listCacheVuePar.Add(sessionId);
    return cacheHolder.cache;
}

Zoom
var newCacheHolder = new CacheHolder(ret);
dicoCache.AddOrUpdate(MasterPage.Langue, newCacheHolder, (k, v) => newCacheHolder);

 

10. Pour fonctionner correctement, Mercator attend les paramètres de culture suivants :

  • séparateur décimal : toujours le point
  • séparateur de milliers : toujours l'espace

Ceci peut être assuré par un code tel que celui-ci :

Zoom
public void ChangeCulture(string langue)
{
    CultureInfo ret;
    switch (langue)
    {
        case "N":
            ret = new CultureInfo("nl-NL");
            break;
        case "E":
            ret = new CultureInfo("en-US");
            break;
        case "D":
            ret = new CultureInfo("de-DE");
            break;
        default:
            ret = new CultureInfo("fr-FR");
            break;
    }
    if (ret.NumberFormat.NumberDecimalSeparator != ".")
        ret.NumberFormat.NumberDecimalSeparator = ".";
    if (ret.NumberFormat.NumberGroupSeparator != " ")
        ret.NumberFormat.NumberGroupSeparator = " ";

    System.Threading.Thread.CurrentThread.CurrentUICulture = ret;
    System.Threading.Thread.CurrentThread.CurrentCulture = ret;
}