jeudi 12 février 2015

Erreur 405, lors d'un appel Ajax avec le verb DELETE


Lors d'un appel Ajax à une web API avec le verbe DELETE, j'obtenais en retour une erreur 405 (Method Not Allowed).

Voici un extrait du code que j'utilise :

$.ajax({
    url: "/.../API/.../DeleteForm?" + $.param({ id: form.id }),
    type: "DELETE",
    contentType: 'application/json',
    success: function (result) {
    ...
    },
    error: function (result) {
    ...
    }
})
Après quelques recherches je me suis aperçu que ce problème pouvait provenir de la présence de WebDAV qui semble interférer mon appel.

Une solution consiste à désinstaller WebDAV...rien que ça. Sinon une autre solution consiste à désactiver les modules WebDAV au niveau de votre site. Pour cela vous pouvez utiliser le code suivant dans votre fichier web.config :
<system.webServer>
  <modules>
    <remove name="WebDAVModule" />
  </modules>
  <handlers>
    <remove name="WebDAV" />
  </handlers>
</system.webServer>
Et avec cela plus de soucis.

mardi 10 février 2015

Comment utiliser RequireJS sur un site DNN

Voici un sujet pour lequel je n'ai jamais réussi à trouver d'informations auprès de mon ami "Google". Après pas mal de tâtonnement, j'ai, il me semble, trouvé une solution à peu près convenable.

La notion de "component" sous Knockout

J'ai décidé de me pencher sur ce sujet lorsque j'ai découvert la notion de "component" sous Knockout. Cette notion permet de faire des développements Javascript modulaires, ce qui signifie plus de souplesse, plus facile à maintenir... voici un lien vous présentant un peu le sujet : http://knockoutjs.com/documentation/component-overview.html.
Quel est le lien avec RequireJS ? La modularité. Comme je le disais plus haut, vous développez de façon modulaire, chaque module peut être lié à d'autres modules. Comment gérer ces liens et comment faire en sorte que lorsque vous décidez d'utiliser un "component" tous les "components" liés soient bien récupérer par le client ?
C'est là que la puissance de RequireJS prend toute son ampleur.

Le chainage des "components" avec RequireJS

Sur chaque "component" vous allez définir les autres "components" devant être récupérés pour pouvoir fonctionner. Chacun des "components" récupérés ayant eux-mêmes d'autres "components" de référencés. Il se crée ainsi un chainage entre "components". Vous n'avez plus besoin de vous inquiéter si telle ou telle librarie JS a bien été intégrée dans le "header", tout ce fait automatiquement et seuls les éléments nécessaires sont récupérés.

Chargement de RequireJS dans DNN

RequireJS est donc essentiel pour un développement JS modulaire. Maintenant il ne nous reste plus qu'à le charger sur notre site DNN mais voilà...ce n'est pas si simple que cela : RequireJS ne doit être chargé qu'une seule fois.
Sous DNN nous avons l'habitude travailler avec des modules qui sont indépendants les uns des autres, nous aurions donc pu imaginer utiliser RequireJS dans chaque module...malheureusement cela n'est pas possible.
RequireJS n'est pas une librairie JS comme les autres, en effet, lors de la mise en place de la balise SCRIPT permettant de charger RequireJS il faut faire référence à un fichier de configuration qui sera exécuté une fois RequireJS chargé sur le client. On ne peut définir qu'un seul fichier de configuration par page. Donc imaginer monter une instance de RequireJS par module n'est pas possible (où en tout cas je n'ai pas trouvé comment le faire).

Un SKINOBJECT pour charger RequireJS

Je suis donc parti sur la création d'un SKINOBJECT pour charger sur mes pages ma librairie RequireJS. Ce SKINOBJECT est ensuite déposé sur les SKIN où je souhaite utiliser cette librairie.

Voici donc le code C# de mon SKINOBJECT :

    public partial class View : DotNetNuke.UI.Skins.SkinObjectBase
    {
        protected override void OnInit(EventArgs e)
        {
            LiteralControl javascriptRef = new LiteralControl("<script type='text/javascript' data-main='/PathToConfigFile/default.js' src='/PathToLibrary/require.js'></script>");

            Page.Header.Controls.Add(javascriptRef);
        }
    }
Ici, j'insère une balise script dans le "Header" de ma page. Cette balise script pointe vers deux fichiers : "default.js" et "require.js".
Le premier ("default.js"), correspond au fichier de configuration exécuté par RequireJS dès son chargement. Vous trouverez plus loin un descriptif du contenu de ce fichier.
Le second ("require.js") est ni plus ni moins que la librairie RequireJS.

Voici le contenu du fichier "default.js" :
require.config({
    baseUrl: '/DesktopModules',
    paths: {
        "knockout": 'PathToKnockout/knockout',
    },
});


require(["knockout"], function (ko) {
    $(document).ready(function () {
        $.event.trigger("knockoutReady")

        setTimeout(function () {
            ko.applyBindings();
        }, 10);
    });
});
Ce fichier de configuration permet de définir l'URL de base de l'ensemble des chemins utilisés dans RequireJS par la suite ainsi que le chemin d'accès à la librairie "Knockout" (ce chemin étant relatif à la baseUrl s'il ne commence pas par "/").

La seconde partie de ce fichier, permet de mettre en place le Binding de Knockout. Pour cela j'utilise 2 astuces :
  • je lève un événement "knockoutReady" que j'utiliserais dans mes modules utilisant des "components" Knockout pour charger ces derniers.
  • je fais un "applyBindings" en asynchrone pour "binder" les viewModels de mes futurs modules.
Avec cela je suis fin prêt pour créer mes modules avec des "components" dans tous les sens.