SQL Server - Auto-ID Wert nach INSERT ermitteln 
Mittwoch, November 11, 2009, 05:22 PM
Heute hatte ich mal wieder das alte Problem, dass beim SQL Update eines gerade angelegten Datensatzes dieser nicht aktualisiert wurde, weil die automatisch vergebene ID der Auto-Increment Spalte sich nicht im bestehenden Objekt wiederfand.
Normalerweise muss ich mich ja damit nicht rumärgern, weil ich entweder einen OR-Maper verwende, der das alles regelt, oder GUIDS verwende, die ich ja schon vorher kenne. Aber hier war es mal simples ADO.NET und Auto-IDs. Also wieder recherchieren...
Und damit ich das nicht nochmal raussuchen muss - falls ich es vergessen sollte - hier das einfachste Vorgehen in C# für ein INSERT mit darauffolgendem UPDATE mit ADO.NET auf einem SQL Server:

Um die eben erzeugte ID beim INSERT zu erhalten genügt es, ein SELECT scope_identity() an das INSERT Statement zu hängen.
z.B.:

INSERT INTO Customer (Name, LastName)
VALUES ('Max', 'Mustermann')
SELECT scope_identity()



Dann natürlich nicht mehr ExecuteNonQuery() ausführen, sondern ExecuteScalar():


object ret = command.ExecuteScalar();
int id = Convert.ToInt32(ret);
customer.Id = id;



Dann bekommt man die eben erzeugte ID in einem Command wieder zurück, und dann klappts auch mit dem Update.

  |  Permalink   |  Related Link

SharePoint 2007 - Eigenen Custom Field Type erstellen 
Dienstag, September 22, 2009, 03:00 PM
Einen eigenen Custom Field Type zu erstellen ist eigentlich gar nicht so schwer, wenn man den richtigen Weg wählt. Das Thema ist zwar schon alt, und im Internet gibt es bereits einige Einträge zu diesem Thema, aber ich möchte hier einmal einen konkreten Anwendungsfall zeigen, bei dem solche eigenen Field Types wirklich Sinn machen.

Ein solcher Custom Field Type kann nach dem Einbinden in jeder Liste oder Dokumentenbibliothek als zusätzlicher Spaltentyp eingebunden werden:



Der erste Versuch, das vielversprechende WSPBuilder Visual Studio Template zu verwenden, schlug leider fehl, weil die Daten meiner ListBox sich nicht speichern ließen... Der Manuelle Weg, auf Basis des Microsoft Beispielcodes, funktioniert allerdings auch zufriedenstellend. Auf den Komfort eines deploybaren WSP-Files muss man dann zunächst zwar verzichten, aber zum Entwickeln geht es dafür wesentlich schneller.

Im Folgenden wird gezeigt, wie man eine eigene Listen-Spalte definiert, die im Edit-Mode über eine Multi-Select-Box gefüllt wird, in der Ansicht aber für jede Auswahl ein entsprechendes Bild anzeigt. Die Piktogramme werden aus einer fest definierten SharePoint Image-Library geladen:



Und so wird's gemacht:

1. Leeres Visual Studio Projekt anlegen.

2. Der Einfachheit halber eine Ordnerstruktur anlegen


TEMPLATE
TEMPLATE\CONTROLTEMPLATES
TEMPLATE\XML



Und eine Referenz zu Microsoft.SharePoint hinzufügen, für die Verwendung der Basisklassen.



3. Die Assembly signieren

Der Public Key Token wird später für die XML-Felddefinition benötigt.

4. Die Felddefinion anlegen

Für die eigene Felddefinion wird eine Klasse benötigt, die von einem der SharePoint Feld-Basistypen ableitet. Im Folgenden wird von SPFieldMultiLine abgeleitet, um große Textmengen in diesem Feld speichern zu können. Das neue Feld hat den Namen Symbol - das Wort sollte also überall durch einen eigenen Namen ersetzt werden ;)

SymbolField.cs Listing:

using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;

namespace SymbolFieldType
{
    public class SymbolField : SPFieldMultiLineText
    {
        public SymbolField (SPFieldCollection fields, string fieldName)
            : base(fields, fieldName)
        {
            ;
        }

        public SymbolField (SPFieldCollection fields, string typeName, string displayName)
            : base(fields, typeName, displayName)
        {
            ;
        }

