mardi 19 octobre 2010

Sharepoint – Création d’une liste avec un content type spécifique (par code)

Voici le besoin :
Je dois créer une bibliothèque d’images spécifique, donc avec un type de contenu personnalisé.
La solution que j’ai choisi, c’est de faire 2 features:
  • Une pour le déploiement de tous les content types et des webparts avec un scope Site
  • Une autre pour la création de ma bibliothèque dans un sous-site choisi donc scope web

Je ne vais pas présenter le détail de la première feature.
Ce qu’il faut savoir, c’est qu’elle déploie des types de contenus.
Je ne montrerai pas non plus comment créer des solutions wsp pour le déploiement, je pars du principe que tout déploiement dans SP passe par ce biais.
Ma seconde feature, le fichier Feature.xml :
<?xml version="1.0" encoding="utf-8"?>
<Feature  Id="4d60eeca-55a8-4f6a-a49a-b036f616c1cc"
Title="Mon titre de feature"
Description="La description"
Version="1.0.0.0"
Hidden="FALSE"
Scope="Web"
DefaultResourceFile="core"
ReceiverAssembly="MonAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=0a51357f54252cab"
ReceiverClass="MonAssembly.MonReceiver"
xmlns="http://schemas.microsoft.com/sharepoint/">
<ActivationDependencies>
<ActivationDependency FeatureId="510155f1-4eaa-4b63-845f-03718f48fdbf"/>
</ActivationDependencies>
<ElementManifests>  
</ElementManifests>
</Feature>


On remarque 2 choses dans le Feature.xml:

  • On a une ActivationDependency, ici elle permet de vérifier que la Feature 1 est bien activée, sinon, on ne peut activer la feature 2.
    Logique, sinon, la création d’une liste héritant d’un content type inexistant posera un problème.
  • On fait appel à un SPReceiver, en effet, c’est lors de l’activation de la feature que l’on va créer la liste.

Le Receiver :MonReceiver.cs
public class MonReceiver : SPFeatureReceiver
{
private const String LIST_NAME = "maListe";
private const String LIST_DESC = "La desc";
private const String CONTENTTYPE_NAME = "MonContentType";

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
if (properties.Feature.Parent is SPWeb)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
SPSite site = web.Site;

try { SPList list = web.Lists[LIST_NAME]; }
catch //La liste n'existe pas, on va la creer
{
try
{
//Création de la list
Guid listId = web.Lists.Add(LIST_NAME, LIST_DESC, SPListTemplateType.PictureLibrary);
//on selectionne la lise ajoutée
SPList list = web.Lists[listId];
list.ContentTypesEnabled = true;
list.OnQuickLaunch = false;
list.EnableFolderCreation = false;
list.Update(); //Mise à jour de la liste avec les options

//Ajout du type de contenu souhaité pour la liste
SPContentType ct = web.AvailableContentTypes[CONTENTTYPE_NAME];
list.ContentTypes.Add(ct);

//On sélectionne le contentype précédent comme  l'unique CT de la liste
SPContentType[] ctToDisplay =  new SPContentType[1];
for (int i = 0; i < list.RootFolder.ContentTypeOrder.Count; i++)
{
if (list.RootFolder.ContentTypeOrder[i].Name == CONTENTTYPE_NAME)
{
ctToDisplay[0] = list.RootFolder.ContentTypeOrder[i];
}

}
list.RootFolder.UniqueContentTypeOrder = ctToDisplay;
list.RootFolder.Update();

}
catch (Exception ex) { throw ex; }
}
}
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
if (properties.Feature.Parent is SPWeb)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
SPSite site = web.Site;

try
{
SPList list = web.Lists[LIST_NAME];
if (list.ItemCount < 1)
{
list.Delete();
}
}
catch {}
}
}

public override void FeatureInstalled(SPFeatureReceiverProperties properties){ }

public override void FeatureUninstalling(SPFeatureReceiverProperties properties) { }
}


Ce que fait l’activation de la feature :

  • Elle crée la liste si celle-ci n’existe pas (de type PictureLibrary dans notre cas)
  • Elle ajoute le type de contenu souhaité pour la liste
  • Ensuite, on redéfini le type de contenu par défaut de la liste, via le RootFolder.UniqueContentTypeOrder
    Il s’agit d’une collection de SPContentType qui permet de définir l’ordre et le type de contenu par défaut du bouton “Nouveau” de la liste.

Lors de la désactivation de la feature, si la liste est vide, on la supprime.

Voilà, ça n’est pas plus compliqué.

vendredi 15 octobre 2010

Sharepoint – Webpart et ValidationGroup en WCM

Si vous déployez une webpart, contenant un formulaire avec validation, dans une page de publication, au moment de l’archivage de la page, vous obtenez le message suivant :

Cette page contient du contenu ou une mise en forme non valide. Vous trouverez plus d'informations dans les sections concernées.
Options :  Quitter sans enregistrer

La solution est de remplir tous les champs du formulaire pour satisfaire la validation : Bof, pas très productif et pour expliquer ça aux collaborateurs du website !!

L’idée, pour éviter ça, est de ne pas afficher le formulaire lorsque la page est en mode “Edition” :

