vendredi 3 avril 2015

Comment récupérer les rôles définis dans DNN

Pour récupérer les rôles de DNN, je pensais devoir utiliser le controller "RoleController", et bien non...

Voici un extrait de code, vous permettant de récupérer l'ensemble des rôles définis dans une instance de portail :
ArrayList roles = RoleProvider.Instance().GetRoles(portalId);

Un ArrayList n'est pas forcément des plus simple à utiliser, voici la même chose mais en initialisant un objet List<RoleInfo> :

List<RoleInfo> roles = RoleProvider.Instance().GetRoles(portalId).Cast<RoleInfo>().ToList();

mardi 31 mars 2015

Utiliser Telerik OpenAccess sans avoir à l'installer

Voici une méthode permettant d'utiliser Telerik OpenAccess sans avoir à l'installer. Cette méthode peut aussi être utilisée pour détacher votre projet de la version de Telerik installé sur votre poste.

L'intérêt ? Vous avez une dizaine de projets sur votre poste utilisant Telerik OpenAccess mais bien sur, tous ne vont pas évoluer de la même façon. A un moment donné vous mettrez forcément à jour votre version d'OpenAccess, mais que se passera-t-il pour vos projets ?

Si vos projets sont détachés de la version installée sur votre poste vous n'aurez pas de soucis, sinon attention aux effets de bords, et généralement on les découvre quelques mois après la mise à jour d'OpenAccess lorsque vous retournez sur un projet.

L'idée est donc d'avoir dans votre solution les fichiers OpenAccess vous permettant de compiler sans soucis de version installée sur votre poste. Vous trouverez toutes les infos dans cet article :

http://docs.telerik.com/data-access/developers-guide/integrating-data-access-in-your-solution/external-tools-howto-integrate-enhancer-msbuild

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.