        public override Microsoft.SharePoint.WebControls.BaseFieldControl FieldRenderingControl
        {
            get
            {
                BaseFieldControl control = new SymbolFieldControl();
                control.FieldName = this.InternalName;
                return control;
            }
        }

        public override string GetValidatedString (object value)
        {
            if (this.Required || value.ToString().Equals(string.Empty))
            {
                throw new SPFieldValidationException("Symbols not assigned");
            }
            return base.GetValidatedString(value);
        }

    }
}


5. Die Control-Definion für den neuen Typ anlegen

Die Control-Definion bestimmt das Verhalten und das Aussehen des neuen Feldes in der Editier-Ansicht. Diese Klasse ist eigentlich die "Code-Behind" Klasse des ascx-Files.



Hier wird dem Anwender eine Multi-Select Listbox angezeigt.

SymbolFieldControl.cs Listing:

using System.Configuration;
using System.Text;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;

namespace SymbolFieldType
{
    public class SymbolFieldControl : BaseFieldControl
    {
        #region [ Protected properties          ]

        protected ListBox symbolListBox;

        #endregion

        #region [ Overridden methods            ]
        
        protected override string DefaultTemplateName
        {
            get
            {
                return @"SymbolFieldControl";
            }
        }

        public override object Value
        {
            get
            {
                this.EnsureChildControls();
                return GetSelectedValues(this.symbolListBox);
            }
            set
            {
                this.EnsureChildControls();
                string selectedItemsString = (string)this.ItemFieldValue;
                foreach (ListItem i in symbolListBox.Items)
                {
                    if (i.Value.Length > 0 && selectedItemsString.Contains(i.Value))
                    {
                        i.Selected = true;
                    }
                }
            }
        }

        protected override void CreateChildControls ()
        {
            if (this.Field == null || this.ControlMode == SPControlMode.Display)
                return;
            base.CreateChildControls();

            this.symbolListBox = (ListBox)TemplateContainer.FindControl("symbolListBox");

            if (this.symbolListBox == null)
                throw new ConfigurationException("SymbolFieldControl.ascx is corrupt.");

            if (!this.Page.IsPostBack)
            {
                this.symbolListBox.Items.AddRange(new ListItem[]{ 
                  new ListItem(string.Empty, null), 
                  new ListItem("Ätzend", "Aetzend.png"), 
                  new ListItem("Brandfördernd", "Brandfoerdernd.png"), 
                  new ListItem("Explosiv", "Explosiv.png"), 
                  new ListItem("Flammbar 1", "Flamm1.png"),
                  new ListItem("Flammbar 2", "Flamm2.png"),
                  new ListItem("Flammbar 3", "Flamm3.png"),
                  new ListItem("Giftig", "Giftig.png"),
                  new ListItem("Leicht entzündlich", "LeichtEntzuendlich.png"),
                  new ListItem("Reizend", "Reizend.png"),
                });
                
                this.symbolListBox.SelectionMode = ListSelectionMode.Multiple;
            }
        }

        #endregion

        #region [ Private methods               ]

