SharePointCommunity
Die deutschsprachige Community für SharePoint, Microsoft 365, Teams, Yammer und mit Azure

Sponsored by

Willkommen im Forum Archiv.
Einträge sind hier nicht mehr möglich, aber der Bestand von 12 Jahren SharePoint-Wissen ist hier recherchierbar.




SPTimerJob nur für eine WebApplication aktivieren anstatt für alle - SharePoint Server 2010

Geprüfte Antwort Dieser Beitrag hat 6 Antworten

Ohne Rang
282 Beiträge
MStel erstellt 21 Dez. 2016 15:34
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

Hallo,
ich habe in C# einen SPTimerJob entwickelt, der listenelemente aktualisiert und in einer nicht sichtbaren Spalte einen wert einträgt. Der Job tut auch einwandfrei genau das, was er soll.

Anschließend habe ich die .wsp Datei aus dem Programverzeichnis genommen und mit den -stsadm addsolution- und deploysolution Befehlen auf unserem Testserver bereitgestellt.

Sowohl auf meinem lokalen Rechner als auch auf dem Testserver funktionierte diese Lösung wie gewünscht. Als ich genau die gleiche Prozedur auf dem Echtsystem anwenden wollte, ist mir in der Zentraladministration aufgefallen, dass ich einen Fehler gemacht habe.
Und zwar habe ich die Lösung für alle sich dort befindlichen Webanwendungen bereitgestellt und nicht nur für die ursprünglich angedachte Zielanwendung.
Auf den Testsystemen ist dies nicht aufgefallen, da meine Testanwendung die einzige WebApplication auf dem "Server" war, auf dem Echtsystem ist dies jedoch nicht so.

Mein Ziel ist es jetzt also, den Bereitstellungsprozess auf eine Anwendung, und dort auch nur auf eine SiteCollection zu spezifizieren.

Meine Frage ist nun, wo und wie realisiere ich dies.
Ich bin natürlich nicht unvorbereitet und habe mir dazu einige Gedanken gemacht, die für mich sinnvollsten Orte, meine Lösung zu realisieren wären:

- im Feature des C# Programmes mithilfe der Bereich(Scope) Eigenschaft, die aktuell auf WebApplication steht, (was für mich eigentlich Sinn ergibt, da das Ziel letztendlich auch eine WebApplication ist. Da auf dieser WebApplication auch nur eine SiteCollection mit einer TopLevel Site angelegt ist und auch zukünftig keine weiteren geplant sind, halte ich es für sinnvoll, als Scope WebApplication und nicht Site zu verwenden, wenn dies aber die offensichtliche Ursache für den Fehler ist, lasse ich mich gerne eines besseren belehren)

- innerhalb der override Methode, in der ich mich im Objektmodell "herunterhangele" und die Zielsite verwende, oder

- in Powershell beim bereitstellen der Lösung via stsadm deploysolution?

Sowie sich mir die nächste frage stellt: Muss ich die Ziel URL schon im C# Code hart kodiert hinterlegen, oder lässt sich wenn man an dieser stelle alles richtig konfiguriert (site beispielsweise über den Titel der Websitecollection festlegen) das bereitstellen komplett über die PowerShell Befehle (stsadm) regeln?

Eine Hartkodierte URL im Code wäre sehr unvorteilhaft, da die Lösung auf mehreren Webanwendungen und Serverfarmen funktionieren sollte.

Zur Verdeutlichung meines bisherigen Vorgehens hier meinen Code:
Powershell:
stsadm -o addsolution -filename $wspFileName
stsadm -o deploysolution -name UpdateSolution.wsp -immediate -allowgacdeployment -force

C# im Event Receiver:
 public override void FeatureActivated(
    SPFeatureReceiverProperties properties)
        {
            SPWebApplication webApplication =
                (SPWebApplication)properties.Feature.Parent;
          ...
       }