WebPartManager wp = WebPartManager.GetCurrentWebPartManager(this.Page);
if (wp.DisplayMode == WebPartManager.BrowseDisplayMode)
{
Control control = this.Page.LoadControl(ASCX_PATH);
Controls.Add(control);
}
else
{
Controls.Add(new LiteralControl("Mode édition - Pas d'affichage du formulaire"));
}

Donc en mettant le code ci-dessus dans le “CreateChildControls” de la WebPart, en mode édition, on affiche un message au lieu du formulaire.

Après archivage, on visualise le formulaire.


Donc plus de problème de validation.

Sharepoint – Obtenir le SMTP Host de la config en code-behind

Pour obtenir le SMTP Host configuré dans notre ferme :

if (SPContext.Current.Site.WebApplication.OutboundMailServiceInstance != null)
{
//Obtient le SMTP host de "Outgoing e-mail settings"
smtp.Host = SPContext.Current.Site.WebApplication.OutboundMailServiceInstance.Parent.Name;
}

jeudi 14 octobre 2010

MOSS 2007 – Reverse proxy, site public et MOSS

Voici la configuration :

  • Une webapp étendue MOSS en WCM public sur le port 82 du IIS
  • Une url public externe www.monsite.fr
  • Une url interne intra.monsite.fr:82
  • une reverse proxy pour la publication
  • Les “acces mappings” de MOSS configurés

Jusqu’ici tout va bien.

La page à afficher contient une “Content Query Webpart”, en interne, pas de problème tout fonctionne.

En externe, ça se complique, la webpart ne fonctionne pas.

1ére solution:

La CQWP ne fonctionne pas avec un accès anonyme car le XSLT utilise la variable “SafeLinkUrl”, donc la modification de ItemStyle.xsl paraissait logique.
Voici un exemple de modifications clair : Content Query Web Part (CQWP) with Anonymous Access

Pour autant, ça ne fonctionne pas.

2ème solution

Une petite analyse de la response avec Fiddler et je m’aperçoit que la webpart à comme url : www.monsite.fr:82

Donc en ajoutant un “access mapping” sur la zone correspondante de type
Url interne : www.monsite.fr:82
Url public : www.monsite.fr

La CQWP fonctione.

Infos : Où se trouve les Access Mappings :

  • Ouvrez la console d’administration de Sharepoint
  • Opérations image

 

 

 

 

  • Rubrique Configuration globale
    image
  • Mappages des accès de substitution
  • image

Linq - Juste un exemple de concaténation de texte avec Aggregate

Pour mes problèmes de mémoire, voici un petit exemple de concaténation de texte avec Linq to Object et la méthode Aggregate :

var checkedValues = 
MaCheckBoxList.Items.Cast<ListItem>()
.Where(c => c.Selected)
.Select(c => c.Value);

//On vérifie qu'il y a bien des valeurs sélectionnées
String maString = MaCheckBoxList.Count() > 0
? checkedValue.Aggregate((c, next) => c + ", " + next)
: String.Empty;


lundi 20 septembre 2010

WPF– Application qui plante au démarrage – Erreur CLR20r3

Application en WPF, l’ensemble des tests sur le poste de développement fonctionne.

Parfait, donc je fais le setup et lance l’installation sur un XP SP3.
Ca fonctionne, tous les tests passent, donc prêt pour la production.
Et soudain, c’est le drame, l’appli plante dès le démarrage sous Seven.

Voici l’erreur :

Récipient d’erreurs , type 0
Nom d’événement : CLR20r3
Réponse : Non disponible
ID de CAB : 0
Signature du problème :
P1 : monitoringserver.exe
P2 : 1.0.0.0
P3 : 4c97529a
P4 : PresentationFramework
P5 : 3.0.0.0
P6 : 4a174fbc
P7 : 81d
P8 : 1f
P9 : System.InvalidOperationException
P10 :

Peut être un problème de références? Impossible à savoir.
Après plusieurs recherche sur le web, voici la solution qui m’a permis de repérer l’erreur :

Dans le App.xaml :

<Application 
x:Class="MonitoringServer.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"

StartupUri="MainWindow.xaml"
DispatcherUnhandledException="Application_DispatcherUnhandledException" >



Et le code-behind:



private void Application_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e)
{
Exception CurrentException = e.Exception;
while (CurrentException != null)
{
MessageBox.Show(CurrentException.Message);
CurrentException = CurrentException.InnerException;
}

}



Ainsi, dès le démarrage de l’application, des boites de dialogues s’affichent avec le détail de l’erreur.



Mon problème est corrigé et l’application fonctionne Sourire

Silverlight–Navigation–Rediriger vers une page

Ca peut paraitre idiot, mais j’ai mis un peu de temps à trouver et je n’est rien trouvé sur le web.

Mon problème, je suis dans une application de navigation Silverlight.
Je veux qu’une de mes vues soit celle par défaut, au démarrage.

Et bien, j’ai eu du mal à trouvé, pourtant, c’est tout bête :

private void ContentFrame_Navigated(object sender, NavigationEventArgs e)
{
if (String.IsNullOrEmpty(e.Uri.OriginalString))
{
this.ContentFrame.Navigate(new Uri("/MaView", UriKind.Relative));
}
}



C’est tout, il suffit juste de naviguer dans la frame Embarrassé