        private string GetSelectedValues (ListBox listBox)
        {
            StringBuilder selectedItems = new StringBuilder();
            foreach (ListItem item in listBox.Items)
            {
                if (item.Selected)
                {
                    selectedItems.Append(");
                    selectedItems.Append(item.Value);
                    selectedItems.Append("\">");
                }
            }
            return selectedItems.ToString();
        }

        #endregion
    }
}


Die gewählten Einträge der ListBox werden gleich als String von HTML Image-Tags gespeichert, um später in der Listen-Ansicht nicht das Problem zu haben, dass man mit CAML die Elemente zerlegen und zusammenbauen muss *grusel*. Sicher gibt es auch schönere Ansätze, aber in diesem Fall funktioniert es auch so.

6. Das ascx-Control zum Bearbeiten des Feldes anlegen

Im Ordner TEMPLATE\CONTROLTEMPLATES eine leere ascx-Datei (ohne Code-Behind) anlegen, und folgenden Codeschnipsel einfügen:

<%@ Control Language="C#" Debug="true" %>
<%@ Assembly Name="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=12.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c"
             Namespace="Microsoft.SharePoint.WebControls" %>

<SharePoint:RenderingTemplate ID="SymbolFieldControl" runat="server">
  <Template>
    <asp:ListBox ID="symbolListBox" runat="server"  />
  Template>
SharePoint:RenderingTemplate>


Wenn man eigene Controls baut sollte man darauf achten, dass hier der Typ des ASP.NET controls dem Element entspricht, das man in der Field-Control Definition angegeben hat. Hier muss also zusammenpassen:

<asp:ListBox ID="symbolListBox" runat="server"  />


und

protected ListBox symbolListBox;


7. Die XML-Felddefinion anlegen

im Ordner TEMPLATE\XML eine leere XML-Datei anlegen, und folgendes einfügen:

xml version="1.0" encoding="utf-8" ?>
<FieldTypes>
    <FieldType>
        <Field Name="TypeName">SymbolSelectionField>
        <Field Name="ParentType">NoteField>
        <Field Name="SQLType">ntextField>
        <Field Name="TypeDisplayName">Danger signField>
        <Field Name="TypeShortDescription">Custom symbol columnField>
        <Field Name="Sortable">FALSEField>
        <Field Name="Filterable">FALSEField>
        <Field Name="UserCreatable">TRUEField>
        <Field Name="ShowInListCreate">TRUEField>
        <Field Name="ShowInSurveyCreate">TRUEField>
        <Field Name="ShowInDocumentLibraryCreate">TRUEField>
        <Field Name="ShowInColumnTemplateCreate">TRUEField>
        <Field Name="FieldTypeClass">SymbolFieldType.SymbolField, SymbolFieldType, Version=1.0.0.0, Culture=neutral, PublicKeyToken=!Hier den eigenen Token einsetzen!Field>
        <RenderPattern Name="DisplayPattern">
            <Switch>
                <Expr>
                    <Column/>
                Expr>
                <Case Value="">
                Case>
                <Default>
                    <Column/>
                Default>
            Switch>
        RenderPattern>
    FieldType>
FieldTypes>


Der PublicKeyToken muss mit sn.exe -T MyCustomFieldType.dll aus der aktuellen Assembly ermittelt werden.

Erläuterungen:

"ParentType" gibt den internen zu verwendenen SharePoint Datentypen an. Note ist ein Text mit mehr als 255 Zeichen.
"SQLType" gibt den zu verwendenen Physikalischen Datentypen in der Datenbank an. Dies kann für den Note Typ nötig zu sein.

Die restelichen Field-Definitionen sollten selbsterklärend sein...

Wichtig ist natürlich der Abschnitt RenderPattern, in dem per CAML das Aussehen des Feldinhaltes in der Listenansicht und in der Detailansicht definiert wird. In diesem Beispiel wird der Inhalt einfach nur 1:1 ausgegeben, denn er ist ja bereits richtig formatiert:

<Default>
    <Column/>
Default>


8. Deployment

Ohne WSP-Datei, muss alles per Hand installiert werden. Das geht jedoch wesentlich schneller!

- Die kompilierte DLL des Projektes kommt in den GAC auf dem Webserver. Einfach mit dem Explorer hineinkopieren.

- Die ascx-Datei kopiert man in den Ordner ...\12\TEMPLATE\CONTROLTEMPLATES

- Und die XML-Datei kopiert man in den Ordner ...\12\TEMPLATE\XML

Wenn man jetzt im IIS den entsprechenden Application-Pool aktualisiert (recycle), sollte der neue Feld-Typ auch schon verfügbar sein!

Das ganze muss man bei einer Server-Farm natürlich für jeden FrontendWebServer machen. Dafür kann man sich aber eine kleine Batch-Datei schreiben...

Um den Feld-Typen zu deinstallieren, genügt es, die Assembly aus dem GAC zu entfernen und die beiden Dateien im Filesystem zu löschen.


Quellen:
http://wspbuilder.codeplex.com/Release/ ... seId=25962