C# Methode mit der Programmfunktionalität: (wird aus der override Methode aufgerufen)
public void UpdateColumn()
        {
            SPWebApplication webApp = this.Parent as SPWebApplication;
             int m = 0;
             int counter = 0;
            foreach (SPSite siteOfWeb in webApp.Sites)
            {
                if (webApp.Sites[m].RootWeb.Title == "MeineSeite")
                {
                    counter = m;
                }
                m++;
            }
            using (SPSite site = new SPSite(webApp.Sites[counter].Url))
            {
                using (SPWeb web = webApp.Sites[0].RootWeb)
                {                    SPList listTest = web.Lists["Testliste"];
                }
   usw...
  }

ich bin an dieser stelle wirklich etwas überfragt, es ist auch viel Code und es sind viele Schrauben an denen ich für den TimerJob drehen musste, damit dieser überhaupt mal fehlerfrei das tut, was ich wollte.

Ich wäre um einen Lösungshinweis bzw. Schub in die Richtige Richtung sehr dankbar.

Mit freundlichen grüßen

mstel



 

Alle Antworten

Ohne Rang
19231 Beiträge
Andi Fandrich Als Antwort am 21 Dez. 2016 16:17
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

Im Grunde hast Du das meiste schon: für sowas nimmt man ein WebApp-Feature und in dessen Activating erzeugt man den Timer und bindet ihn an Feature.Parent (also an die WebApp). Und bitte im FeatureDeactivate auch wieder entfernen.

Im Code des Timers kannst Du dann auch wieder über Parent auf die WebApp zugreifen und es bleibt die Frage nach der SiteCollection. Entweder die relative URL ist in allen Systemen identisch, dann kannst Du die Site mit Hilfe der URL der WebApp plus dem relativen Teil instanzieren.

Falls es ganz flexibel sein soll, braucht man eine Möglichkeit Einstellungen zu speichern. Dazu eigen sich z.B. die an vielen Stellen verfügbaren PropertyBags zu verwenden. Oder man erstellt gleich eine eigene Klasse abgeleitet von SPPersistedObject und hängt das an SPFarm. Die Einstellung kann man dann per PowerShell speichern oder auch komfortabel über eine eigene Page in der Zentraladministration.

Viele Grüße
Andi
af @ evocom de
Blog
Ohne Rang
282 Beiträge
MStel Als Antwort am 22 Dez. 2016 09:32
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

[quote user="Andi Fandrich"]

Und bitte im FeatureDeactivate auch wieder entfernen.

[/quote]
Das habe ich gemacht, ja.

[quote user="Andi Fandrich"]

Entweder die relative URL ist in allen Systemen identisch

[/quote]
Ist sie nicht, lediglich der Titel der SiteCollection bzw. der SiteCollectionName der in der URL hinter der immer unterschiedlichen Webanwendung steht sind jedesmal gleich.

 [quote user="Andi Fandrich"]

Oder man erstellt gleich eine eigene Klasse abgeleitet von SPPersistedObject und hängt das an SPFarm. Die Einstellung kann man dann per PowerShell speichern oder auch komfortabel über eine eigene Page in der Zentraladministration.

[/quote]

Ich habe bereits eine solche Settings Klasse, die vom PersistedObject erbt erstellt:

public class mySettings : SPPersistedObject
{
    public static string SettingsName = "mySettings ";

    public mySettings () { }
    public mySettings (SPPersistedObject parent, Guid id)
        : base(SettingsName, parent, id) { }
}

Und diese Settings dort, wo meine Funktion die ich entwickelt habe ist abgerufen:

public override void Execute(Guid targetInstanceId)
        {
            mySettings jobSettings =
                this.WebApplication.GetChild<mySettings>(
                    mySettings.SettingsName);

            if (jobSettings == null)
            {
                return;
            }

            UpdateColumn(); //methodenaufruf der funktionalität
        }

Aber zurück zu deinem Vorschlag; Wie hänge ich dieses objekt an eine Farm? ist die Stelle weiter oben, an der ich this.WebApplication.GetChild mache eventuell die Ursache? Darüber hinaus: wie speichere ich die Einstellung per Powershell?

Mit freundlichen Grüßen

Mstel

Ohne Rang
929 Beiträge
Thomas Östreich Als Antwort am 22 Dez. 2016 09:54
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

Hallo Mstel,

ich würde um genau die SiteCollection zu bekommen die du benötigst mit SPWebApplication.QueryFeature arbeiten, denn wenn du deine Liste über ein Feature bereitstellst bekommst du alle SPSite/SPWeb Objekt (je nach Feature Scope) wo dein Feature aktiv ist.

Hast du jetzt mehrere Sites wo dein Feature aktiv ist würde ich die spezifische Konfiguration in die Properties vom Web speichern.

Hast du eine globale Konfiguration würde ich diese einfach im TimerJob speichern dies kann auch ein "mySettings" Objekt sein.

DeinTimerJob

- Variable mySettings als "Persisted"

- Property "MySettings" (Getter/Setter)

...

Dann kannst du dir ganz einfach deinen TimerJob über die Powershell holen und Eigenschaften anpassen und wieder über Update speichern. Generics funktionieren in Powershell nur über Reflection und das macht kein Spaß alternativ kann man auch eigene SP CmdLets bereitstellen aber der richtige Weg wäre eine Property in deiner JobDefinition.

Ohne Rang
282 Beiträge
MStel Als Antwort am 23 Dez. 2016 10:04
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

[quote user="Thomas Östreich"]

Hallo Mstel,

ich würde um genau die SiteCollection zu bekommen die du benötigst mit SPWebApplication.QueryFeature arbeiten, denn wenn du deine Liste über ein Feature bereitstellst bekommst du alle SPSite/SPWeb Objekt (je nach Feature Scope ) wo dein Feature aktiv ist.

[/quote]

Was wäre wenn ich als Scope eine Site auswähle? Ließe sich der TimerJob dann dennoch in vollem Funktionsumfang auf mehrere WebApplications übertragen?

Ohne Rang
929 Beiträge
Thomas Östreich Als Antwort am 23 Dez. 2016 10:22
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

Verstehe deine Frage nicht genau. Da du über die Instanz der Webanwendung QueryFeature ausführst bekommst du auch immer nur die SPSite/SPWeb Objekte die in dieser Webanwendung enthalten sind. 

Ohne Rang
282 Beiträge
MStel Als Antwort am 23 Dez. 2016 12:35
SchlechtSchlechtIn OrdnungIn OrdnungDurchschnittDurchschnittGutGutSehr gutSehr gut

okay ich werde es ausprobieren. danke vielmals

frohe weihnachten und guten rutsch :)

mstel