Beim Debuggen von eigenen BDC Modellen in Visual Studio 2010 ist mir aufgefallen, dass die Business Connectivity Services (BCS) von SharePoint 2010 nicht sehr effizient implementiert sind.
Das Anzeigen eines einzelnen ListItems im Browser (DispForm.aspx Seite) resultiert beispielsweise in zwei Aufrufen der Finder Methode (Read List) und zusätzlich in einem Aufruf der Specific Finder Methode (Read Item).
Komplettes Beispiel: (anhand der Customer Tabelle der Northwind Datenbank)
Zugriff auf die Daten über den Browser
| Aktion |
Browser |
BDC Model Methoden |
|
|
|
| Read List |
ReadList.aspx |
ReadList |
|
|
|
| View Item |
DispForm.aspx |
ReadList |
|
|
ReadList |
|
|
ReadItem |
|
|
|
| Edit Item |
EditForm.aspx |
ReadList |
|
|
ReadList |
|
|
ReadItem |
|
|
|
| Edit Item (Save) |
EditForm.aspx |
ReadList |
|
|
ReadList |
|
|
ReadItem |
|
|
ReadItem |
|
|
ReadItem |
|
|
Update |
|
|
ReadList |
|
|
|
| New Item |
NewForm.aspx |
ReadList |
|
|
|
| New Item (Save) |
NewForm.aspx |
ReadList |
|
|
Create |
|
|
ReadList |
|
|
|
| Delete Item |
|
ReadItem |
|
|
Delete |
|
|
ReadList |
Bemerkung: Bei "Edit Item" werden die Daten zuerst im Browser geladen. Nach der Daten-Eingabe des Benutzers werden die Daten gespeichert (Save).
Zugriff auf die Daten über das Client Object Model (Silverlight)
| Aktion |
BDC Model
Methoden |
| |
|
| ReadList |
ReadList |
| |
|
| Update |
ReadItem |
| |
ReadItem |
| |
ReadItem |
| |
Update |
| |
ReadItem |
| |
|
| Create |
Create |
| |
ReadItem |
| |
|
| Delete |
ReadItem |
| |
ReadItem |
| |
Delete |
Bemerkung: Nachdem die Finder Methode ausgeführt wurde und alle resultierenden ListItems lokal in der SilverlightApplikation zwischengespeichert worden sind, ist es nicht nötig erneut die Specific Finder Methode auszuführen, um ein einzelnes ListItem zu lesen.
Zusammenfassend kann man festhalten, dass die Methode "Browser" nicht sehr effizient ist. Über Silverlight und das Client Object Model gelingt es dem Entwickler effizienter auf die Daten zuzugreifen und diese zu verwalten.
Randnotiz: Die hier gezeigten Ergebnisse basieren auf Beta-Produkten von Microsoft. Nach der Veröffentlichung von SharePoint 2010 werde ich die Aussagen überprüfen und nötigenfalls korrigieren. Auf jeden Fall hat Brad Stevenson von Microsoft angekündigt, dass die Release Version von SharePoint 2010 optimiert sein werde und die externen Daten effizienter verwaltet.
Eine Frage, die letzthin aufgetaucht ist, lautet:
Wie kann ich in einer Silverlight Applikation den aktuell angemeldeten Benutzer ermitteln?
Es gibt von mir aus gesehen zwei Lösungen:
Die klassische Lösung:
Die Web Applikation resp. die ASPX Seite, die die Silverlight Applikation hostet, übergibt den Namen des angemeldeten Benutzers über die Initialisierungs Parameter an die Silverlight Applikation:
Mit dieser Anweisung wird der aktuell angemeldete Benutzer der Silverlight Applikation zur Verfügung gestellt:
<param name="Initparams" value="CurrentUserIdentity=<%=HttpContext.Current.User.Identity.Name%>" />
Im Application_Startup Event der App Klasse kann man über das StartupEventArgs Objekt das InitParams Dictionary abfragen.
Siehe auch: http://www.codeproject.com/KB/silverlight/SL3WindowsIdentityName.aspx
Die SharePoint Lösung:
Falls die Silverlight Application in SharePoint 2010 gehostet wird, ist die Abfrage nach dem aktuell angemeldeten Benutzer noch einfacher:
1. In dem Silverlight Projekt eine Referenz auf die SharePoint Assemblies erstellen
Pfad: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\LAYOUTS\ClientBin
Assemblies: Microsoft.SharePoint.Client.Silverlight.dll und Microsoft.SharePoint.Client.Silverlight.Runtime.dll
2. In der C# Klass ein using hinzufügen...
using Microsoft.SharePoint.Client;
3. ...und den nötigen Code dazu schreiben:
Über ClientContext.Web.CurrentUse.LoginName kann der aktuelle Benutzer ermittelt werden.
Wichtiger Hinweis zur SharePoint Lösung:
Die Frage ist, ob ich mit dem Namen des Benutzers wirklich viel
anfangen kann?
Ein wichtiger Grundsatz in SharePoint ist es, nur diejenige Objekte (Sites, Liste, Items, ...) im Browser anzuzeigen, auf denen der Benutzer mindestens Leserechte hat.
Dieser Grundsatz in Silverlight umzusetzen ist ebenfalls möglich:
Die ClientContext Klasse von SharePoint 2010 erlaubt es, die Benutzer-Rechte von allen SharePoint Objekten abzufragen.
Über sogenannte BasePermissions, RoleAssignments und RoleDefinitions lässt sich herausfinden, welche Objekte der Benutzer sehen und/oder verändern kann.
Siehe auch: http://blogs.technet.com/speschka/archive/2009/11/01/using-the-sharepoint-2010-client-object-model-part-5.aspx
In meinem Vortrag: "Line of Business Applikationen mit SharePoint 2010 und Silverlight 4" ist in der Demo mit dem BDC Model und den External Content Types ein Schritt von mir nicht klar kommuniziert worden:
Wie kommt man in Visual Studio 2010 überhaupt zu einem BDC Model für SharePoint 2010?
Ganz einfach:
1. Visual Studio 2010 starten
2. In der Start Page auf "New Project..." klicken
3. Unter den vorinstallierten Templates SharePoint 2010 auswählen
4. Das Template "Business Data Connectivity Model" auswählen
5. [Ok] drücken, um das Projekt zu erstellen
6. Auf dem nächsten Dialog eine SharePoint URL angeben, wohin das BDC Model deployed werden soll
Fertig. Erstellt wird eine Visual Studio Solution mit einem Class Library Projekt.
In dem Projekt enthalten ist ein BDC Model "BdcModel1" mit einer vordefinierten Entität: "Entity1"
Generiert wird automatisch der Code für die Entität: Entity1.cs und die Service Klasse: Entity1Service.cs.
Wichtiger Hinweis:
Auch wenn man beim Erstellen der Visual Studio Solution als Target Framework ".NET Framework 4" angegeben hat, wird im soeben erstellen Projekt fix das Target Framework ".NET Framework 3.5" definiert! Warum? Weil SharePoint 2010 auf dem .NET Framework 3.5 SP1 basiert.
Siehe auch: http://social.msdn.microsoft.com/Forums/en/sharepoint2010general/thread/4be4d224-0a38-4ed3-95c9-d2c6bd1248d7
Was bedeutet das nun für uns Entwickler?
Beispielsweise, dass das Entity Framework 4.0 (mit der Möglichkeit POCO Entitäten zu erstellen) aussen vor bleibt... Leider!
Siehe auch: http://blogs.msdn.com/adonet/archive/2009/05/21/poco-in-the-entity-framework-part-1-the-experience.aspx
SharePoint gilt allgemein nicht gerade als Rakete unter den (Web-) Applikationen. Mit ein paar 10-tausend Items in einer Liste wird eine Abfrage resp. View bereits quälend langsam aufgebaut.
Was nun? Wir haben ja den SQL Server und die Business Connectivity Services (BCS) von SharePoint 2010. Nutzen wir also die Tools:
Mit SharePoint Designer 2010 "schnell" einen External Content Type resp eine External List erstellen. Wars das?
Nein! Eine echte Performanc-Steigerung wird hier noch nicht erreicht, da SharePoint im Hintergrund immer noch zuerst alle Items lädt, bevor ein View-Filter angewendet werden kann.
Eine Lösung sind sogenannte Finder Methoden mit Filter Deskriptoren. Hier ein Beispiel:
Der Screenshot wurde im BDC Model Designer inerhalb von Visual Studio 2010 gemacht. Der generierte C# Code sieht dann so aus:
Mit geeignetem SQL Code (resp. LINQ to Entities und dem Entity Framework) kann nun eine optimale Datenbank Abfrage erstellt werden, die Daten unglaublich schnell filtert.
Nachdem das BDC Modell deployt und in SharePoint Designer eine External List erstellt wurde, stehen uns die Filter Kriterien auch in den Views zur Verfügung:

Mit diesem Filter werden alle Personen mit "meier" im Namen und "zürich" als Ortschaft gefunden. Effektiv wird mit dem LIKE Operator gearbeitet. D.h. es werden auch Personen mit dem Namen: "Birchmeier" gefunden.
Interessant ist, wenn man die Seite resp. die View mit dem SharePoint Designer öffnet. Im CAML Query stösst man wieder auf den Methoden-Namen (siehe früherer Blog-Post hier):

Diese Information kann man auch ausnutzen, wenn man mit selbst erstellten Programmen (beispielsweise mit Silverlight Applikationen) auf SharePoint Daten zugreifen will.
Fazit: "Das" sind schnelle (SharePoint-) Abfragen! Alles andere ist langsam... 
Hier eine (unvollständige) Liste von SharePoint Produkten von Drittherstellern, die den Sprung in die 2010er Version geschafft haben:
PointFire
2010 von IceFire Studios Corp.
http://icefire.ca/Web/products.aspx
<< PointFire 2010 alleviates
this risk by giving you a powerful framework and "out-of-box"
multilingual user
interface in a plug and play solution that enables you manage your
multilingual
content in one location where all your users can work together in the
language
of their choice! PointFire also greatly speeds up the management of your
multilingual user interface. >>
Nintex Workflow 2010
http://www.nintex.com/en-US/Products/Pages/SPS2010Products.aspx
<< Nintex Workflow 2010 offers functional and feature
rich SharePoint workflow to your organization. It takes the
powerful-yet-easy design, deployment, management, and integration
features of Nintex Workflow 2007 to the SharePoint 2010 platform, with
improved process monitoring, extensibility, and designer productivity. >>
SharePoint Business Data List Connector (BDLC) von Layer2
http://www.layer2.de/en/community/FAQs/BDLC/Pages/Feature-comparision-sharepoint-external-list.aspx
<< Although the SharePoint 2010 External List is a great step forward in
SharePoint data integration features, it is not a REAL SharePoint list -
as the SharePoint BDLC List definitely is. >>
DocAve von AvePoint
http://eu.avepoint.com/sharepoint-products
<< The award-winning DocAve Software Platform is a comprehensive suite of
products for Microsoft SharePoint infrastructure management and
protection. >>
Weitere werden sicher folgen...
Wenn man aus Silverlight 4 heraus versucht auf eine externe Liste zuzugreifen, um alle ListItems zu lesen, wird überraschenderweise diese Exception geworfen:
Microsoft.SharePoint.Client.ServerException: The given key was not present in the dictionary.
Code-Snippet (funktioniert nicht mit externen Listen):
using (ClientContext context = ClientContext.Current ?? new ClientContext("<<ServerUrl>>"))
{
Web site = context.Web;
context.Load(site.Lists);
List list = site.Lists.GetByTitle("<<ListName>>");
context.Load(list);
items = list.GetItems(CamlQuery.CreateAllItemsQuery());
context.Load(items);
context.ExecuteQueryAsync(Succeeded, Failed);
}
Was ist an diesem Code falsch? Auf den ersten Blick nichts...
Erst wenn man die externe Liste über einen XsltListView-WebPart auf einer Weseite benutzt, bemerkt man, wie SharePoint intern arbeitet:
1. Erst wenn man den WebPart editiert und die View auf "<<ListName>> Read List" umstellt, bekommt man überhaupt vernünftige Daten angezeigt
2. Wenn man diese Webseite in SharePoint Designer 2010 öffnet und den CAML Query Code des XsltListViewWebPart anschaut sieht man die relevanten Method und ViewFields Tags:
<XmlDefinition>
<View Name="{F417DD2C-DE80-48A0-B2D8-7AFCBCC415FC}" MobileView="TRUE" Type="HTML"
Hidden="TRUE" DisplayName="" Url="/zhm/default.aspx" Level="1" BaseViewID="1"
ContentTypeID="0x" ImageUrl="/_layouts/images/generic.png">
<Method Name="Read List"/>
<Query>
<OrderBy>
<FieldRef Name="ID"/>
</OrderBy>
</Query>
<ViewFields>
<FieldRef Name="ID" ListItemMenu="TRUE" LinkToItem="TRUE"/>
<FieldRef Name="EventName"/>
<FieldRef Name="Location"/>
<FieldRef Name="Info"/>
</ViewFields>
<RowLimit Paged="TRUE">30</RowLimit>
<Aggregations Value="Off"/>
<Toolbar Type="Freeform"/>
</View>
</XmlDefinition>
(Die wichtigen Teile sind fett markiert)
Daraus folgt (nach einigem Pröbeln und Reduzieren des CAML Query Codes) der endgültige und funktionierende Code:
using (ClientContext context = ClientContext.Current ?? new ClientContext("<<ServerUrl>>"))
{
Web site = context.Web;
context.Load(site.Lists);
List list = site.Lists.GetByTitle("<<ListName>>");
context.Load(list);
CamlQuery query = new CamlQuery();
query.ViewXml =
"<View>" +
"<Method Name='Read List'/>" +
"<ViewFields>" +
"<FieldRef Name='ID' ListItemMenu='TRUE' LinkToItem='TRUE'/>" +
"<FieldRef Name='EventName'/><FieldRef Name='Location'/>" +
"<FieldRef Name='Info'/>" +
"</ViewFields>" +
"</View>";
items = list.GetItems(query);
context.Load(items);
context.ExecuteQueryAsync(Succeeded, Failed);
}
Externe Referenzen:
http://social.technet.microsoft.com/Forums/en/sharepoint2010programming/thread/e0f238e7-ec5b-49e7-a87c-7d70208af4d6
In SharePoint sind wir es seit längerem gewohnt Listen mit Lookup Spalten miteinander zu verknüpfen. Beim Erstellen einer Lookup Spalte kann man jeweils definieren, über welche Id die Verknüpfung angelegt wird und welches Feld zur Anzeige verwendet werden soll.
Mit SharePoint 2010 und dem neuen Konzept der External Content Types habe ich versucht diese Lookups resp. Assoziierungen zwischen Externen Listen nachzubilden.
Fazit:
Technisch gesehen funktionieren die Assoziierungen. Aber: man kann keine Anzeige-Felder definieren; Es werden immer die Id Werte angezeigt.
Beispiel:
In einer SQL Server Datenbank sind zwei Tabellen vorhanden: Event und EventYear. Zwischen den Tabellen besteht ein Foreign Key, um den Event in der EventYear Tabelle benutzen zu können.
![]()
Diese beiden Tabellen wurden in SharePoint Designer 2010 als External Content Types registriert. Zusätzlich wurde eine Assoziierung zwischen den External Content Types erstellt, um den Foreign Key (resp. den Lookup) in SharePoint nachzubilden.
Danach habe ich die External Lists basierend auf den Content Types erstellt. wenn ich im Browser in die Event Liste anschaue, sehe ich folgendes:
So weit alles in Ordnung. Der Event (also das ListItem) kann im Browser angezeigt und modifiziert werden. Toll!
Bei der EventYear Liste sieht es hingegen anders aus:

Die ListItems können zwar editiert werden; aber der Event wird als Integer Id dargestellt und nicht als Text.
Anscheinend soll es auch in Zukunft nicht möglich, dass sich Assoziierungen zwischen External Content Types gleich verhalten wie die Lookup Spalten innerhalb von SharePoint Listen.
Externe Referenzen:
http://social.technet.microsoft.com/Forums/en/sharepoint2010customization/thread/c382b04f-b55e-4c65-b9e8-b295b48eebd0
![]()
Manche Leute sehen SharePoint einfach gesagt als Datenspeicher mit einem Web-Frontend. Das stimmt soweit: denn die Datenspeicherung mit den Listen und Document Libraries ist elegant gelöst und das Aussehen des konfortablen ASP .NET 2.0 User Interfaces kann hervorragend an Kundenwünsche angepasst werden.
Dadurch ist man versucht, die Anforderungen an SharePoint hoch anzusetzen: Man könnte ja fortan jede datenzentrische Applikation mit SharePoint implementieren. Das User Interface, das man vorher umständlich selber entwickeln musste, gibt es nun quasi "gratis" mitgeliefert.
SharePoint darf jedoch nicht auf die gleiche Stufe wie ein relationales Datenbanksystem gestellt werden. SharePoint benutzt zwar unter der Haube den MS SQL Server um Daten zu speichern, gibt aber die "Datenbank-Features", wie etwa die referentielle Integrität, nicht weiter. Was in den SharePoint Listen eindeutig fehlt sind Constraints (z.Bsp. Unique Key Constraints) und Fremdschlüssel.
Fazit: Mit den Bordmitteln von SharePoint können wir keine Eindeutigkeit und keine referentielle Integrität garantieren.
Dies wurde mit heute (anlässlich der TechEd in Barcelona) von den beiden SharePoint Profis Ben Robb (cScape) und Jan Tielens (u2u) bestätigt.
Die Lösung dieses Problems ist naheliegend, denn SharePoint ist mit seinem Objektmodell gut erweiterbar: das Mittel heisst Events. Mit den vorbereiteten Event Receivern, z.Bsp. der SPItemEventReceiver Klasse, können synchron Events abgefangen, ausgewertet und wenn nötig abgebrochen werden, denn das übergebene properties Argument enthält ein Cancel Property.
Wir haben keine Wahl: wir müssen die Lücke selber füllen und können nur hoffen, dass Microsoft unser Anliegen kennt und in der nächsten SharePoint Version eine Lösung anbietet.
Es gibt diese frustrierenden Momente wo man einen Workflow einfach nicht zum Laufen bringt. Man glaubt alles korrekt eingestellt zu haben: die beiden Deployment Files: feature.xml und workflow.xml wurden schon tausend Mal kontrolliert, der Workflow Designer in Visual Studio 2005 zeigt keine Fehler, alle Tasks werden im Code korrekt erstellt, die InfoPath Formulare sind bereit und die Class Library kompiliert.
Und trotzdem beendet sich der Workflow zur Laufzeit kurz nach der Initialisierung. Erster Anlaufpunkt ist die Workflow History Liste. Nichts. Dann die Event-Logs. Nichts. Schlussendlich wird man in den SharePoint Logs (C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\LOGS) fündig: Sucht man nach "Workflow Infrastructure" finden sich einige Fehler in der Log-Datei. Beispielsweise: System.InvalidOperationException: The event receiver context for Workflow is invalid.
Diesen Text kopiert; in Google Groups eingefügt und los geht's mit der Suche. Beim Duchsehen der Resultate werde ich auf einen Eintrag im MSDN Forum von Microsoft aufmerksam: "The issue with the correlation token, the correlation token for the task needs to be different from the workflow!! Remember this guys, and avoid the turmoil ive been through."
Vermutlich wird in jedem SharePoint Workflow Buch x- Mal darauf hingewiesen und doch geht dieser Punkt immer wieder vergessen: Der "CorrelationToken" des Workflows darf nicht für die Tasks (wieder-) verwendet werden!
Die einfache Lösung des Problems: Einfach für jeden Task einen neuen CorrelationToken definieren oder in dem bestehenden Workflow den Wert mit einem neuen Text überschreiben. That's it...
Wird in Visual Studio 2005 in einem SharePoint Workflow Projekt über den Workflow Designer (siehe Referenzen) mit Hilfe der CreateTask Aktivität ein neuer Task erstellt, müssen im Source Code die TaskId und die TaskProperties gesetzt werden:
taskId = Guid.NewGuid();
taskProperties.Title = "my Title";
taskProperties.Description = "my Description";
taskProperties.AssignedTo = "Administrator";
taskProperties.PercentComplete = 0;
taskProperties.StartDate = DateTime.Today;
taskProperties.DueDate = DateTime.Today.AddDays(2);
taskProperties.ExtendedProperties["Instructions"] = "my Instructions ";
Wird zum Beispiel ein InfoPath Formular verwendet um den Task zu editieren, kann über die ExtendedProperties HashTable Werte (z.B. Instructions) an das Formular übergeben werden. Sind diese Werte leer (null) wird folgender Fehler in der Workflow History geloggt:
User ID: 'System Account'
Outcome: 'mscorlib'
Description: 'Exception has been thrown by the target of an invocation.'
Data:
at System.RuntimeMethodHandle._InvokeMethodFast(Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.RuntimeMethodHandle.InvokeMethodFast(Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeTypeHandle typeOwner)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.InvokeMember(String name, BindingFlags bindingFlags, Binder binder, Object target, Object[] providedArgs, ParameterModifier[] modifiers, CultureInfo culture, String[] namedParams)
at System.Workflow.Activities.CallExternalMethodActivity.Execute(ActivityExecutionContext executionContext)
at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext)
at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(Activity activity, ActivityExecutionContext executionContext)
at System.Workflow.ComponentModel.ActivityExecutorOperation.Run(IWorkflowCoreRuntime workflowCoreRuntime)
at System.Workflow.Runtime.Scheduler.Run()
Dieser nichts sagende Fehler kann vermieden werden, indem der ExtendedProperties HashTable keine null Werte übergeben werden!
Referenzen:
-
Visual Studio 2005 extensions for .NET Framework 3.0 (Windows Workflow Foundation) -->
Download
-
Windows SharePoint Services 3.0 Tools: Visual Studio 2005 Extensions -->
Download
Gerade im Zusammenhang mit SharePoint Workflows ist es unabdingbar, dass sich die Workflow Variablen serialisieren lassen, weil sich der Workflow ab und zu schlafen legt (Serialisierung der Variablen), bis ein gewisses Ereignis, beispielsweise das Abschliessen einer Aufgabe, eintritt und der Workflow fortgeführt wird (Deserialisierung der Variablen).
Microsoft gibt uns zwar mit den Workflow Properties (SPWorkflowActivationProperties) ein Objekt in die Hand, das von der Ereignis Aktivität OnWorkflowActivated abgefüllt wird. Wir müssen uns nicht um die Serialisierung der Properties (wie Site, Web, List, Item) kümmern. Dies wird automatisch für uns gemacht.
Wenn wir nun aber in unserem Workflow eine weitere Variable vom Typ SPListItem benötigen, die nicht über die Workflow Properties erreichbar ist, müssen wir selber dafür sorgen, dass die Variable beim Fortführen des Workflows korrekt initialisiert wird. Dazu ein kleiner Code Ausschnitt:
public int ItemID = -1;
[NonSerialized()]
private SPListItem _item;
public SPListItem DuplicateItem
{
get
{
if (_item == null && ItemID != -1)
_item = LoadListItem(ItemID); // ToDo: Implement LoadListItem()
return _item;
}
set
{
_item = value;
if (_item != null)
ItemID = _item.ID;
}
}
Zuerst benötigen wir eine Integer Variable ItemID für die eindeutige Identifikation des Items. Um die Serialisierung dieser Variable brauchen wir uns nicht zu kümmern.
Danach deklarieren wir eine private Variable _item vom Typ SPListItem, die das List Item zur Laufzeit zur Verfügung stellt, die aber nicht serialisierbar ist. Darum wird die Variable mit dem NonSerialized Attribut dekoriert.
Schlussendlich müssen wir noch eine Property Item implementieren, die bei Bedarf das List Item nachlädt (nämlich genau dann, wenn der Workflow fortgeführt wird und alle Variablen deserialisert werden). Zu diesem Zweck muss noch die LoadListItem Funktion implementiert werden, die anhand der List Item ID ein List Item zurückgibt.
SharePoint zeigt nirgends eine Liste mit der Workflow History.
Dabei gibt es diese auf Stufe Site; Sie wird nur nicht angezeigt (auch nicht in All Site Content).
Die URL lautet: http://localhost/Lists/Workflow%20History
Diese Liste zeigt die Spalte Data, die normalerweise in der Workflow History nicht zu finden ist.
Data kann in eigenen Visual Studio 2005 Workflows benutzt werden, um Texte oder Fehlermeldungen anzuzeigen, die in Outcome und Description nicht Platz finden (diese beiden sind auf 256 Zeichen limitiert).
Aktivität: LogToHistoryListActivity. Eigenschaft: OtherData.