  |  Permalink   |  Related Link

SharePoint 2007 - Custom List Form Attachments 
Dienstag, September 22, 2009, 02:41 PM
Über Custom List Forms kann man eigens angepasste Formulare für New/Edit/View für Listen oder Libraries erstellen.
Wenn man dann aber versucht, ein Attachment an einen Listeneintrag zu hängen, stellt man fest, dass es zunächst den einen oder anderen Fehler gibt, z.B.:

"This form was customized not working with attachment"

oder

"Can't move focus to the control because it is invisible, not enabled, or of a type that does not accept the focus."

oder der Button zum Editieren eines Elements fehlt völlig.

Natürlich gibt es für dieses bekannte Problem schon eine Lösung:
http://support.microsoft.com/?scid=kb%3 ... 3&y=14

Allerdings funktionierte es bei mir trotzdem nicht. Was war los?

Zum Einen benötigt man dafür nicht unbedingt den angegebenen Hotfix, sondern die Installation von SP2 sollte ausreichen.

Zum Anderen muss man darauf achten, dass man das ursprüngliche Standard-Formular



auf der Seite belässt aber über die WebPart-Eigenschaften schließt:





Wenn man das alte Formular löscht, lässt sich die Seite gar nicht mehr aufrufen. Wenn man es nur versteckt, bekommt man später einen JavaScript-Fehler.
Da der SharePoint Designer zudem bei mir einen Fehler im WebPart-Eigenschafts-Menü hatte, so dass ich das Menü nicht sehen konnte, musste ich die Einstellung im XML vornehmen und IsIncluded auf false setzen:

<IsIncluded>false</IsIncluded>

Danach klappt es auch mit den Attachments...

Quellen:
http://support.microsoft.com/?scid=kb%3 ... 3&y=14

  |  Permalink   |  Related Link

Javascript Fehler nach Installation von MOSS SP2 
Dienstag, September 22, 2009, 11:51 AM
Nach der Installation von SharePoint SP2 auf einem VirtualPC Entwicklungs-Image zeigte sich auf einmal das Problem, dass jegliches Submit von Formularen nicht mehr funktionierte. Es gab unterschiedliche JavaScript Fehlermeldungen beim Klick auf den Button, z.B.:

"WebForm_PostBackOptions is undefined"

Nach langem Suchen - unter anderem gab es viele Hinweise darauf, dass es sich um ein Problem mit httpModules und WebResource.axd handeln solle - fand ich den entscheidenden Kommentar in einem Blog.

Das Datum des VPC Images war einfach falsch! Es lag in der Vergangenheit, und MOSS SP2 mag offenbar keine falschen Zeitangaben im System - ein Schelm, wer böses dabei denkt ;)
Nach der Korrektur (und vorsichtshalber Neustart) lief alles wie gewohnt.

Also: Wenn dieser Fehler auftritt, zu allererst das Datum des Servers Prüfen, dann erst im IIS ISAPI-Filter verändern.


  |  Permalink   |  Related Link

SharePoint 2007 - Editierbare Themes und Vererbung auf neue Sites 
Freitag, August 21, 2009, 03:47 PM
Diese Themen sind zwar alles andere als neu, aber ich habe mir nochmal die Mühe gemacht, alle Schritte zusammenzutragen und aufzuschreiben, die nötig sind, um ein eigenes SharePoint Theme automatisch auf neu angelegte Sites anzuwenden und dieses Theme obendrein zur Laufzeit editierbar zu halten. (Ansonsten müsste man zum nachträglichen Ändern jede Site einzeln aktualisieren.)
Diese Methode ist meines Wissens nach die einzige Alternative zum Erstellen eigener, individuell gestalteter Templates - hat aber den Vorteil, dass das gesamte Portal immer noch 100% dem Standard entspricht und sich später einmal problemlos migrieren lassen sollte.

1. Custom Theme erstellen

Hier steht, wie man ein custom Theme nach regulärem Schema erstellt

Normale Themes haben allerdings einen entscheidenen Nachteil: Wenn ein Theme einmal auf eine Site angewendet wurde, werden weitere Veränderungen am Theme nicht mehr in der Site übernommen! Wer also 1000 Sites mit eigenem Theme hat und dann feststellt, dass die CSS Datei doch noch mal geändert werden muss, hat ein Problem.

Die beste Lösung hierzu, die im Netz gefunden habe, ist folgende:

1.1
Man erstellt einen neuen Ordner im System (z.B. "Customer_Theme") unter:
...\12\TEMPLATE\LAYOUTS\1033\STYLES\Customer_Theme
und kopiert den gesamten Inhalt des Theme-Ordners (z.B. "Customer") von
...\12\TEMPLATE\THEMES\Customer
in den neuen Ordner.

1.2
Man löscht den Inhalt des alten Theme-Ordners, bis auf die beiden Dateien
Customer.INF und
theme.css

1.3
Man editiert die theme.css und ersetzt den gesamten Inhalt durch fogende beiden Zeilen:

@import "/_layouts/1033/styles/Customer_Theme/mossExtension.css";
@import "/_layouts/1033/styles/Customer_Theme/theme.css";


Das führt dazu, dass das Theme lediglich die beiden angegeben CSS Dateien einbindet. Das Theme braucht man danach auch nie mehr zu ändern, denn Änderungen können jetzt in dem neuen Ordner vorgenommen werden und sind sofort sichtbar!


2. Projektstruktur in Visual Studio erstellen

Es empfiehlt sich, folgende Projektstruktur für das weitere Vorgehen anzulegen:
(Ausgehend von einer standard Class-Library)



Die DLL muss einen Strong Name haben.
Die DeployTTA.bat wird nicht unbedingt benötigt.

Alternativ kann auch mein Beispiel-Projekt verwendet werden:

Download ThemeActivator2008.zip

3. ThemeActivatorReceiver.cs implementieren

Dieser Part ist sehr einfach. Der unten stehende Code kann (bis auf den Namespace) 1:1 übernommen werden und muss nicht weiter angepasst werden:

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.IO;
namespace Company.SharePoint
{
public class ThemeActivatorReceiver : SPFeatureReceiver
{
private const string Property_DefaultTheme = "DefaultTheme";
private const string Property_ThemeToApply = "ThemeToApply";

public override void FeatureInstalled(SPFeatureReceiverProperties properties)
{
}

public override void FeatureUninstalling(SPFeatureReceiverProperties properties)
{
}

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
SPWeb web = properties.Feature.Parent as SPWeb;
if (site != null)
{
web = site.RootWeb;
}
if (web != null)
{
if (properties.Feature.Properties[Property_ThemeToApply] != null)
{
string theme = properties.Feature.Properties[Property_ThemeToApply].Value;
if (!string.IsNullOrEmpty(theme))
{
web.ApplyTheme(theme);
}
}
}
}

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
{
SPSite site = properties.Feature.Parent as SPSite;
SPWeb web = properties.Feature.Parent as SPWeb;
if (site != null)
{
web = site.RootWeb;
}
if (web != null)
{
if (properties.Feature.Properties[Property_DefaultTheme] != null)
{
string theme = properties.Feature.Properties[Property_DefaultTheme].Value;
if (!string.IsNullOrEmpty(theme))
{
web.ApplyTheme(theme);
}
}
}
}
}
}

Die Information, welches Theme zu setzen ist, kommt später aus dem XML des Features.


4. Theme Activator-Feature implementieren

Um ein Theme automatisch auf eine Site anzuwenden, muss zunächst ein neues Feature erstellt und deployed werden, das in der Lage ist, bei seiner Aktivierung der aktuellen Site das Gewünschte Theme zu verpassen.
(Später wird das zweite Feature benötigt, welches automatisch das erste Feature aktiviert.)

Hierzu die Datei ThemeActivator\feature.xml mit folgendem XML befüllen:

<Feature Id="86D25ADF-DE83-4238-8EFF-802AB22136C2"
Title="Customer Theme Activator"
Description="Applies the Customer Theme to this site."
Version="1.0.0.0"
Scope="Web"
Hidden="false"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/"
ActivateOnDefault="true"
ReceiverAssembly="Company.SharePoint, Version=1.0.0.0, Culture=neutral, PublicKeyToken=a32a55f152c86b83"
ReceiverClass="Company.SharePoint.ThemeActivatorReceiver"
>
<Properties>
<Property Key="DefaultTheme" Value="none" />
<Property Key="ThemeToApply" Value="Customer" />
</Properties>
</Feature>

Die hervorgehobenen Bereiche sind individuell anzupassen:

Feature Id: Hier eine eigene Guid einfügen
Feature Title: Eigener Name für das Feature (wird in der Feature Übersicht angezeigt)
Feature Description: Entsprechende Beschreibung
ReceiverAssembly: Name der DLL
PublicKeyToken: Der StrongName der Assembly (über "sn.exe -Tp" ermitteln)
ReceiverClass: Namespace+Name der Klasse in der ThemeActivatorReceiver.cs
Property ThemeToApply Value: Name des Themes, wie er in der .INF Datei angegeben wurde

Das Feature wird dann den Code aus dem ThemeActivatorReceiver aufrufen, und den Namen des Themes (hier "Customer") übertragen.


5. ThemeTemplateAssociation Feature implementieren

Das zweite Feature benötigt keinen .NET Code, sondern dient lediglich dazu, beim Anlegen einer neuen Site das erste Feature aufzurufen.
Diese Feature ist auch nicht in der Feature Übersicht sichtbar, sondern ist automatisch aktiv.

In [u]ThemeTemplateAssociation\feature.xml[/u] folgenden Code einfügen:

<Feature Id="FC472661-DE52-4fda-950A-970ED9EAE9E5"
Title="Customer Theme Stapling"
Description="Staples the Customer Theme Feature to all sites."
Version="1.0.0.0"
Scope="Farm"
Hidden="true"
DefaultResourceFile="core"
xmlns="http://schemas.microsoft.com/sharepoint/"
ActivateOnDefault="true"
>
<ElementManifests>
<ElementManifest Location="SiteAssociations.xml" />
</ElementManifests>
</Feature>

Die hervorgehobenen Bereiche wie zuvor entsprechend anpassen.

Danach in die ThemeTemplateAssociation\SiteAssociations.xml folgenden Inhalt einfügen:

<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
<!-- <FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="GLOBAL#0" /> -->
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSMSITE#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSPERS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="OSRV#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="STS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="STS#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="STS#2" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#2" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#3" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="MPS#4" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="WIKI#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLOG#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BDR#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="EAWF#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="OFFILE#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="OFFILE#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="PWA#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="PWS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSMSITE#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSTOC#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSTOPIC#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSNEWS#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSNHOME#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSSITES#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSBWEB#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSCOMMU#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSREPORTCENTER#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SPSPORTAL#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="SRCHCEN#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="PROFILES#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="CMSPUBLISHING#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLANKINTERNET#0" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLANKINTERNET#1" />
<FeatureSiteTemplateAssociation Id="86D25ADF-DE83-4238-8EFF-802AB22136C2" TemplateName="BLANKINTERNET#2" />
</Elements>

Die Angegebene Guid in jeder Zeile muss mit der Guid aus dem XML des ThemeActivator-Feature übereinstimmen.
Jede Zeile steht hier für einen Vorgegebenen Template Typ aus SharePoint, bei dessen Verwendung das Feature mit der Guid aktiviert wird.
Die auskommentierte Zeile mit GLOBAL#0 soll eigentlich alle Template-Typen mit einschließen, aber scheinbar funktioniert das nicht wie erwartet. Darum ist hier jeder Typ einzeln aufgelistet.


6. Das Installations-Batch erstellen

Der Inhalt der Install.bat sollte folgendermaßen aussehen:

@SET TEMPLATEDIR="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE"
@SET STSADM="C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\stsadm"
@SET GACUTIL="C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\gacutil"
%GACUTIL% -if bin\debug\Company.SharePoint.dll
xcopy /e /y TEMPLATE\* %TEMPLATEDIR%
%STSADM% -o InstallFeature -filename ThemeActivator\feature.xml -force
%STSADM% -o InstallFeature -filename ThemeTemplateAssociation\feature.xml -force
IISRESET

Im Grunde wird hier nur die DLL des Projektes in den GAC kopiert, die beiden Feature-Verzeichnisse in das FEATURES Verzeichnis von SharePoint kopiert und die beiden Features werden über stsadm.exe installiert.


7. Deployment

Anschließend das Projekt kompilieren, und über den Explorer die Install.bat aufrufen. Damit sollte alles erledigt sein.
Die Install.bat muss natürlich auf dem SharePoint Server selbst ausgeführt werden. Wenn man nicht dort entwickelt hat, am besten alles erstmal dorthin kopieren.

Anschließend sollte in SharePoint das neue "Customer Theme Activator" Feature sichtbar sein. Beim Erstellen einer neuen Site sollte jetzt auch bereits das angegebene Theme verwendet werden und das Feature automatisch aktiv sein.
Wenn dies nicht der Fall ist, wurde evtl. ein Template verwendet, das nicht der SiteAssociations.xml definiert wurde. Am besten man probiert es zunächst mit "Blank" und "Teamsite".

Wenn auf dem Server entwickelt wird, kann man sich auch ganz gewöhnlich mit VisualStudio an den w3wp prozess hängen und den Aufruf des ThemeActivatorReceiver debuggen.



So, und jetzt warten wir auf SharePoint 2010 und hoffen, dass dort alles viel einfacher wird, und wir all diese Merkwürdigkeiten nicht mehr benötigen.

Quellen:
http://www.heathersolomon.com/blog/arch ... hemes.aspx
http://grahamsibley.typepad.com/thought ... lly_a.html
http://www.grahamzero.com/blog/2008/05/ ... aplin.html

  |  Permalink   |  Related Link


Weiter