1
Obsah 1.
Přehled: SharePoint Services 3.0 a workflow.................................................................................... 7
2.
Úvod do problematiky, motivace ..................................................................................................... 8
3.
Popis technologie Workflow Foundation ......................................................................................... 9
4.
5.
3.1
Sekvenční workflow ................................................................................................................. 9
3.2
Stavové workflow .................................................................................................................... 9
Přehled základních komponent WF ................................................................................................ 11 4.1
Knihovna tříd Workflow Foundation....................................................................................... 11
4.2
Workflow Runtime Engine ..................................................................................................... 11
4.3
Workflow RuntimeServices .................................................................................................... 12
4.4
Nástroje určené k návrhu workflow ....................................................................................... 12
4.5
Komunikace WF s hostitelskými aplikacemi ............................................................................ 12
4.6
SharePoint – WorkflowRuntime, RuntimeServices ................................................................. 13
Aplikace Bankomat a jednoduché použití stavového workflow ...................................................... 15 5.1
Základní popis funkčnosti aplikace ......................................................................................... 15
5.2
Detailní popis stavů aplikace .................................................................................................. 16
5.3
Popis komponent aplikace ..................................................................................................... 17
5.4
Vytvoření projektu ................................................................................................................. 18
5.5
Runtime Local Service – ATMService ...................................................................................... 19
5.5.1.
Definice komunikačního rozhraní ................................................................................... 19
5.5.2.
Definice argumentů sloužících ke komunikaci workflow a hostitelské aplikace ............... 20
5.5.3.
Implementace komunikační služby ................................................................................. 21
5.5.4.
Události vyvolané ve workflow ovlivňující hostitelskou aplikaci ...................................... 22
5.6
Implementace workflow ........................................................................................................ 23
5.6.1.
Modelování workflow .................................................................................................... 23
2
5.6.2.
Vytvoření prázdného stavu ............................................................................................. 23
5.6.3.
Vložení aktivity StateInitialization ................................................................................... 24
5.6.4.
Vložení aktivity CallExternalMethod ............................................................................... 25
5.6.5.
Vložení aktivity EventDriven ........................................................................................... 27
5.6.6.
Vložení aktivity HandleExternalEvent – zpracování události ........................................... 27
5.6.7.
Vložení aktivity SetState – přechod workflow do stavu „Karta vložena“ .......................... 28
5.7
Dokončení modelu workflow pro platební bankomat ............................................................. 29
5.8
Shrnutí modelování a programování workflow ....................................................................... 33
5.9
Hostitelská aplikace ............................................................................................................... 34
5.9.1.
Potřebné objekty............................................................................................................ 34
5.9.2.
Inicializace WorkflowRuntime ........................................................................................ 34
5.9.3.
Spuštění instance workflow uvnitř WorkflowRuntime .................................................... 35
5.9.4.
Volání událostí komunikační služby ................................................................................ 36
5.9.5.
Obdržení a zpracování události o přechodu do nového stavu.......................................... 37
5.10
Shrnutí kapitoly o implementaci jednoduchého platebního bankomatu ................................. 38
6.
Vývoj aplikací v prostředí SharePointu – co je potřeba ................................................................... 39
7.
Popis aplikačního rozhraní MS SharePoint ..................................................................................... 40
8.
7.1
Architektura MS SharePoint ................................................................................................... 40
7.2
Definice přístupových práv ..................................................................................................... 42
7.3
Objektový model SharePoint .................................................................................................. 42
Manipulace s položkami v seznamu pomocí SharePoint API ........................................................... 44 8.1
Příprava seznamu v SharePointu ............................................................................................ 44
8.2
Vytvoření projektu ve Visual Studiu........................................................................................ 45
8.3
Poznámka o uvolňování objektu objektového modelu SharePointu ........................................ 46
8.4
Zdrojový kód příkladu ............................................................................................................ 47
3
8.5 9.
Závěr, poznámky k příkladu.................................................................................................... 48
Ukázková aplikace: Import kontaktů z ActiveDirectory do SharePointu .......................................... 50 9.1
Přístup do Active Directory..................................................................................................... 50
9.2
Vytvoření projektu, přidání referencí ..................................................................................... 51
9.3
Získání uživatelských dat z Active Directory ............................................................................ 52
9.4
Import získaných dat do seznamu kontaktů v SharePointu ..................................................... 54
9.5
Závěr...................................................................................................................................... 56
10. Přidání vlastních ASP stránek do SharePointu ................................................................................ 57 10.1
Master Pages ......................................................................................................................... 58
10.2
Vytvoření projektu a přidání referencí .................................................................................... 59
10.3
Logika webové stránky ........................................................................................................... 60
10.4
Deployment ASPX stránek do složky LAYOUTS........................................................................ 63
10.5
Deployment dynamické knihovny .......................................................................................... 65
11. SharePoint a Workflow Foundation ............................................................................................... 68 11.1
Úvod do problematiky a cíle této části ................................................................................... 68
11.2
Schválení požadavku na nový software .................................................................................. 68
12. Integrace Workflow Foundation do SharePointu............................................................................ 70 12.1
Workflow jako sled úkolů ....................................................................................................... 71
12.2
Workflow SharePoint aktivity ................................................................................................. 71
12.3
SharePoint Features ............................................................................................................... 72
12.4
Nástroj STSADM ..................................................................................................................... 73
12.5
Napojení úkolů v SharePointu na webové formuláře .............................................................. 73
12.6
Vlastní typy obsahu ................................................................................................................ 74
13. Architektura aplikace ..................................................................................................................... 75 13.1
Návrh vstupního formuláře (formuláře požadavku) ................................................................ 75
4
13.2
Návrh a zpracování webových formulářů, sloužících jako vstupní body pro uživatele aplikace 75
13.3
Návrh a zpracování workflow ................................................................................................. 75
13.4
Přehled architektury aplikace ................................................................................................. 76
14. Návrh formuláře požadavku pomocí nástroje MS InfoPath ............................................................ 78 14.1
Návrh formuláře a jeho publikování ....................................................................................... 78
14.2
Tlačítko „Odeslat“ – uložení formuláře do knihovny v SharePointu......................................... 80
14.3
Tipy a triky pro vytváření formulářů ....................................................................................... 84
14.3.1.
Zisk aktuálního data ....................................................................................................... 84
14.3.2.
Zisk aktuálního uživatele ................................................................................................ 84
15. Návrh a implementace webového rozhraní.................................................................................... 88 15.1
Vytvoření projektu ................................................................................................................. 88
15.2
ASPX formulář pro schválení .................................................................................................. 89
15.3
Zdrojový soubor formuláře..................................................................................................... 91
15.4
Získání proměnných z požadavku a z úkolu............................................................................. 93
15.5
Odeslání informací zpět do workflow ..................................................................................... 95
15.6
Úprava hodnot v požadavku ................................................................................................... 97
15.7
Další metody v požadavku ...................................................................................................... 99
15.8
Formulář pro dodání dodatečných informací ........................................................................ 100
15.9
Publikování formulářů.......................................................................................................... 101
15.10
Vytvoření vlastních typů obsahu pro jednotlivé úkoly ....................................................... 101
15.11
Povolení typů obsahu ....................................................................................................... 104
16. Návrh a implementace workflow ................................................................................................. 105 16.1
Soubory feature a workflow ................................................................................................. 106
16.2
Úpravy workflow.................................................................................................................. 106
16.3
Příprava proměnných........................................................................................................... 106
5
16.4
Modelování workflow .......................................................................................................... 107
16.5
Vytvoření nového úkolu ....................................................................................................... 109
16.6
Změna úkolu ........................................................................................................................ 112
16.7
Stav přidání dodatečných informací ..................................................................................... 116
16.8
Ladění aplikace .................................................................................................................... 118
16.8.1. 16.9
Ladění na vzdáleném počítači ....................................................................................... 119
Deployment – přenos do produkčního prostředí .................................................................. 119
16.10
Ukázka fungování systému ............................................................................................... 120
16.11
Závěr................................................................................................................................ 122
17. Tipy a triky pro vývoj workflow v SharePointu.............................................................................. 124 17.1
Programové povolení typů obsahu na seznamu ................................................................... 124
17.2
Posluchače událostí seznamu ............................................................................................... 125
17.2.1.
Implementace posluchače události ItemAdded ............................................................ 125
17.2.2.
Registrace posluchače událostí se seznamem ............................................................... 126
17.3
Nastavení práv k úkolu ......................................................................................................... 127
18. Závěr ........................................................................................................................................... 128 18.1
Shrnutí obsahu příručky ....................................................................................................... 128
18.2
Shrnutí programování workflow v SharePointu .................................................................... 128
6
1. Přehled: SharePoint Services 3.0 a workflow Windows SharePoint je webová platforma, intranetový portál, který má za úkol sloužit jako univerzální informační systém podporující sdílení informací. Základem sdílených informací v SharePointu jsou knihovny dokumentů a seznamy. Jednou z možností manipulace s dokumenty a položkami v seznamech SharePointu je vytváření workflow, tedy popsání a definování business procesů, které je možné s dokumenty nebo položkami seznamů provádět. Vytváření workflow v SharePointu je umožněno díky integraci Workflow Foundation a objektového modelu SharePointu. Workflow Foundation je platforma určená k modelování workflow, která je standardní součástí .NET Frameworku od verze 3.0. K úplnému pochopení workflow pod SharePointem je nutné probrat nejen aplikační rozhraní SharePointu, ale také základy Workflow Foundation, a zároveň doplnit, jak jsou tyto dvě platformy vzájemně propojeny. Tato série bude rozdělena na následující kapitoly: 1. Motivace-popis možného využití workflow 2. Workflow Foundation a. Popis platformy, základní stavební kameny b. Příklady sekvenčních a stavových workflow c. Příklad ilustrující implementaci workflow do jednoduché aplikace 3. Windows SharePoint Services a. Popis architektury b. Příklad ilustrující využití aplikačního rozhraní SharePointu c. Vkládání vlastních ASP.NET stránek do SharePointu 4. Návrh a implementace workflow, sloužícího ke schválení dokumentu a. Popis integrace SharePointu a Workflow Foundation b. Popis workflow stavový diagram c. Návrh workflow pomocí jednotlivých aktivit SharePointu
7
2. Úvod do problematiky, motivace S rozvojem informačních technologií se v dnešní době stále častěji setkáváme s nutností zmapovat, jak některé firemní procesy ve společnostech fungují, a jako vývojáři připravit pro tyto činnosti informační systémy, které budou k jejich vykonávání nápomocné. Během jakéhokoliv business procesu mezi sebou vzájemně komunikují a vyměňují si informace zaměstnanci firmy. Je vhodné business proces popsat a zautomatizovat. Tím dojde ke zvýšení efektivnosti a snížení chybovosti. K popisu business procesů se nejčastěji používají tzv. workflow. Pojmu workflow v češtině asi nejlépe odpovídá slovní spojení „sled prací“. Workflow je definováno jako postup činností, které jsou vykonávány v běžném životě za určitým účelem. Tento postup lze většinou zaznamenat vývojovým nebo stavovým diagramem. V této sérii článků se budeme zabývat procesy, které se týkají dokumentů. Mezi takovéto procesy může patřit například: 1. Schvalování dokumentů – nejčastější použití workflow, kdy uživatel po vytvoření dokumentu odešle dokument prostřednictvím informačního systému svému nadřízenému ke schválení. 2. Společné vytváření dokumentů a koordinace spolupráce – situace, kdy se několik uživatelů podílí na vytváření dokumentu. 3. Issue tracking – během některých business procesů může vznikat seznam problémů, které je nutné přidělovat jednotlivým řešitelům, a tyto problémy jsou potom řešeny paralelně.
8
3. Popis technologie Workflow Foundation V této kapitole bude popsáno, ze kterých komponent se Workflow Foundation skládá, jak tyto komponenty fungují a zároveň komunikují, a posléze bude na jednoduché aplikaci demonstrována funkčnost této platformy. Jak již bylo zmíněno, Workflow Foundation je součástí platformy .NET od verze 3.0. Je to sada nástrojů a knihovna tříd, které umožňují modelovat libovolné procesy. Její základní výhodou je použití v jakékoliv hostitelské aplikaci. Workflow Foundation tedy můžeme použít v klientské aplikaci (Windows Forms) nebo například ve webové aplikaci postavené na platformě ASP.NET. Než probereme základní součásti platformy, nejprve jasně vymezíme, co lze pomocí Workflow Foundation modelovat. V zásadě jsou to dva typy workflow: sekvenční a stavové.
3.1 Sekvenční workflow Sekvenční (Sequential) workflow je dáno jako sled akcí a událostí, které jsou spouštěny v předepsaném pořadí. Tok událostí je stanoven podmínkami a cykly. Sekvenční workflow má jasně daný začátek, všechny cesty svého průběhu a konec. Můžeme si ho představit jako jednoduchý vývojový diagram, pro ilustraci uvádím diagram schválení bankovního úvěru: Vytvoření požadavku na úvěr
Zjistit finanční situaci klienta
Je uvěr dostatečně zajištěn?
Alokovat prostředky pro klienta
Poslat klientovi odůvodnění zamítnutí
Konec
Obrázek 1: Sekvenční workflow
3.2 Stavové workflow Stavové (State Machine) workflow neurčuje jednoznačně pevnou posloupnost kroků. Místo toho je určeno několika stavy a přechody mezi nimi. Stavové workflow může, ale nemusí, mít pevně daný
9
počáteční a konečný stav. Toto mu umožňuje být přerušeno v libovolnou dobu a být znovu inicializováno z jakéhokoliv stavu, pokud je to nutné. Přechody mezi stavy jsou vyvolány událostmi, které workflow obdrží z hostitelské aplikace (popsáno dále). Následující stavový diagram popisuje schválení úvěru z hlediska stavů.
Zjištěno úvěr zajištěn Obdržení žádosti Čekání na žádost o úvěr
Prostředky alokovány
Zjišťování zajištění Žádost obdržena
Zajištění zjištěno
Zjištěno úvěr nezajištěn
Žádost odmítnuta
Obrázek 2: Stavové workflow
Z výše uvedeného popisu je jasné, že každý z těchto typů je vhodný k modelování různých procesů. Vzhledem k tomu, že sekvenční workflow je určeno přesnou sekvencí kroků, dá se říci, že je vhodnější pro modelování systémových interakcí, kde dopředu známe přesný sled událostí, které nastanou. Naopak stavové workflow může dobře posloužit při modelování procesů, při nichž dochází k interakci s lidmi, kde je zapotřebí větší flexibilita, protože lidé ne vždy dělají vše podle předepsaných kroků. Závěrem je ale nutné zmínit, že ve většině případů můžeme namodelovat proces nebo činnost oběma typy workflow.
10
4. Přehled základních komponent WF Na následujícím obrázku jsou zobrazeny komponenty, které tvoří MS Workflow Foundation, a dále následuje jejich popis. Workflow Foundation WF Runtime Engine
WF Runtime Services
WF Framework Knihovna tříd
WF Design – Time – Tools Visual Studio WF Designer
.NET 2.0
Obrázek 3: Základní komponenty Workflow Foundation
4.1 Knihovna tříd Workflow Foundation Knihovna tříd Workflow Foundation (Workflow Class Library) obsahuje třídy a objekty, které slouží k modelování procesů. Základní entitou v platformě Workflow Foundation je „aktivita“. Aktivita je jakýkoliv proces, který je prováděn v průběhu workflow. Z výše zmíněných příkladů můžeme za aktivitu označit například „zjišťování finanční situace klienta“. Základem je třída Activity, od níž dědí všechny třídy, které specifikují určitou prováděnou činnost. WF Class Library obsahuje řadu již hotových aktivit, jež lze použít, jako například SendEmailActivity nebo CallExternalMethodActivity, jejichž význam je zřejmý. Stejně tak můžeme ale definovat svoje vlastní aktivity, které budeme chtít ve workflow používat. Vzhledem k výše uvedenému příkladu si můžeme představit aktivity jako například CheckClientSituationActivity nebo ApproveLoanActivity. Základním objektem každého workflow je WorkflowInstance. Tento objekt obdržíme po vytvoření nového workflow a umožňuje nám kontrolovat a spouštět workflow. Obsahuje metody jako například Start( ), Suspend( ) a Terminate( ), jejichž význam také není potřeba vysvětlovat. Všechny třídy, které tvoří tuto knihovnu tříd, lze najít ve jmenném prostoru System.Workflow.
4.2 Workflow Runtime Engine WF Runtime Engine je reprezentován třídou WorkflowRuntime. Tuto třídu si můžeme představit jako kontejner, který je uzpůsoben ke spouštění, zastavování a všeobecné správě instancí jednotlivých workflow (WorkflowInstance). Pokud chceme v aplikaci využít workflow, musíme nejprve vytvořit WorkflowRuntime, který bude workflow instance spravovat. WorkflowRuntime tedy poskytuje prostředí, v němž je možné spouštět jednotlivá workflow.
11
4.3 Workflow RuntimeServices RuntimeServices poskytují různé externí funkce a metody pro instance, uvnitř kontejneru WorkflowRuntime. Aby mohla služba spolupracovat s instancí workflow, musí být registrována s kontejnerem WorkflowRuntime. Instance jednotlivých workflow uvnitř kontejneru WorkflowRuntime mohou využít externích služeb voláním metod a posloucháním událostí, které daná služba registrovaná s WorkflowRuntime poskytuje. RuntimeServices jsou základními komponentami, které umožňují komunikaci workflow s okolním světem, především s hostitelskou aplikací. Služby se dělí na Core Services a Local Services. Core Services (základní služby) jsou reprezentovány třídami, které už jsou součástí knihovny tříd Workflow Foundation. Tyto služby jsou již připravené k použití a služby, které pro workflow instance zajišťují, mohou být různé. Příkladem je například třída SqlWorkflowPersistanceService. Tato třída slouží k uchování stavu workflow v SQL databázi. K takovéto serializaci stavu workflow do databáze dochází vždy v případě, kdy je workflow v nečinném stavu a čeká na akci uživatele. Workflow může být následně znovu nahráno z této zálohy v databázi. Je ovšem možné implementovat i vlastní typy „základních služeb“. Například děděním od třídy WorkflowPersistanceService je možné vytvořit vlastní službu pro ukládání stavu workflow, například do XML (eXtensible Markup Language) souborů. Local Services (místní služby) jsou služby definované vývojáři, za účelem poskytnutí instancím workflow uvnitř kontejneru WorkflowRuntime metody a události, které mu umožní komunikovat s hostitelskou aplikací.
4.4 Nástroje určené k návrhu workflow Jedna ze základních výhod Workflow Foundation je možnost vizuální práce s workflow. Především možnost grafického návrhu workflow pomocí Designéru, který je součástí MS Visual Studia 2008. Grafický návrh workflow není podmínkou. Celé workflow se dá napsat ručně bez použití tohoto Designéru, ale tím se připravujeme o jednu ze základních výhod Workflow Foundation. V této souvislosti je vhodná paralela s designérem klasického GUI (Graphical User Interface) pro Windows Forms aplikace. Jeho použití také není nutností, ale ušetříme dost času, nemusíme-li psát lehce vygenerovatelný kód.
4.5 Komunikace WF s hostitelskými aplikacemi Jak již bylo zmíněno výše, jedním ze základních problémů a zároveň funkčností, bez které by bylo použití workflow naprosto bez užitku, je možnost komunikovat s hostitelskou aplikací. Také již bylo řečeno, že k tomu slouží Local RuntimeServices. Z následujícího obrázku je patrné, jak tato komunikace probíhá.
12
Registrovat službu
Používá
WorkflowInstance WorkflowInstance
Vytvořit službu
Core Services
Workflow Runtime
Hostitelská aplikace
WorkflowInstance
Doručení události
WorkflowInstance Spusť událost
Local Runtime Services
Registrovat službu
Spusť událost
Doručení události
Vytvořit službu
Obrázek 4: Komunikace workflow s hostitelskou aplikací
Hostující aplikace musí v první řadě obsahovat instanci třídy WorkflowRuntime, tato instance může obhospodařovat libovolný počet instancí jednotlivých workflow. Dále je nutné definovat třídu, která bude reprezentovat lokální službu určenou ke komunikaci. Tato služba má pevně danou strukturu, tak aby mohla být s instancí třídy WorkflowRuntime registrována a instance workflow, které běží uvnitř, mohly volat metody a poslouchat události této služby. Proces ovšem může fungovat i opačně, kdy hostitelská aplikace volá metody této služby a také poslouchá události, které jí tato služba odesílá. Tím je docíleno vzájemné komunikace.
4.6 SharePoint – WorkflowRuntime, RuntimeServices Logická otázka zní: Jak tyto součásti nutné pro běh workflow zakomponovat do SharePointu? Pokud vyvíjíme Windows Forms nebo ASP.NET aplikaci, je to poměrně jednoduché (jak bude ukázáno v příkladu na konci této kapitoly). Nemáme v zásadě žádná omezení, můžeme si vytvářet libovolné objekty, které jsou potřeba ke spuštění instance Workflow. V případě SharePointu je situace odlišná. SharePoint je již hotový produkt a nemůžeme měnit jeho strukturu, nejde tedy například přidat do SharePointu nový Workflow Runtime a v něm spouštět instance vlastních workflow. SharePoint již obsahuje základní objekty Workflow Foundation. Obsahuje tedy Workflow Runtime, které je připravené k přidávání a spouštění jednotlivých instancí workflow. Zároveň obsahuje také vlastní implementace Core Services. Tedy například službu zajišťující perzistenci workflow do SQL databáze SharePointu.
13
Detailněji to bude popsáno v samostatné kapitole, která se bude zabývat integrací Workflow Foundation do SharePointu.
14
5. Aplikace Bankomat a jednoduché použití stavového workflow Nyní se již zaměříme na konkrétní příklad použití Workflow Foundation a tím bude jednoduchá aplikace simulující platební bankomat. Protože aplikace slouží jen k účelu vysvětlení technologie WF, byla co nejvíce zjednodušena, a bankomat tak provádí jen některé základní operace.
5.1 Základní popis funkčnosti aplikace Následující diagramy ukazují několik stavů, ve kterých se může bankomat nacházet od operace vložení karty až po výběr hotovosti. Bankovní automat Zapnout
Bankovní automat Zapnout
Vložit kartu
První Bankovní a.s.
Vybrat hotovost
První Bankovní a.s.
Zjistit stav účtu
Vyberte akci kterou chcete provést:
Vyjmout kartu
Vložte prosím kartu
Výběr hotovosti Zjištění zůstatku na Vašem účtu
Bankovní automat Zapnout
Potvrdit PIN
První Bankovní a.s.
Nyní jsemVyjmout ve stavu: WaitingForCardState kartu
Nyní jsem ve stavu: WaitingForCardState Nyní jsem ve stavu: CardEnteredState Nyní jsem ve stavu: PINEnteredState
Zadejte prosím Váš PIN a potvrďte stiskem tlačítka (PIN je: "1111")
Nyní jsem ve stavu: WaitingForCardState Nyní jsem ve stavu: CardEnteredState
Obrázek 5: První tři stavy aplikace Bankomat
15
Bankovní automat Zapnout
Bankovní automat
Zpět do MENU
První Bankovní a.s.
Vyjmout kartu
Výše zůstatku na Vašem účtu činí:
Zapnout
200
První Bankovní a.s.
500
Vyberte částku, kterou chcete vybrat.
1000
Pokud Vám nabízené částky nevyhovují, můžete zadat vlastní.
2000
Jinou částku
3500 Zpět do MENU
Nyní jsem ve stavu: WaitingForCardState Nyní jsem ve stavu: CardEnteredState Nyní jsem ve stavu: PINEnteredState Nyní jsem ve stavu: WithDrawMoneyState Nyní jsem ve stavu: TransactionCompletedState Nyní jsem ve stavu: PINEnteredState Nyní jsem ve stavu: CheckAccountState
Bankovní automat Zapnout
Nyní jsem ve stavu: WaitingForCardState Vyjmout Nyní jsem ve stavu: kartuCardEnteredState Nyní jsem ve stavu: PINEnteredState Zpět do Nyní jsem ve stavu: WithDrawMoneyState
První Bankovní a.s.
MENU
Transakce proběhla vpořádku. Přejete si návrat do hlavního menu?
Nyní jsem ve stavu: WaitingForCardState Nyní jsem ve stavu: CardEnteredState Nyní jsem ve stavu: PINEnteredState Nyní jsem ve stavu: WithDrawMoneyState Nyní jsem ve stavu: TransactionCompletedState
Obrázek 6: Stavy aplikace Bankomat při výběru hotovosti
5.2 Detailní popis stavů aplikace Popsat všechny stavy, ve kterých se bankomat nachází, lze nejlépe stavovým diagramem.
16
Vložení karty
Čekání na vložení karty
Karta vložena Čekáni na PIN Vyjmutí karty
Chybný PIN Korektní PIN Vyjmutí karty Vyjmuti karty
PIN vložen Výběr operace Návrat do hlavní nabídky Operace provedena Výběr hotovosti Dokončení operace Dokončení operace
Výběr konkrétní částky
Zjistit stav účtu
Výběr hotovosti
Návrat do hlavní nabídky
Výběr konkrétní částky Zjištění zůstatku na účtu
Obrázek 7: Stavový diagram Bankomatu
Z tohoto diagramu je zřejmé, že aplikace má jeden počáteční stav, ve kterém bankomat čeká na vložení karty. Ve stavovém diagramu jsou vyznačeny události, jež způsobují přechody mezi stavy. Například pokud se aplikace nachází v počátečním stavu „Čekání na vložení karty“ a je vložena karta, přejde do stavu „Čekání na PIN“. Toto stavové workflow nemá koncový stav, po vyjmutí karty bankomat přechází znovu do prvního stavu.
5.3 Popis komponent aplikace Aplikace Bankomat vytvořená pomocí WF se bude skládat ze tří základních částí:
Hostitelská aplikace reprezentovaná formulářem (třída MainForm.cs)
Dynamická knihovna obsahující workflow (třída ATMWorkflow.cs)
Komunikační Runtime Local Service (třída ATMService.cs)
Architektura aplikace je naznačena na níže uvedeném diagramu. Aplikace Bankomat CardEntered
Workflow Runtime WorkflowInstance
RaiseCardEntered()
GUI Aplikace MainForm
ATMService SendMenuText()
UpdateMenuText()
Obrázek 8: Schéma komponent aplikace Bankomat
17
Visual Studio Solution se bude skládat ze tří základních projektů, z nichž každý bude reprezentovat jednu z výše uvedených součástí. Uživatelské rozhraní aplikace reprezentované formulářovým oknem bude obsluhovat události prováděné uživatelem – v tomto případě stisky jednotlivých tlačítek. V obsluze těchto událostí bude tyto vyvolávat události ATMService – služby, která bude tvořit komunikační vrstvu. Takto vyvolané události se dostanou až k instanci workflow běžící ve Workflow Runtimu, a zde budou zpracovány a na základě stavu, v němž se workflow nachází, a vstupů, které obdrželo, budou zpět do aplikace reprezentující uživatelské rozhraní odeslány informace a vyhodnocení určující, co je potřeba provést.
5.4 Vytvoření projektu Nejprve navrhneme strukturu a vytvoříme prázdné projekty, ve kterých budeme vyvíjet jednotlivé části aplikace. Otevřeme tedy Visual Studio a vytvoříme v něm nový projekt typu Windows Forms Application. Zároveň s projektem se vytvoří i nové Solution.
Obrázek 9: Vytvoření nového projektu
18
Do Solution následně přidáme další dva projekty. První typu State Machine Workflow Library, v němž budeme vytvářet a modelovat samotné workflow, a druhý typu Class Library, ve kterém budou třídy reprezentující ATMLocalService.
Obrázek 10: Projekt workflow
Obrázek 11: Projekt komunikační služby
Výsledné řešení ve vašem Visual Studiu by mělo vypadat následovně:
Obrázek 12: Přehled řešení ve Visual Studiu
5.5 Runtime Local Service – ATMService Jak již bylo řečeno, třídy v projektu ATMLocalService budou sloužit jako komunikační prostředky mezi uživatelským rozhraním a workflow. Protože v obou ostatních projektech se budeme odkazovat na třídy z tohoto projektu, definujeme je nyní jako první. 5.5.1. Definice komunikačního rozhraní První je třeba definovat komunikační rozhraní, které určí události (events), jež bude workflow poslouchat. Vytvoříme tedy rozhraní, které pojmenujeme IATMService. Rozhraní musí být dekorované
19
atributem ExternalDataExchange, ten řekne workflow, že se jedná o třídu definující komunikační rozhraní. Rozhraní IATMService bude definovat všechny události spojené s bankomatem (vsunutí/vysunutí karty, zadání PINu atd.). Dále bude obsahovat jednu metodu SendMenuText. Tato metoda bude sloužit ke komunikaci směrem od Workflow Enginu k aplikaci. [ExternalDataExchange] public interface IATMService { /// <summary> /// Metoda, která umožní našemu workflow nastavit výstupní /// text v hostitelské aplikaci. /// /// <param name="menuText">Výstupní text void SendMenuText(String menuText); /// <summary> /// Událost vsunutí karty /// event EventHandler
CardInserted; event event event event event event event
EventHandler EventHandler EventHandler EventHandler EventHandler EventHandler EventHandler
PINEntered; CardRemoved; CheckAccoundRequested; MoneyRequested; SumRequested; ExactSumRequested; BackToMenuRequested;
}
5.5.2. Definice argumentů sloužících ke komunikaci workflow a hostitelské aplikace Při definici EventHandleru je nutné specifikovat typ argumentu události. Argumenty události musí obsahovat veškeré informace, které chceme do workflow poslat v daném kroku. Formulář aplikace může do workflow posílat dva speciální argumenty: při vkládání karty její PIN a při výběru hotovosti celkovou požadovanou částku. Třída ATMEventArgs, kterou používáme ve výše uvedené definici EventHandlerů, zapouzdří tyto argumenty. Zároveň musí dědit od třídy ExternalDataEventArgs. Konstruktor třídy argumentů dědící od ExternalDataEventArgs má jeden parametr a tím je ID určující Instanci Workflow, jehož pomocí WorkflowRuntime zjistí, kterému workflow uvnitř má událost doručit. Vytvoříme tedy třídu ATMEventArgs. [Serializable] public class ATMEventArgs : ExternalDataEventArgs { /// <summary> /// Zadávaný PIN ///
20
public string Pin {get;set;} /// <summary> /// Suma pří výběru hotovosti /// public int Amount { get; set; } /// <summary> /// Konstruktor třídy argumentů /// public ATMEventArgs(Guid instanceId) : base(instanceId) { } }
5.5.3. Implementace komunikační služby Nyní, když máme předdefinované komunikační rozhraní IATMService a zároveň argumenty, které chceme do workflow pomocí tohoto rozhraní posílat, můžeme přistoupit k navržení komunikační služby, jež bude toto rozhraní implementovat. Vytvoříme třídu ATMService, která tedy bude obsahovat všechny události rozhraní IATMService a navíc definovat metody sloužící pro probuzení těchto událostí. Pro ilustraci je níže uvedena metoda, která probudí událost PINEntered. Stejné metody musíme dopsat pro probuzení všech ostatních událostí. V metodě je nejprve zjišťováno, zda jsou s událostí registrované některé metody, a v případě, že tomu tak je, je vytvořen nový objekt typu ATMEventArgs. Tomuto objektu jsou předány argumenty: vložený PIN a identifikátor instance workflow. Následně je „probuzena“ událost PINEntered s těmito argumenty. Zbytek komunikace již nemůžeme ovlivnit. WorkflowRuntime obdrží tuto událost od služby ATMService a podle identifikátoru jí doručí konkrétní instanci workflow. [Serializable] public class ATMService : IATMService { public void RaisePINEnteredEvent(Guid instanceId,string lPin) { //zjistí, zda jsou s událostí registrované metody if (PINEntered != null) { //vytvoří argumenty události ATMEventArgs e = new ATMEventArgs(instanceId); //přiřadí PIN do argumentů e.Pin = lPin; //zavolá metody registrované s událostí PINEntered(null, e); } } public event EventHandler PINEntered; }
21
5.5.4. Události vyvolané ve workflow ovlivňující hostitelskou aplikaci Za účelem odeslání výstupního textu do hostitelské aplikace implementuje služba ATMService metodu SendMenuText, také definovanou rozhraním IATMService. Pro pochopení implementace metody SendMenuText je nutné si uvědomit architekturu celého programu. Možnosti komunikace jedné instance workflow, které běží uvnitř WorkflowRuntime, s okolním světem jsou poměrně omezené. Pomocí speciálních aktivity CallExternalMethodActivity, ke které se ještě vrátíme, je možné volat externí metody, ale pouze definované v komunikační službě, která implementuje rozhraní dekorované atributem ExternalDataExchange. Takovou komunikační službou je v našem případě služba ATMService. Je tedy nutné definovat ve službě ATMService metodu SendMenuText. Tato metoda se ale nemůže odvolávat přímo na GUI aplikace. Je nutné definovat událost, která bude voláním této metody probuzena a GUI aplikace bude moci tuto událost odposlouchávat, a vždy při probuzení této události změnit výstupní text automatu. Definujeme tedy delegáta a k němu odpovídající událost MenuTextEvent, kterou budou moci využít klienti (v tomto případě GUI aplikace) k získání informace o změně výstupního textu. V metodě SendMenuText se nejprve zjistí, zda jsou s událostí MenuTextEvent registrované posluchače (zda událost není null), a v případě, že tomu tak není, je vytvořen objekt typu UpdateMenuTextEventArgs, do kterého zabalí text, jenž se má odeslat hostitelské aplikaci. Následně je probuzena událost MenuTextEvent s vytvořenými argumenty. Hostitelská aplikace tyto argumenty obdrží a zobrazí výstupní text. // Delegát sloužící k připojení k notifikaci o změně textu public delegate void UpdateMenuTextEventHandler(object sender, UpdateMenuTextEventArgs e); // Událost, kterou mohou využít klienti kdykoliv dojde ke změně textu
public event UpdateMenuTextEventHandler MenuTextEvent; public void SendMenuText(string menuText) { //nastavení textu k poslání this.CurrentMenuText = menuText; //zjistí, zda jsou s událostí registrované metody if (this.MenuTextEvent != null) { //spustí metody registrované s událostí this.MenuTextEvent(this, new UpdateMenuTextEventArgs(CurrentMenuText)); } }
// Property k nastavení aktuálního textu, který se má odeslat private String CurrentMenuText { get; set; }
22
Posledním stavebním kamenem, který chybí, je definovat argumenty, jež může Workflow posílat hostitelské aplikaci ve třídě UpdateMenuTextEventArgs. Ta slouží k zapouzdření textu, který je potřeba poslat z WorkflowEnginu do formuláře aplikace. Stačí poslat pouze výstupní text automatu: public class UpdateMenuTextEventArgs :EventArgs { // Text, který je odeslán do aplikace public String MenuText { get; set; } // Konstruktor argumentů public UpdateMenuTextEventArgs(String lMenuText) { this.MenuText = lMenuText; } }
5.6 Implementace workflow V této části vysvětlíme, jak modelovat a následně implementovat jednoduché stavové workflow pro platební bankomat. 5.6.1. Modelování workflow Prvním úkolem bude vytvořit počáteční stav bankomatu. Při vstupu do tohoto svatu by mělo workflow odeslat aplikaci bankomatu zprávu: „Jsem v počátečním stavu, čekám na vložení karty. “ Toho docílíme následujícími kroky: 1. Vytvoříme dva stavy – stav, kdy automat čeká na kartu, a stav, kdy již byla karta vložena. 2. Do počátečního stavu přidáme aktivitu StateInitialization – ta se provede vždy při vstupu workflow do stavu. 3. Do StateInitialization aktivity vložíme aktivitu CallExternalMethod – budeme chtít volat metodu komunikační služby, která oznámí bankomatu, co má zobrazit ve výstupním okně. 4. Vložíme do stavu aktivitu EventDriven – tuto aktivitu budeme chtít probudit po vložení karty. 5. Do této aktivity vložíme aktivitu HandleExternalEvent – ta zpracuje událost vložení karty. 6. Dále do EventDriven aktivity vložíme aktivitu SetState – ta umožní přesunout workflow do jiného stavu. 5.6.2. Vytvoření prázdného stavu Projekt ATMWorkflow, který jsme vytvořili na začátku vývoje, obsahuje standardně třídu Workflow1. Obsahem je workflow diagram, který zatím obsahuje pouze jeden stav.
23
Obrázek 13: Vygenerované workflow s iniciálním stavem
Využijeme tento stav pro náš účel a přejmenujeme stav na WaitingForCardState. Dále bude nutné přidat nový stav, do kterého workflow přejde po vložení karty. Z Toolboxu vybereme položku State a přetažením vložíme do workflow.
Obrázek 14: Objekt State v Toolboxu
Vložený stav je vhodné přejmenovat na CardInsertedState. 5.6.3. Vložení aktivity StateInitialization Do stavu vložíme aktivitu StateInitialization. Tuto aktivitu najdeme v Toolboxu ve skupině aktivit označené jako Windows Workflow v3.0. Aktivitu vložíme do workflow přetažením na počáteční stav.
Obrázek 15: Aktivita StateInitialization v Toolboxu
StateInitialization se provede vždy během vstupu workflow do daného stavu. Po jejím vložení se zobrazí její detail. Aktivitu přejmenujeme pomocí okna vlastností na WaitingForCardInitialize. Budeme chtít, aby se při vstupu do tohoto stavu odeslal do formuláře aplikace text: „Vložte kartu.“ Toho docílíme tak, že z námi vytvořené StateInitialization zavoláme externí metodu SendMenuText, kterou jsme definovali v komunikační službě ATMService.
24
5.6.4. Vložení aktivity CallExternalMethod Přetáhneme tedy do StateInitialization z Toolboxu aktivitu CallExternalMethod. Výsledek by měl vypadat zhruba takto:
Obrázek 16: Detail stavu „WaitingForCardState“
Aktivitu můžeme v okně vlastností opět přejmenovat na CallShowMainMenu. Červený vykřičník v rohu aktivity CallExternalMethod naznačuje, že bude nutné upravit její vlastnosti. Otevřeme okno vlastností této aktivity a uvidíme, které vlastnosti je nutné modifikovat. Protože bude nutné jako v InterfaceType vybrat službu ATMService, která je ovšem v jiném projektu než samotné workflow, nejprve přidáme tento projekt do referencí workflow. Po kliknutí pravým tlačítkem na projekt ATMWorkflow vybereme Add Reference a na záložce Projects vybereme komunikační projekt obsahující třídu ATMService. Nyní po kliknutí na vlastnost InterfaceType se zobrazí dialog, ve kterém vybereme ATMService, tak jak je zobrazeno na následujícím obrázku:
Obrázek 17: Nastavení vlastnosti InterfaceType aktivity CallExternalMethod
25
Nyní, jak ukazuje červený vykřičník, je nutné vybrat externí metodu, která se má zavolat. V rozevíracím seznamu se zobrazí jediná metoda: SendMenuText.
Obrázek 18: Přehled vlastností aktivity CallExternalMethod
Protože metoda má jeden argument menuText typu String, tak se tento argument automaticky zobrazí v okně vlastností. Do pole menuText můžeme vepsat přímo text, který chceme odeslat do hostující aplikace. Další možností je napojit (bind) toto pole na novou nebo již existující proměnnou ve třídě workflow. Po kliknutí na tři tečky, jež se objeví v rohu vlastnosti menuText, se otevře speciální dialog, který umožní napojení na nové pole. Pole pojmenujeme například insertCard.
Obrázek 19: Napojení vlastnosti aktivity na nové pole
26
Při zobrazení zdrojového kódu workflow můžeme nyní například rovnou nastavit hodnotu této nově vytvořené proměnné. namespace ATMWorkflow { public sealed partial class Workflow1 : StateMachineWorkflowActivity { public Workflow1() { InitializeComponent(); } public String insertCard = "Vložte prosím kartu"; } }
Krátká rekapitulace: Vytvořili jsme nový stav. Do něj jsme vložili aktivitu StateInitialization. V této aktivitě voláme externí metodu komunikační služby pomocí aktivity CallExternalMethod. Nyní zbývat namodelovat a naprogramovat vložení karty a přesunutí workflow do nového stavu. 5.6.5. Vložení aktivity EventDriven Exekuce EventDriven aktivity je svázaná s určitou událostí, a je to vlastně EventHandler, který se provede poté, co je přes komunikační interface probuzena určitá událost. Aktivitu najdeme v Toolboxu ve skupině Windows Workflow v3.0. Do stavu ji vložíme opět přetažením.
Obrázek 20: Aktivita EventDriven v Toolboxu
Po vložení bude náš stav vypadat následujícím způsobem:
Obrázek 21: Detail stavu WaitingForCardState
Po dvojkliku na právě vloženou aktivitu eventDrivenActivity1 se otevře její detail. Aktivitu přejmenujeme na „CardInsertedEvent“ a pokračujeme dalším krokem, kterým je vložení HandleExternalEvent. 5.6.6. Vložení aktivity HandleExternalEvent – zpracování události HandleExternalEvent najdeme opět v Toolboxu:
27
Obrázek 22: Aktivita HandleExternalEvent v Toolboxu
Po vložení aktivity nám opět červený vykřičník u vlastností InterfaceType a EventName prozradí, že je nutné tyto vlastnosti doplnit.
Obrázek 23: WaitingForCardState – HandleExternalEvent
Otevřeme kontextovou nabídku kliknutím na tři tečky u vlastnosti InterfaceType. Zde je opět nutné vybrat komunikační rozhraní. Pomocí stejného postupu jako v kroku 2 vybereme rozhraní IATMService. Nyní je již pouze nutné vybrat EventName, tedy událost, kterou chceme touto aktivitou zpracovat. Z kontextové nabídky vybereme vlastnost CardInserted. Tato aktivita nevolá žádnou další metodu. Pouze čeká a je probuzena událostí CardInserted. Jakmile je však probuzena a zpracována, může workflow pokračovat dál. Pro náš účel bude vhodné, aby workflow pokračovalo vstupem do stavu „Karta vložena“. 5.6.7. Vložení aktivity SetState – přechod workflow do stavu „Karta vložena“ Nyní pod dříve vloženou aktivitu, která zpracuje událost CardInserted, vložíme aktivitu SetState.
Obrázek 24: Aktivita SetState v Toolboxu
Po vložení aktivity vidíme v jejích vlastnostech, že jedinou vlastností, kterou je nutné nastavit, je TargetStateName – tedy cílový stav. V kontextovém menu vlastnosti TargetStateName máme na výběr ze dvou stavů. Jedním je ten, v němž se právě nacházíme, a druhým ten, který je vhodné vybrat: CardInsertedState.
28
Obrázek 25: Vlastnosti aktivity SetState
Když si nyní zobrazíme celkové workflow, uvidíme oba dva propojené, přechodovou hranou.
Obrázek 26: Workflow po vložení prvních dvou stavů
Tímto jsme provedli prvních šest kroků, kterými jsme schopni odeslat do aplikace výstupní text po vstupu do stavu, zpracovat událost vložení karty a přejít po této události do stavu, ve kterém budeme moci dále provádět zpracování zadání PINu.
5.7 Dokončení modelu workflow pro platební bankomat Pokud chceme namodelovat takové workflow, které bude odpovídat stavovému diagramu uvedenému v kapitole 5.2, bude nutné, aby workflow obsahovalo stejný počet stavů jako stavový diagram a stejné přechody mezi nimi. Nebudeme zde podrobně rozebírat vytvoření celého workflow. Zaměříme se pouze na některé detaily, které se liší od postupů uvedených v předchozí kapitole. Na následujícím obrázku je konečný návrh workflow diagramu pro platební bankomat.
29
Obrázek 27: Stavové workflow v Designeru Visual Studia 2008
Každý stav obsahuje vnitřní aktivity; jde v zásadě vždy o dvě aktivity, již zmíněné v předchozí kapitole.
StateInitialization – obsahuje všechny aktivity, které se mají provést při inicializaci stavu, tedy při vstupu workflow do tohoto stavu.
EventDriven – obsahuje aktivity, které se provádějí při obdržení externí události z hostitelské aplikace, například „PIN obdržen“.
Každý stav obsahuje jednu aktivitu typu StateInitializationActivity, ve které odesílá výstupní text do hostitelské aplikace a pak několik aktivit typu EventDrivenActivity, jimiž reaguje na různé události, které mohou nastat. Například ve stavu CardEnteredState jsou obsaženy dvě aktivity tohoto typu:
CardRemovedEvent – reaguje na vyjmutí karty.
PINEnteredEvent – reaguje na zadání PINu.
30
Na příkladu PINEnteredEvent aktivity ze stavu CardEnteredState si můžeme ukázat, jak je možné na základě probuzené události a obdržených parametrů rozvětvit workflow a poslat do různých stavů. Na následujícím obrázku je detail aktivity PINEnteredState:
Obrázek 28: Detail aktivity vyvolané událostí „PIN vložen“
První aktivitou, která je prováděna při obdržení externí události, je HandleExternalEvent (v diagramu je to aktivita pojmenovaná handlePinEnteredActivity) a k jejímu vykonání dochází v okamžiku, kdy workflow obdrží pomocí služby ATMService událost PINEnteredEvent. Jakmile je tato událost obdržena, spustí se následující aktivita typu IfElse, při které se vyhodnotí, zda byl zadán správný PIN. Vidíme dvě větve, z nichž každá obsahuje aktivitu typu SetState. Tato aktivita zaručuje přechod do dalšího stavu. V případě, že byl PIN zadán v pořádku, přecházíme do stavu PINEnteredState, v případě, že nebyl zadán pořádku, zůstáváme ve stavu CardEnteredState (aplikace tak znovu požádá uživatele o vložení PINu). Při vytváření této aktivity postupujeme podobně jako ve výše uvedeném případě. Rozdíl je v tom, že při zpracování vnější události PINEntered je nutné získat z argumentů této události vložený PIN. Po vložení HandleExternalEvent musíme nastavit InterfaceType a EventName, tak jak je ukázáno na obrázku.
31
Obrázek 29: Vlastnosti aktivity zpracující událost vložení stavu
Nyní ovšem ještě napojíme argumenty události zde určené vlastností pojmenovanou „e“ na novou proměnnou, kterou si uložíme do workflow. Otevřeme dialog pro napojení a pojmenujeme novou proměnnou:
Obrázek 30: Napojení obdržených argumentů události na novou proměnnou
Nyní vložíme aktivitu IfElse, která nám umožní rozdělit běh workflow pro různě zadané PINy. Po vložení této aktivity si všimneme, že u jedné z větví svítí červený vykřičník. Je totiž nutné alespoň u jedné z větví nastavit podmínku pro průchod touto větví. U vlastnosti Condition zvolíme Declarative Rule Condition.
Obrázek 31: Vlastnosti aktivity IfElse
32
Declarative Rule Condition umožní vytvořit jednoduchá pravidla, která určí, kdy je daná podmínka splněna. Jedná se vlastně o logické výrazy, které si Designer workflow ukládá v položce souborech s příponou .rules. Každé workflow defaultně obsahuje alespoň jeden takovýto soubor. Klikneme-li tedy vpravo na tlačítko u vlastnosti ConditionName, otevře se okno správce těchto pravidel. Ještě v něm není uloženo žádné pravidlo. Klikneme tedy na tlačítko „New“ a vytvoříme nové pravidlo. Otevře se k tomu speciální editor těchto výrazů.
Obrázek 32: Vytvoření deklarativního pravidla
Zadáme uvedený výraz. V něm se odkazujeme na získané argumenty události PINEntered. Ze skupiny těchto argumentů nás zajímá právě proměnná Pin. Porovnáme ji s jakoukoliv jinou stringovou proměnnou, která bude obsahovat PIN karty. Výsledná vytvořená podmínka se pojmenuje „Condition1“, je možné jí přejmenovat, aby byl seznam v budoucnu, kdy bude podmínek více, přehlednější. Nyní je již možné do jednotlivých větví aktivity IfElse vložit aktivity SetState, které posunou workflow do požadovaných stavů.
5.8 Shrnutí modelování a programování workflow Z výše zmíněných příkladů by mělo být jasné, že stavové workflow je souhrn stavů. Aby mohla být ve stavu provedena určitá činnost, musí stav obsahovat některou z aktivit. Aktivity nemohou být ve stavu přímo vloženy bez určení času jejich spuštění. Proto musí každý stav obsahovat nejprve aktivitu StateInitializationActivity nebo StateFinalizationActivity, které udávají, zda a kdy má ke spuštění určité činnosti dojít. Další a poslední možností jsou potom EventDrivenActivity. Jejich spuštění je inicializováno obdržením události od hostitelské aplikace.
33
5.9 Hostitelská aplikace Hostitelská aplikace je reprezentována klasickým formulářovým dialogem s několika tlačítky a vstupním a výstupním textovým polem. Jak již bylo řečeno, aplikace musí obsahovat instanci třídy WorkflowRuntime. WorkflowRuntime umožňuje spouštění a správu instancí workflow. V případě bankomatu tento runtime spravuje pouze jednu instanci workflow. Pokud by uměl bankomat paralelně pracovat s několika kreditními kartami najednou, mohla by být pro každou „seanci“ vytvořena vlastní instance workflow. 5.9.1. Potřebné objekty Pro komunikaci s instancí workflow musí hostitelská aplikace obsahovat instanci třídy ATMService, tedy službu, která tuto komunikaci umožňuje. Tato služba je registrovaná s kontejnerem WorkflowRuntime a poskytuje workflow ty události, které vyvolávají přechody mezi stavy. Následující část kódu ukazuje proces inicializace WorkflowRuntime a registrace ATMService. public partial class MainForm : Form { private WorkflowRuntime runtime; private ATMService atmService; private StateMachineWorkflowInstance stateMachineWorkflowInstance; private Guid workflowInstanceId; public MainForm() { InitializeComponent(); } }
5.9.2. Inicializace WorkflowRuntime Při spuštění aplikace je nutné provést inicializaci WorkflowRuntime a jeho spuštění. Dále je nutné inicializovat a připojit komunikační službu ATMService. Můžeme také nastavit EventHandlery událostem, které obsahuje WorkflowRuntime, tedy spuštění, uspání a ukončení workflow. Všechny tyto události jsou prováděny v metodě StartWorkflowRuntime(), která je volána během inicializace formuláře.
34
private void StartWorkflowRuntime() { runtime = new WorkflowRuntime(); //Vytvoříme posluchače událostí, které dodává WorkflowRuntime. runtime.WorkflowTerminated += new EventHandler<WorkflowTerminatedEventArgs>(runtime_WorkflowTerminated); runtime.WorkflowCompleted += new EventHandler<WorkflowCompletedEventArgs>(runtime_WorkflowCompleted); runtime.WorkflowIdled += new EventHandler<WorkflowEventArgs>(runtime_WorkflowIdled); //spuštění Workflow Runtime runtime.StartRuntime(); //Vytvoříme službu pro správu komunikace hostující aplikace a workflow ExternalDataExchangeService dataExchangeService = new ExternalDataExchangeService(); //Registrujeme tuto službu s WorkflowRuntimem runtime.AddService(dataExchangeService); //Vytvoříme novou službu – pro komunikaci WF – hostitelská aplikace atmService = new ATMService(); //Přidáme ke službám registrovaným s WorkflowRuntimem dataExchangeService.AddService(atmService); //Registrujeme posluchače událostí, které nám bude posílat workflow atmService.MenuTextEvent += new ATMService.UpdateMenuTextEventHandler(atmService_MenuTextEventHandler); }
V aplikaci Bankomat se tato část programu vykonává při inicializaci formuláře. Kromě kroků inicializace WorkflowRuntime a registrace komunikační služby je v posledním řádku registrován nový EventHandler (posluchač) události MenuTextEvent. Pomocí této události předává instance workflow hostitelské aplikaci výstupní text. Tato událost je vybuzena vždy v inicializaci nového stavu. 5.9.3. Spuštění instance workflow uvnitř WorkflowRuntime Dalším nutným krokem je vytvoření instance workflow a její spuštění. Vytvoření se provádí pomocí třídy WorkflowRuntime a metody CreateWorkflow(Type), které se jako parametr předává typ workflow, jež má být vytvořeno.
35
private void StartATMWorkflow() { //Vytvoříme instanci workflow typu ATMWorkflow WorkflowInstance instance = runtime.CreateWorkflow(typeof(ATMWorkflow)); //spuštění této instance uvnitř WorkflowRuntimu instance.Start(); //získání instance stavového workflow, aby bylo možné přistupovat ke stavům stateMachineWorkflowInstance = new StateMachineWorkflowInstance(this.runtime, instance.InstanceId); //získáme ID instance,abychom jí mohli posílat události workflowInstanceId = stateMachineWorkflowInstance.InstanceId; }
Jako návratová hodnota z metody CreateWorkflow(Type) je obdržen objekt typu WorkflowInstance, tedy odkaz na instanci workflow, následně je možné získat i objekt typu StateMachineWorkflowInstance. Tento objekt umožňuje přístup k některým užitečným informacím o spuštěné instanci stavového workflow, především její aktuální stav. Tyto objekty je nutné uchovat, protože umožňují posílat instanci workflow události, tedy změny stavů, vyvolané stisky jednotlivých tlačítek. 5.9.4. Volání událostí komunikační služby Následující část aplikace ukazuje, jak se volají události obsažené ve službě ATMService a jak je tato služba doručí konkrétní instanci workflow uvnitř WorkflowRuntime. Zde ukázaná metoda EventHandlerem stisku libovolného tlačítka. Podle textu tlačítka se rozpozná, která událost se má probudit a odeslat do WorkflowRuntime. Pro ukázku jsou zde zpracována pouze dvě tlačítka: „Vložení karty“ a „Potvrzení PINu“. // Event Handler, připojený na stisk všech tlačítek ve formuláři bankomatu private void ButtonEventHandler(object sender, EventArgs e) { //Odesílací tlačítko Button lButton = sender as Button; string text = lButton.Text; //porovnáme text a zavoláme příslušnou událost if (lButton.Text == "Vložit kartu") { //volání události Karta vložena atmService.RaiseCardInsertedEvent(workflowInstanceId); } else if (lButton.Text == "Potvrdit PIN") { //volání události PIN vložen atmService.RaisePINEnteredEvent(workflowInstanceId, txbInput.Text); } }
Metoda nejprve detekuje, z jakého tlačítka byla tato událost vyvolána, a podle toho zavolá jednu z metod ATMService, která probudí (Raise) některou událost z této služby.
36
Například po stisku tlačítka „Potvrdit PIN“ se vyvolá metoda, která probudí událost PinEnteredEvent. Jako argumenty se této metodě předají identifikace instance workflow a vložený PIN. Pokud se workflow nachází ve stavu CardEnteredState, tato aktivita ho probudí a jako argument je mu doručen PIN. Jak bylo popsáno výše, PIN bude vyhodnocen a workflow se přesune do nového stavu. Při stisku tlačítka „Vložit kartu“ se pouze probudí událost CardInserted, ale kromě ID workflow, kterému má být doručena, již není nutné přidávat další argumenty. 5.9.5. Obdržení a zpracování události o přechodu do nového stavu Kromě probouzení událostí, jež způsobují přechody mezi stavy workflow, poslouchá hostitelská aplikace také události, které jí posílá workflow. Takovou událostí je MenuTextEvent služby ATMService. Registrace EventHandleru k této události probíhá již při registraci služby, v inicializaci formuláře. V případě obdržení této události obdrží EventHandler argumenty události ve formě instance třídy UpdateMenuTextEventArgs. Tato instance má proměnnou MenuText, jež obsahuje řetězec se zprávou, kterou hostitelská aplikace zobrazí ve výstupním okně. Toto je řádek, kterým se přidá posluchač události: atmService.MenuTextEvent += new ATMService.UpdateMenuTextEventHandler(atmService_MenuTextEventHandler);
Nyní je nutné implmentovat metodu atmService_MenuTextEventHandler, která se stará o zpracování události. void atmService_MenuTextEventHandler(object sender, UpdateMenuTextEventArgs e) { //nastavíme RTF výstupního pole. Tedy nastavíme výstupní text outputWindow.Text = e.MenuText; }
V ideálním případě by vše mělo již fungovat. Narazíme zde ale na problém. V .NETu není povoleno updatovat nebo editovat grafické prvky, tedy GUI aplikace, z jiného vlákna než z vlákna, kterým byly vytvořeny. To je ale problém, protože instance workflow běží v jiném vlákně než samotná aplikace. Je tedy nutné obejít tento probléme pomocí nového delegáta, kterého vytvoříme přímo v hostitelské aplikaci. K tomuto delegátovi registrujeme tu samou metodu jako při registraci k události od WorkflowRuntimu a vyvoláme tohoto delegáta pomocí metody Control.Invoke(Delegate). Tím, že tuto metodu zavoláme na aktuálním formuláři, budou metody, které jsou s delegátem registrovány, spuštěny z aktuálního vlákna. V těle metody dále přidáme if klausuli, ve které otestujeme proměnnou Control.InvokeRequiered, jež je v .NETu právě pro tento účel a určuje, zda je nutné Invoke provést.
37
Jinými slovy, když dojde k prvnímu volání metody z vlákna instance workflow, tak se pomocí proměnné InvokeRequiered zjistí, že je nutné volat metodu z aktuálního vlákna. To se provede pomocí nového delegáta, kterému se předají všechy parametry. Při druhém volání již není nutný nový Invoke a pouze se nastaví výstupní text aplikace. private delegate void UpdateMenuTextDelegate(object sender,UpdateMenuTextEventArgs e); void atmService_MenuTextEventHandler(object sender, UpdateMenuTextEventArgs e) { //Pokud je potřeba pustit metodu z jiného vlákna if (this.InvokeRequired) { //Vytvoříme delegáta, s odkazem na tuto metodu UpdateMenuTextDelegate updateMenuText = new UpdateMenuTextDelegate(atmService_MenuTextEventHandler); //předáme argumenty, které obdržela tato metoda object[] args = new object[2] { this, e }; //zavoláme delegáta z vlákna aktuálního formuláře this.Invoke(updateMenuText, args); } else { outputWindow.Text = e.MenuText; } }
5.10 Shrnutí kapitoly o implementaci jednoduchého platebního bankomatu K vytvoření takovéto aplikace je tedy zapotřebí tří projektů:
Workflow pro namodelování stavového diagramu aplikace
Komunikační rozhraní
Hostitelská aplikace obsahující uživatelské rozhraní
Je nutné začít od komunikačního rozhraní, v němž se definují události, pomocí kterých mezi sebou mohou workflow a uživatelská aplikace komunikovat. Následně je možné namodelovat workflow pomocí workflow designéru. Zde je důležité si uvědomit, že každý stav musí obsahovat jednak aktivity, které se spustí při přechodu workflow do stavu, a jednak aktivity, jež umožní reagovat na události od hostitelské aplikace. Hostitelská aplikace musí obsahovat především instance třídy WorkflowRuntime a instanci komunikační služby. Je nutné implementovat volání především vyvolávání jednotlivých událostí, které jsou doručeny instancím workflow uvnitř WorkflowRuntime. Také je nutné implementovat odposlouchávání událostí, které workflow posílá hostitelské aplikaci.
38
6. Vývoj aplikací v prostředí SharePointu – co je potřeba K vývoji na platformě SharePoint 2007 potřebujeme dva základní nástroje:
SharePoint 2007 (na operačním systému Windows Server) Visual Studio 2008
Vývoj aplikací pro SharePoint 2007 má jednu podstatnou nevýhodu, a to fakt, že počítač, na kterém vyvíjíme, musí mít nainstalovaný SharePoint 2007. SharePoint 2007 je serverové řešení, a proto musí být nainstalován na operační systém Microsoft Windows Sever. Zároveň je postaven na databázi a ve standardní instalaci je obsažen SQL Server 2005. Pokud tedy nemáte vývojový počítač, který by používal Microsoft Windows Server, nebo máte, ale nechcete si instalovat SharePoint přímo na vývojový počítač, nabízí se vhodná a nejčastěji používaná alternativa, a to vytvoření virtuálního prostředí. K tomu je nejvhodnější využít program MS Virtual PC, který je zdarma. Nebudeme zde uvádět konkrétní návod na instalaci SharePointu ve virtuálním prostředí. Zmíníme jen pár detailů. Při vytváření nové Virtual Machine je nutné specifikovat:
Množství operační paměti, které chceme virtuálnímu stroji přidělit. Vhodné jsou 2Gb, nicméně při nedostatku paměti na hostujícím stroji lze použít pouze 1Gb. Velikost disku a typ disku. Na virtuální stroj bude nutné nainstalovat kromě operačního systému i SharePoint 2007 a Visual Studio 2008. Pokud nebudete instalovat další větší aplikace, tak by 10 GB mělo být dostatečných. Pokud vytvoříte disk typu „Fixed size“, můžete zrychlit výkon virtuálního stroje, neboť diskový prostor se nealokuje na začátku a nebude nutné postupné rozšiřování. Ztratíte tím ale možnost disk rozšířit, pokud vám na něm dojde místo.
Jakmile máte připraven vývojový počítač s SharePointem a Visual Studiem 2008, můžeme se pustit do vývoje.
39
7. Popis aplikačního rozhraní MS SharePoint MS SharePoint je intranetový informační systém. Vstupem do tohoto systému je webové rozhraní. SharePoint si klade za cíl sloužit jako server kombinující správu obsahu (CMS), správu procesů (Workflow) a umožnění spolupráce a komunikace pro jeho uživatele. Pomocí webu se mohou uživatelé podílet na vytváření obsahu webu. SharePoint obsahuje šablony pro vytváření seznamů, osobních webů, knihoven dokumentů, diskuzních skupin, dotazníků, kalendářů, webových galerií a dalších typů obsahu. Tyto šablony může běžný uživatel využít bez hlubších znalostí technologie, vytváření obsahu tedy probíhá pouze prostřednictvím webového rozhraní. Následující obrázek znázorňuje webové rozhraní portálové stránky.
Obrázek 33: Webové rozhraní SharePointu
Kromě toho, že se uživatelé sami podílí na vytváření obsahu webu, mohou také rozhodovat o tom, jakým způsobem bude obsah zobrazen a kdo k němu bude mít přístup.
7.1 Architektura MS SharePoint Architekturu systému MS SharePoint popisuje následující diagram:
40
Architektura technologie SharePoint Windows SharePoint Services Definice práv a uživatelů
Grafické rozhraní
Podpora pro Workflow
Podpora Administrace
Napojení na Active Directory
Integrace se službami MS Office
Prohledávání obsahu
Napojení na mail server
Workflow Foundation
ASP.NET SQL Server IIS
.NET Framework
Windows 2003 / 2007 Server
Základem pro MS SharePoint je Windows Server. Další podmínkou je přítomnost databázového SQL Serveru a IIS (Internet Information Services). Internet Information Service je druhým nejpoužívanějším webovým serverem hned po Apache Serveru, který je známý vývojářům pracujícím s programovacími jazyky JAVA nebo PHP (PHP Hypertext Preprocessor). Je to sada služeb, jež umožňují dynamické vytváření webového obsahu, o který si uživatel zažádá, prostřednictvím webového prohlížeče. Internet Information Service umožňuje publikování webových aplikací napsaných pomocí technologie ASP.NET. Protože SharePoint je intranetový portál, je tvořen sadou ASPX souborů, které definují stránky tohoto portálu, a sadou dynamických knihoven, jež jsou s těmito stránkami linkovány a zajišťují logiku tohoto portálu. SharePoint tedy potřebuje ke svému chodu Internet Information Service, aby mohly být publikovány webové formuláře, které ho tvoří. Dalším důležitým stavebním kamenem je SQL Server. SharePoint je server sloužící ke správě obsahu a všechna data, která jsou do něj přes webové rozhraní ukládána, musí být uložena do SQL databáze. Další vrstvou je poté .NET Framework. V diagramu jsou pro ilustraci zobrazeny komponenty ASP.NET a Workflow Foundation, ačkoliv jsou již součástí .NET Frameworku. Nad těmito vrstvami je následně postaveno aplikační rozhraní SharePointu, označované jako Windows SharePoint Services.
41
7.2 Definice přístupových práv SharePoint je napojen na technologii Active Directory, která je postavená na protokolu LDAP (Lightweight Directory Access Protocol). Active Directory je centrálním úložištěm uživatelů operačních systémů Windows, kteří jsou rozděleni do takzvaných domén. Uživatel přihlašující se k počítači pod operačním systémem Windows se může přihlásit přímo na tento počítač anebo do domény. Přihlášením do domény je mu zpřístupněna organizační struktura na základě jeho uživatelských práv nastavených v této doméně. Domény velice často kopírují personální struktury firem a organizací. SharePoint používá autentifikaci na základě LDAP protokolu vůči Active Directory Serveru. Pokud se uživatel přihlásí k webu SharePointu, je podle aktuálního kontextu zjištěn uživatel přihlášený k operačnímu systému Windows, a pokud má nastavena dostatečná práva, je vpuštěn do SharePointu. Pokud práva nemá, zobrazí se výzva ke vložení identifikačních údajů, které jsou potom zkontrolovány pomocí Active Directory Serveru.
7.3 Objektový model SharePoint SharePoint Object Model označuje knihovnu tříd uspořádanou do několika jmenných prostorů (namespaces), pomocí které je SharePoint server naprogramován a která je otevřena vývojářům k jeho editaci. Každá část webové stránky, jakýkoliv seznam, webová galerie, soubor, položka seznamu nebo jiný typ obsahu, vše má svůj ekvivalent v objektovém modelu. Programátoři mohou ke všem těmto objektům pomocí tohoto modelu přistupovat (3). Objektový model Windows SharePoint Services je rozdělen na dva základní jmenné prostory. Těmi jsou Microsoft.SharePoint namespace a Microsoft.SharePoint.Administration. První jmenný prostor umožňuje přístup k obsahu webů, druhý definuje třídy, které slouží k přístupu k nižším úrovním, jako jsou servery, webové služby, databázová připojení serverové farmy a další. Namespace Microsoft.SharePoint umožňuje vývojářům přístup k obsahu webu. Tento jmenný prostor obsahuje desítky tříd detaily lze najít v dokumentaci objektového modelu SharePointu (4), my se v následujícím diagramu omezíme jen na několik základních tříd.
42
SPSite
SPUser SPUser
sdssds SPWeb
SPFolder
SPFile
SPList
SPField
SPListItem
Obrázek 34: Objektový model SharePointu
Každá třída SPSite neobsahuje referenci na konkrétní třídu SPWeb, ale obsahuje třídu SPWebCollection, tedy několik tříd SPWeb v této kolekci, reprezentujících několik konkrétních webů. Stejně tomu je i u všech ostatních tříd. Jména tříd jsou poměrně jednoznačná a není potřeba vysvětlovat, ke kterým položkám pomocí těchto tříd získáme přístup. Prefix SP je součástí jmenné konvence a mají ho všechny třídy související s objektovým modelem SharePointu. K diagramu je přiložen obrázek se zobrazeným seznamem v SharePointu. Ten ukazuje, ke kterým grafickým komponentám třídy diagramu umožňují přístup.
43
8. Manipulace s položkami v seznamu pomocí SharePoint API V tomto příkladu vytvoříme jednoduchou aplikaci, která nám umožní pochopit základ programování v SharePointu, čímž jsou práce se seznamy a položkami. Cílem tohoto příkladu bude vytvořit v SharePointu seznam, který bude reprezentovat „katalog produktů“. Každý produkt bude obsahovat sloupec „Je v prodeji“, jenž bude moci nabývat hodnot „Ano/Ne”. Naprogramujeme jednoduchou konzolovou aplikaci, jež projde celý katalog produktů a vymaže z něj položky, které již nejsou v prodeji.
8.1 Příprava seznamu v SharePointu Nejprve připravíme seznam a položky, se kterými budeme později pomocí aplikačního rozhraní SharePointu pracovat. Administrace a vytváření obsahu v SharePointu není obsahem této brožury, navíc jde o oblast velice intuitivní. Nebudeme zde tedy popisovat všechny kroky, jež jsou nutné, ale pouze ty, které budou souviset s níže popsanými ukázkami kódu. Vytvoříme si tedy seznam v SharePointu, který pojmenujeme například „Katalog produktů“.
Obrázek 35: SharePoint — vytvoření nového seznamu
Do tohoto seznamu přidáme sloupec „Popis“ a sloupec „Je v prodeji“, který bude typu „Yes/No“ – tedy booleovská hodnota. V české verzi je to sloupec typu „Ano/Ne“:
44
Obrázek 36: SharePoint — vytvoření nových polí v seznamu
Kromě těchto dvou sloupců bude seznam obsahovat ještě další tři sloupce: „Created By“, „Modified by“ a „Title“; tyto sloupce jsou automaticky vytvořeny SharePointem při vytváření nového seznamu. Sloupec „Title“ využijeme, ale přejmenujeme ho na „Produkt“. Do seznamu vytvoříme ručně několik položek. Výsledek by měl vypadat zhruba takto:
Obrázek 37: Ukázkový seznam pro práci s položkami
8.2 Vytvoření projektu ve Visual Studiu Nyní se již pustíme do programování. Ve Visual Studiu 2008 založíme nový projekt – konzolovou aplikaci. Protože v projektu budeme používat API SharePoint, musíme na něj přidat referenci. V dialogu pro přidání referencí vybereme Windows SharePoint Services.
45
Obrázek 38: Vložení referencí na objektový model SharePointu
Projekt již obsahuje vygenerovanou třídu Program.cs s Main metodou. Po přidání reference na API SharePoint můžeme přidat direktivu using. using Microsoft.SharePoint;
8.3 Poznámka o uvolňování objektu objektového modelu SharePointu Nyní již můžeme používat třídy a objekty z programového rozhraní SharePointu. Ještě nez začneme, je nutné zmínit, že při programování v SharePointu můžeme narazit na některé zvláštnosti oproti tradičním metodám, na které jsme zvyklí v prostředí .NET. Jednou z nich je nutnost uvolňovat některé objekty z paměti ručně. Konkrétním příkladem jsou například objekty typu SPWeb a SPSite, které použijeme v následující ukázce. Tyto dvě třídy nám umožní získat instanci portálové stránky SharePointu (SPSite) a libovolného podwebu (SPWeb). Tyto objekty jsou navrženy jako managed objekty, to znamená, že jsou uchovávány na haldě (heap) objektů, kterou spravuje .NET CLR (Common Language Runtime). O vyčištění těchto objektů se za normálních okolností stará GC (Garbage Collector). Nicméně tyto objekty využívají další unmanaged kód a paměť, tedy využívají objekty, které nejsou součástí .NETu a jsou uchovány přímo v paměti a ne na haldě. Protože managed část je mnohem menší než unmanaged část, GC, který by za normálních okolností objekt z paměti vyčistil, si této malé části objektu nevšímá, a tak spolu s ní zůstává v paměti uchovaná i mnohem větší unmanaged část (která již ovšem také není používána). Je tedy nutné objekt uvolnit ručně.
46
K uvolnění stačí na objektu zavolat metodu Dispose(). V C# máme druhou možnost a tou je použití klíčového slova using. Objekt, který je ohraničen pomocí klíčového slova using, je uvolněn z paměti hned po dokončení takto označeného kódu. Toto vysvětlení přispěje k pochopení kódu, který vytvoříme.
8.4 Zdrojový kód příkladu Následuje přímo ukázka zdrojového kódu příkladu. Jde o jednoduchý příklad, a tak bude vše provedeno ve stupním bodě aplikace, tedy v metodě Main. Následující kód můžete zkopírovat přímo do své aplikace. static void Main(string[] args) { //získám stránku SharePointu using(SPSite oSPSite = new SPSite("http://sr-sp-vptest/education")) { //otevřu web na dané stránce using (SPWeb oSPWeb = oSPSite.OpenWeb()) { //získám seznam "Katalog produktů" SPList oSPList = oSPWeb.Lists["Katalog produktů"]; //získám kolekci položek a jejich počet SPListItemCollection oCollection = oSPList.Items; int itemsCount = oCollection.Count; for (int i = itemsCount-1; i >= 0; i--) { //vezmu i-tou položku v kolekci webů SPListItem oItem = oCollection[i]; //zjistím, zda je položka v prodeji bool vProdeji = (bool)oItem["Je v prodeji"]; if (!vProdeji) { //smažu položku, pokud není v prodeji oCollection.Delete(i); Console.WriteLine("Smazána položka číslo: " + i); } } } } }
Na počátku získáme objekt SPSite. Objekt SPSite reprezentuje celou kolekci stránek (týmových webů, podwebů, všechny stránky, které vytvoříme na daném portálu). Když ale do konstruktoru odkážeme přímo na danou stránku, získáme kolekci stránek obsahující pouze tu, kteoru žádáme pomocí odkazu „education“. Tuto stránku pak můžeme otevřít pomocí metody OpenWeb. SPSite oSPSite = new SPSite("http://sr-sp-vptest/education");
SPWeb oSPWeb = oSPSite.OpenWeb();
47
Další možností, jak získat stránku, by bylo získat kolekci stránek celého portálu a z této kolekce vybrat pouze stránku, kterou potřebujeme: SPSite oSPSite = new SPSite("http://sr-sp-vptest/"); SPWeb oSPWeb = oSPSite.AllWebs["education"];
Oba přístupy jsou ekvivalentní a v objektu SPWeb dostaneme požadovaný „Web“, v terminologii uživatelů SharePointu je ovšem většinou nazýván „Stránka“. Ve výše uvedených ukázkách jsme pro přehlednost vynechali bloky direktivy using. Ovšem v případě, že pracujeme s objekty SPSite a SPWeb, je nutné se o uvolnění paměti vždy starat. Pokud nechceme použít using blok, můžeme na jednotlivých objektech, které implementují rozhraní IDisposable, zavolat metodu Dispose(), jež se postará o uvolnění objektu z paměti. oSPWeb.Dispose(); oSPSite.Dispose();
Tyto techniky jsou velice dobře popsané v Microsoft Developer Network knihovně v článku Best Practices: Using Disposable Windows SharePoint Services Objects (MSDN). Jakmile máme objekt SPWeb, můžeme pomocí jména získat seznam, který nás zajímá, tedy získat kolekci a počet jeho položek: SPList oSPList = oSPWeb.Lists["Katalog produktů"]; SPListItemCollection oCollection = oSPList.Items; int itemsCount = oCollection.Count;
Následně provádíme iteraci. V každém kroku iterace získáme i-tou položku v seznamu a zjistíme, zda je produkt v prodeji. Přetypování na proměnnou typu bool funguje samozřejmě pouze, pokud je sloupec seznamu typu „Ano/Ne“. SPListItem oItem = oCollection[i]; bool vProdeji = (bool)oItem["Je v prodeji"];
8.5 Závěr, poznámky k příkladu Poznámka k iteraci Pokud iterujeme položky, jež během iterace mažeme, nemůžeme použít foreach klauzuli a metodu Delete(), kterou nabízí objekt SPListItem. Při další iteraci hned po prvním smazání se změní iterovaná kolekce a obdržíme následující výjimku. InvalidOperationException: Collection was modified; enumeration operation may not execute. Dalším problém může nastat, pokud zvolíme iteraci „odspodu“, tedy:
48
for (int i=0 ; i
V takovém případě, pokud by došlo alespoň k jednomu smazání položky, změní se indexování položek v kolekci a ke konci iterace (podle toho, kolik položek bylo smazáno) obdržíme výjimku ArgumentOutOfRangeException, protože položky na pozici „i“ již nebudou v kolekci existovat. Závěr Po spuštění programu by měly v seznamu zůstat jen ty položky, které mají pole „Je v prodeji“ nastaveno na „Ano“. To je vše k prvnímu příkladu. Mělo by být jasné, že základem pro přístup k objektům SharePointu jsou třídy SPSite a SPWeb, které nám umožní nalézt danou stránku. Pomocí objektu SPList můžeme s manipulovat jednotlivými seznamy a pomocí objektu SPListItem můžeme libovolně manipulovat i s jednotlivými položky. Znalosti z této části bude možné využít v Příkladu 2, kde provedeme import uživatelských kontaktů z ActiveDirectory do seznamu v SharePointu.
49
9. Ukázková aplikace: Import kontaktů z ActiveDirectory do SharePointu Jedním z možných využití seznamů v SharePointu může být například zobrazení všech kontaktů z určité skupiny v Active Directory v seznamu na SharePointu. V tomto příkladu bych chtěl vytvořit jednoduchou konzolovou aplikaci, která umožní projít uživatele v Active Directory, a pokud má uživatel alespoň jeden z kontaktů – telefon nebo e-mail, vytvořit v SharePointu ekvivalentní položku, do níž bude uživatel importován. Než začneme importovat, je nutné vytvořit seznam v SharePointu, do kterého budeme chtít kontakty přesunout. Vytvoříme pro tento účel standardní seznam kontaktů podle šablony, která je v SharePointu již připravená. Tuto šablonu lze najít při vytváření nového obsahu webu ve skupině Komunikace (Communications). Tato šablona již obsahuje sloupce jako „E-mail“, „Příjmení“, „Telefon“, a navíc jsou tyto sloupce identifikovatelné pod stejným identifikátorem (GUID) na všech jazykových mutacích SharePointu.
9.1 Přístup do Active Directory K provedení takového importu bude nutné nejprve přistoupit do Active Directory a získat odtud uživatelská data. Active Directory je hierarchicky uspořádaná databáze, ve které jsou shromážděna data o všech síťových prvcích v síti. V zásadě se jedná o zařízení a uživatele. Hierarchie Active Directory začíná organizací (Organization) a následují organizační jednotky (Organization Units); ty již obsahují jednotlivé síťové zdroje a zařízení – zjednodušeně řečeno uživatele a počítače. V .NETu lze pro přístup k Active Directory použít namespace System.DirectoryServices. Třídy z tohoto namespace využívají rozhraní Active Directory Services Interface. ADSI je sada programových rozhraní, která umožňuje všeobecnou správu síťových objektů. ActiveDirectory Services Interface je možné použít s několika různými síťovými zprostředkovateli, především WinNT, Novel Netware Directory Services (NDS), Light Directory Access Protocol (LDAP) a Internet Information Services (IIS). Pro přístup k Active Directory je vhodné použít Light Directory Access Protocol, jemž je jediným z výše zmíněných zprostředkovatelů, který podporuje i prohledávání stromu síťové struktury. Jedná se o síťový protokol postavený nad síťovou vrstvou TCP/IP, jemž umožňuje přístup k síťovým objektům. Ze tříd, které obsahuje System.DirectoryServices, budeme používat především následující dvě: DirectoryEntry – základní třída definující jeden objekt ve struktuře Active Directory, ať již jde o počítač, uživatele nebo definici organizační jednotky. DirectorySearcher – třída, která umožňuje prohledávání Active Directory.
50
Objekty typu DirectoryEntry a DirectorySearcher implementují rozhraní IDisposable, a je tedy nutné zavolat funkci Dispose() k uvolnění paměti zabrané těmito objekty. Pokud použijeme direktivu using, této nutnosti se vyhneme a k uvolnění dojde ihned po dokončení akcí definovaných v dané direktivě.
9.2 Vytvoření projektu, přidání referencí Opět půjde o konzolovou aplikaci. Vytvoříme tedy projekt ve Visual Studiu a kromě referencí na Windows SharePoint Service do něj přidáme i reference na namespace System.DirectoryServices.
Obrázek 39: Vložení referencí na objekty sloužící pro přístup k Active Directory
Průběh programu rozdělíme do dvou částí: získání dat z Active Directory a nahrání dat do SharePointu. Abychom měli strukturu pro uchování a manipulaci s daty, vytvoříme třídu „User“, která bude obsahovat pole určující „Jméno“, „Příjmení“, „E-mail“ a „Telefon“.
51
class User { public String public String public String public String
FirstName { get; set; } SurName { get; set; } Email { get; set; } Phone { get; set; }
public User(){} public User(String fn, String sn, String em, String ph) { this.FirstName = fn; this.SurName = sn; this.Email = em; this.Phone = ph; } }
Než začneme programovat, je nutné přidat do projektu referenci na jmenný prostor Microsoft.SharePoint a také referenci na System.DirectoryService. V hlavičce souboru potom použijeme tyto reference: using System.DirectoryServices; using Microsoft.SharePoint;
9.3 Získání uživatelských dat z Active Directory Teď již můžeme přistoupit k implementaci získání dat z Active Directory. Vytvoříme statickou metodu, jejímž jediným parametrem bude řetězec se síťovou adresou Active Directory serveru a bude vracet objekt typu List<User>, tedy seznam uživatelů.
52
public static List<User> GetUsersFromADServer(string url) { List<User> users = new List<User>(); using (DirectoryEntry searchRoot = new DirectoryEntry(url)) { using (DirectorySearcher searcher = new DirectorySearcher(searchRoot)) { //Nastaveni parametru prohledavani String filter = "(&(givenName=*)(Sn=A*)(department=*) + "(objectClass=user)(mail=*)(telephoneNumber=*))"; searcher.Filter = filter; searcher.PageSize = 10000; searcher.PropertiesToLoad.Add("Sn"); searcher.PropertiesToLoad.Add("givenName"); searcher.PropertiesToLoad.Add("mail"); searcher.PropertiesToLoad.Add("telephoneNumber"); using (SearchResultCollection resultCollection = searcher.FindAll()) { if (resultCollection.Count > 0) { foreach (SearchResult result in resultCollection) { //Volam metodu, ktera vytvori uzivatele z vysledku hledani User user = new User(); using (DirectoryEntry userEntry = result.GetDirectoryEntry()) { user.FirstName = userEntry.Properties["givenName"].Value as String; user.SurName = userEntry.Properties["Sn"].Value as String; user.Email = userEntry.Properties["mail"].Value as String; user.Phone = userEntry.Properties["telephoneNumber"].Value as String; //pridam uzivatele do seznamu users.Add(user); }//using DirectoryEntry }//foreach result }//pokud count>0 }//using SearchResultCollection }//using DirectorySearcher }//using DirectoryEntry return users; }
Prní řádek otevře kořenový uzel v Active Directory, ze kterého budeme chtít začít prohledávání. Dále vytvoříme nový objekt DirectorySearcher, který nám umožní prohledávání. Jak již bylo řečeno, Active Directory je stromová, hierarchicky uspořádaná databáze. Prohledávání tedy musí probíhat rekurzivně do hloubky stromu. DirectorySearcher v tomto směru usnadňuje práci, a tak není nutné metody pro rekurzivní prohledávání programovat.
53
Další řádka definuje řetězec, který později použijeme jako filtr pro prohledávání. Jedná se o syntaxi filtrování LDAP protokolu. Znak „&“ za první závorkou značí logickou spojku AND, tedy že budeme chtít splnění všech výrazů uzavřených v takto označené závorce. (& (givenName=*) (Sn=A*) (mail=*) (telephoneNumber=*) (objectClass=user) )
V zásadě zde říkáme, že požadujeme pouze takové objekty typu user (tedy pouze uživatele, tím vypadnou počítače, kontakty a další typy objektů), které mají vyplněné pole „Jméno“, „Příjmení“, „Telefon“ a „E-mail“. Navíc požadujeme pouze objekty, u nichž pole „Příjmení“ začíná velkým písmenem „A“. Vlastnost PageSize určuje maximální omezení počtu objektů, které budou nalezeny pomocí třídy DirectorySearcher. Jak již bylo řečeno, DirectorySearcher prohledává rekurzivně, říkáme mu tedy, po kolika nalezených objektech má vyhledávání zastavit. Následně určíme vlastnosti, jež chceme získat u prohledávaných objektů. Následující řádek přidá vlastnost „Sn“, která odpovídá příjmení uživatele. searcher.PropertiesToLoad.Add("Sn");
Po zavolání metody FindAll() je navrácen objekt typu SearchResultCollection, který můžeme iterací procházet. Tento objekt obsahuje množinu objektů SearchResult. Ty již obsahují výsledky vyhledávání. Je vhodné použít metodu GetDirectoryEntry(), která z daného výsledku vrátí objekt DirectoryEntry, jenž reprezentuje vyhledaný objekt ve stromové struktuře Active Directory. Z tohoto objektu je pak již poměrně snadné získat požadované vlastnosti toho objektu. DirectoryEntry userEntry = result.GetDirectoryEntry(); user.FirstName = userEntry.Properties["givenName"].Value as String;
9.4 Import získaných dat do seznamu kontaktů v SharePointu Druhou částí bude metoda, která data získaná z ActiveDirectory nahraje získané uživatele jako položky dp seznamu v SharePointu. Vytvoříme tedy metodu, jejíž argumenty budou: seznam získaných uživatelů, které chceme nahrát do SharePointu, adresa webu a jméno seznamu kontaktů.
54
public static void UploadToSharePoint(string siteUrl, string listName,List<User> users) { using (SPSite site = new SPSite(siteUrl)) { using (SPWeb web = site.OpenWeb()) { SPList list = web.Lists[listName]; foreach (User user in users) { SPListItem item = list.Items.Add(); item[SPBuiltInFieldId.FirstName] = user.FirstName; item[SPBuiltInFieldId.Title] = user.SurName; item[SPBuiltInFieldId.EMail] = user.Email; item[SPBuiltInFieldId.WorkPhone] = user.Phone; item.Update(); } list.Update(); } } } }
Struktura metody pro získání objektu SPList v SharePointu je stejná jako v předchozím příkladu. Jakmile získáme SPList reprezentující seznam, do kterého chceme objekty naimportovat, procházíme iterací jednotlivé uživatele v seznamu users. Pro přidání nové položky do seznamu je použito následující volání: SPListItem item = list.Items.Add();
Metoda Add() přidá do seznamu novou položku a vrátí ukazatel na tuto položku typu SPListItem. K takto získanému objektu můžeme následně přistoupit a modifikovat jeho vlastnosti. Změny se v SharePointu neprojeví, dokud nezavoláme metodu Update() na položce SharePointu a následně na seznamu v SharePointu. Za zmínku stojí použití třídy SPBuildInFieldId. Tato třída obsahuje GUID pro pole, která jsou v SharePointu již obsažená. Pokud tedy použijeme standardní seznam kontaktů, který již obsahuje standardní pole v SharePointu, můžeme použít ID, jež tato třída obsahuje k referencování těchto polí. Například pro vepsání do sloupce „E-mailová adresa“ ve standardním seznamu kontaktů použijeme následující volání. item[SPBuiltInFieldId.EMail] = user.Email;
V Main metodě – vstupním bodu konzolové aplikace – již jen zavoláme po sobě tyto dvě metody.
55
static void Main(string[] args) { List<User> users = GetUsersFromADServer("LDAP://sr-ad-001.mountfield.lad"); UploadToSharePoint("http://sr-sp-vptest/education/", "Kontakty", users); }
9.5 Závěr Jak je vidět, import uživatelských dat z Active Directory může být poměrně jednoduchou záležitostí. V tomto případě je vždy nutné myslet na uvolňování objektů z paměti, tedy na volání metody Dispose() anebo na používání klíčového slova using. Pokud bychom tak nečinili a program by se spouštěl například pravidelně, tak by při každém spuštění docházelo k alokaci paměti, která by nikdy nebyla uvolněná, a to by mohlo mít vliv na výkonnost serveru.
56
10.
Přidání vlastních ASP stránek do SharePointu
SharePoint ukládá většinu svého obsahu do své databáze obsahu (nejčastěji MS SQL Server). Všechny stránky, které jsou vytvořeny nebo upraveny, ať již z webového rozhraní SharePointu nebo pomocí SharePoint Designeru, jsou uloženy v databázi SharePointu. Tyto stránky ale nemohou obsahovat ani provádět vlastní kód. Existuje však možnost, jak přidat do SharePointu vlastní stránky, které budou obsahovat logiku zkompilovanou do dynamické knihovny, a jak spouštět tyto stránky v kontextu SharePointu. Tímto způsobem je přidání stránek do složky LAYOUTS v „úlu“ SharePointu. (Anglicky je toto umístění označováno jako SharePoint 12 HIVE. ) SharePoint 12 HIVE budeme v následujícím textu označovat jako „úložiště SharePointu“ a cesta k němu je: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12 Složka LAYOUTS má tu vlastnost, že pomocí IIS serveru dochází k její virtualizaci do všech webů SharePointu. Toho můžeme využít, neboť jakýkoliv ASPX soubor, který přidáme, bude virtualizován do všech týmových webů a přístupných z SharePointu. Cílem tohoto příkladu bude zobrazit v SharePoint stránku, na které se zobrazí jméno aktuálně přihlášeného uživatele a aktuální čas.
Obrázek 40: Vestavěná stránka v SharePointu zobrazující aktuálního uživatele a datum
57
10.1 Master Pages Než začneme vytvářet stránky, je nutné si uvědomit, že SharePoint využívá takzvaných Master Pages. Master Pages nahrazují v ASP.NET dědičnost grafických komponent. Master Pages jsou vlastně šablonami. Například na hlavním portálu SharePointu jsou levý a horní panel již definovány příslušnou Master Page a nový obsah je možné vkládat pouze do hlavního okna ohraničeného těmito panely. Master Pages obsahují speciální tagy ContentPlaceHolder, které slouží jako kontejnery pro obsah, jenž je později vložen prostřednictvím stránek, které od této Master Page dědí. Následující příklad ukazuje jednoduchou Master Page: <%@ Master Language="C#" AutoEventWireup="true" CodeBehind="Demonstration.master.cs" Inherits="MPDemonstration.Demonstration" %> Demonstrační Master Page
A nyní příklad stránky, která tuto Master Page používá. V atributu MasterPageFile je odkaz na výše definovanou Demonstration.Master. <%@ Page Language="C#" MasterPageFile="~/Demonstration.Master" AutoEventWireup="true" CodeBehind="MPDemonstration.aspx.cs" Inherits="MPDemonstration.MPDemonstration" Title="Untitled Page" %> A toto již je z obsahu stránky, která dědí Master Page
Výsledek předchozího příkladu vypadá následovně:
58
Obrázek 41: Ukázka využití Master Page
10.2 Vytvoření projektu a přidání referencí Nyní se již pustíme do vývoje vlastní stránky pro SharePoint. Vytvoříme nový projekt typu WebApplication ve Visual Studiu a následně upravíme strukturu projektu, tak aby vypadala následujícím způsobem:
Obrázek 42: Struktura webového projektu
59
Nyní upravíme soubor SPCustomPage.aspx. Jelikož SharePoint používá Master Pages, musíme vědět, jak se jmenují kontejnery typu ContentPlaceHolder, které můžeme použít a do nichž je možné vložit vlastní obsah. My pro svůj obsah využijeme kontejner s ID „PlaceHolderMain“. Do tohoto kontejneru umístíme to, co na stránce SharePointu chceme zobrazit, tedy aktuálně přihlášeného uživatele a aktuální čas. Je právě:
A jste přihlášen jako uživatel:
Naše stránka tedy obsahuje tag , ve kterém jsou dva objekty typu TextBox. Ty využijeme ke zobrazení jména aktuálního uživatele a aktuálního času. Nyní je nutné dopsat potřebnou logiku do souboru, který je za naší ASPX stránkou.
10.3 Logika webové stránky Protože k zisku informací o aktuálním uživateli potřebujeme objekty SharePoint API, je nutné použít následující jmenné prostory. using Microsoft.SharePoint; using Microsoft.SharePoint.WebControls;
Ve jmenném prostoru Microsoft.SharePoint je objekt SPUser, který přímo reprezentuje uživatele v SharePointu. Abychom získali aktuálního uživatele, budeme potřebovat aktuálně otevřený web. Ten získáme prostřednictvím třídy SPContext, která je ve jmenném prostoru Microsoft.SharePoint.WebControls. Nyní již přistoupíme ke konkrétní implementaci. Vytvoříme ve třídě dvě základní vlastnosti „ActualTime“ a „ActualUser“ a jejich obsah následně v přepsané metodě OnLoad() vložíme do textových polí, která jsme připravili v ASPX formuláři. K získání Master Page z galerie šablon v SharePointu budeme potřebovat objekt SPWeb, reprezentující aktuální otevřenou stránku v SharePointu.
60
public partial class SPCustomPage : System.Web.UI.Page { private SPWeb teamSite; public String ActualTime { get { return DateTime.Now.ToString("hh:mm:ss"); } } public String ActualUser { get { return SPContext.Current.Web.CurrentUser.Name; } } protected override void OnPreInit(EventArgs e) { base.OnPreInit(e); //ziskame SPWeb this.teamSite = SPControl.GetContextWeb(Context); //nastavi se masterpage teto stranky stejny jako masterpage webu this.MasterPageFile = teamSite.MasterUrl; } protected override void OnLoad(EventArgs e) { base.OnLoad(e); txtActualTime.Text = this.ActualTime; txtActualUser.Text = this.ActualUser; } }
Nejprve definujeme dvě vlastnosti: „ActualTime“ a „ActualUser“. ActualTime pouze vrátí aktuální čas ve formátu HH:MM:SS. Vlastnost ActualUser vrátí aktuálně přihlášeného uživatele. Toho získáme z objektu SPWeb, který reprezentuje aktuálně otevřený web. Díky tomu, že kód je prováděn v prostředí ASP.NET, můžeme použít objekt SPContext, který nám přes svou vlastnost Current vrátí aktuálně otevřený objekt typu SPWeb. Vyhneme se tak získávání objektu typu SPWeb pomocí konstruktoru, tak jak to bylo provedeno v předchozích příkladech. return SPContext.Current.Web.CurrentUser.Name;
Je nutné poznamenat, že i když používáme objekt typu SPWeb, který implementuje rozhraní IDisposable, je zakázáno zde volat metodu Dispose()nebo použít klíčové slovo using, a nutit tak Garbage Collector k úklidu objektu z paměti. Garbage Collector by se pokusil z paměti uvolnit objekt SPWeb, který jsme sami nevytvořili a který reprezentuje aktuální otevřený Web v SharePointu.
61
Velice důležité je přepsání metody OnPreInit(). Ve výše uvedeném příkladu na použití Master Pages obsahovala stránka obsahu v directivě Page odkaz na svou mateřskou Master Page, tak jak je ukázano níže: <%@ Page Language="C#" MasterPageFile="~/Demonstration.Master"…>
To ovšem nemůžeme provést, protože chceme použít jednu z defaultních Master Page SharePointu, tedy Master Page uloženou v Galerii v databázi SharePointu. Pokud bychom například zkopírovali tuto Master Page z Galerie do adresáře projektu, nepůjde projekt zkompilovat, protože Master Page SharePointu obsahují odkazy na další stránky a dynamické knihovny SharePointu. Je tedy nutné přepsat Master Page dynamicky v metodě OnPreInit(), která se provede před načtením stránky. this.teamSite = SPControl.GetContextWeb(Context); //nastavi se masterpage teto stranky stejny jako masterpage webu this.MasterPageFile = teamSite.MasterUrl;
Nejprve získáme aktuálně otevřený objekt SPWeb a následně použijeme Master Page z tohoto objektu. Poslední přepsanou metodou je metoda OnLoad(), která se provede v momentě načtení stránky. Zde již pouze nastavíme hodnoty vlastností Text výstupních TextBoxů na požadované hodnoty. Výslednou knihovnu budeme chtít nakopírovat do BIN složky, aplikace SharePointu v Internet Information Services Serveru, bude o ní ještě řeč. Ta je standardním umístěním dynamických knihoven pro všechny ASP.NET webové aplikace. Dynamické knihovny v tomto umístění nemají ve standardním nastavení webové aplikace přístup k objektovému modelu SharePointu. Pokud se o přístup k objektovému modelu SharePointu pokusí, CLR (Common Language Runtime) vyhodí následující výjimku: Request for the permission of type Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c failed
Proto bude nutné tyto knihovny nainstalovat zároveň i do Global Assembly Cache (GAC). Global Assembly Cache je centrálním uložištěm dynamických knihoven platformy .NET a je přítomen na každém počítačí s nainstalovaným .NET Frameworkem. K instalaci dynamické knihovny do GAC je nutné, aby dynamická knihovna měla takzvané silné jméno (Strong Assembly Name). Strong Assembly Name u dynamické knihovny zaručuje její jedinečnost. Strong Assembly Name je tvořené identitou dynamické knihovny a veřejným klíčem spolu s digitálním podpisem. Toto jméno vygenerujeme ze souboru dynamické knihovny a odpovídajícího privátního klíče, který musíme ve Visual
62
Studiu vytvořit. To provedeme na okně vlastností projektu na záložce „Signing“. Je nutné zaškrtnout checkbox „Sign the assembly“. Z nabídky „Choose a strong name key file:“ vyberme „New“ a v novém dialogu pojmenujeme a vytvoříme nový soubor primárního klíče. Není nutné, aby byl soubor chráněn heslem.
Obrázek 43: Vytvoření „Strong Name Key“
V této fázi máme projekt hotov, teď je nutné přesunout stránky do složky LAYOUTS a zajistit jejich přístupnost ze SharePointu. Tomu se věnuje následující podkapitola.
10.4 Deployment ASPX stránek do složky LAYOUTS V tuto chvíli máme stránky připravené a je nutné provést jejich nasazení. Nejprve je nezbytné nakopírovat ASPX soubory do složky LAYOUTS v úložišti aplikací SharePointu. C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\LAYOUTS Můžeme sem nakopírovat složku projektu společně se soubory ASPX a Web.config.
63
Obrázek 44: Nakopírování výsledného formuláře do složky LAYOUTS
Nyní je nutné nastavit tuto složku jako „webovou aplikaci“ v nastavení IIS serveru. Ve webových aplikacích naleznete aplikaci SharePointu – po standardní instalaci je pojmenovaná SharePoint – 80. Pokud otevřete složku „_layouts“, měli byste zde vidět obsah výše uvedené složky LAYOUTS na vašem disku.
Obrázek 45: Nastavení IIS serveru
64
Kliknutím pravým tlačítkem na složce vaší nové aplikace zobrazte její vlastnosti. V aplikačním nastavení („Application settings“) naleznete položku Jméno aplikace („Application name“). Aplikace v této chvíli ještě nemá žádné jméno. Stiskem tlačítka „Vytvořit“ („Create“) toto jméno vytvoříte. Po vytvoření aplikačního jména by mělo okno vypadat následujícím způsobem:
Obrázek 46: Nastavení složky aplikace v IIS serveru
Zároveň uvidíte, že se v okně správce internetové Informační služby změní ikona složky na ikonu aplikace.
10.5 Deployment dynamické knihovny Nyní je nutné nahrát DLL knihovnu, ve které je zkompilovaná logika formuláře, do dvou umístění. Tím prvním je BIN složka Internetové informační služby a tím druhým GAC – Global Assembly Cache. Umístění BIN složky webové aplikace SharePointu může být různé, nejčastěji jde o následující umístění (pokud byla provedena čistá instalace do prázdné IIS): C:\Inetpub\wwwroot\wss\VirtualDirectories\80\bin\ Do této složky nahrajte soubor SPCustomPage.dll, ve kterém je logika vašeho formuláře. Pokud tak neučiníte, objeví se po navigování prohlížeče na vaši nově vytvořenou
65
stránku (například http://server/site/_layouts/SPCustomPage/SPCustomPage.aspx) následující chybová hláška: Could not load type 'SPCustomPage.SPCustomPage'. at System.Web.UI.TemplateParser.GetType(String typeName, Boolean ignoreCase, Boolean throwOnError) at System.Web.UI.TemplateParser.ProcessInheritsAttribute(String baseTypeName, String codeFileBaseTypeName, String src, Assembly assembly) at System.Web.UI.TemplateParser.PostProcessMainDirectiveAttributes(IDictionary parseData) Toto chybové hlášení v zásadě říká, že se nepovedlo nalézt třídu SPCustomPage ze jmenného prostoru SPCucstomPage, a to proto, že dynamická knihovna chybí ve složce BIN aplikačního serveru IIS. Dalším krokem bude nainstalovat tuto dynamickou knihovnu do Global Assembly Cache. Jak již bylo řečeno, Global Assembly Cache je centrálním uložištěm dynamických knihoven pro platformu .NET na každém počítači. Jeho umístění se může opět lišit. Pokud používáte jako vývojový server Windows Server 2003, naleznete GAC na následující cestě: C:\WINDOWS\assembly\GAC_MSIL\ K instalaci dynamických knihoven do Global Assembly Cache se používá systémový nástroj GACUTIL. Užitečné je použít nástroj Visual Studio 2008 Command Prompt, který již má nastevenu cestu k nástroji GACUTIL. Intalaci provedeme příkazem gacutil –i Pokud se instalace povedla, mělo by váše výstupní okno vypadat jako na obrázku. Po instalaci do GAC bude nutné provést restart IIS serveru. Ten se provede příkazem iisreset.
Pokud bychom instalaci do GAC vynechali, objevila by se v LOGu SharePointu nebo přímo na obrazovce po navigaci na vytvořenou stránku již zmíněná chyba:
66
Request for the permission of type Microsoft.SharePoint.Security.SharePointPermission, Microsoft.SharePoint.Security, Version=11.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c failed Nyní již můžete navigovat váš prohlížeč na adresu: http://server/site/_layouts/SPCustomPage/SPCustomPage.aspx Všiměte si, že dochází k virtualizaci složky LAYOUTS do všech webů na daném portálu. To má tu výhodu, že můžete vytvořenou stránku použít hned z několika webů na portálu. Tedy http://server/site1 a http://server/site1 obshují stejné stránky ve složce _layouts.
67
11.
SharePoint a Workflow Foundation
11.1 Úvod do problematiky a cíle této části V první kapitole byly probrány základy Workflow Foundation a v kapitole druhé byly rozebrány základy programování pomocí objektového modelu SharePointu. Tato kapitola by měla objasnit, jak a za jakých podmínek lze integrovat Workflow Foundation a SharePoint, a vytvářet tak vlastní workflow přímo v SharePointu. Jinými slovy jak lze spojit znalosti z předchozích dvou kapitol tak, abychom s jejích pomocí byli schopni vytvořit workflow spustitelné v prostředí SharePointu. Během této kapitoly vytvoříme jednoduché workflow sloužící ke schválení zaměstnaneckého požadavku na nový software. Můžeme si představit větší firmu, používající elektronickou formu schvalování v případě, že její zaměstnanci potřebují ke své práci nový software. Následuje popis procesu schválení.
11.2 Schválení požadavku na nový software V praxi by měl proces schválení probíhat následujícím způsobem: 1. Uživatel potřebuje nový software – otevře si intranetovou stránku, vyplní formulář, specifikuje, co konkrétně požaduje a za jakou orientační cenu. 2. Takto vyplněný formulář se uloží do knihovny dokumentů a automaticky se k němu spustí workflow. 3. Nadřízený uživatele, který vyplňoval formulář, dostane e-mailem informaci s žádostí o schválení od svého podřízeného. 4. Nadřízený klikne na odkaz, který mu byl zaslán elektronickou poštou. Otevře se mu webová stránka, kde bude vyobrazen obsah požadavku, a bude mu umožněno schválit požadavek, zamítnout požadavek nebo požádat o dodatečné informace. 5. Nadřízený by měl mít možnost požádat o dodatečné informace libovolnou osobu z firmy, například odborníka na IT nebo přímo žadatele. 6. Pokud si nadřízený vyžádal dodatečné informace, tazatel obdrží opět e-mail s odkazem na webovou stránku, na které bude moci doplnit požadované informace. 7. Workflow se vrátí k nadřízenému žadatele, který bude mít opět na výběr, co si přeje s požadavkem provést. Protože budeme workflow programovat jako stavové, bylo by vhodné nastínit, jak bude vypadat stavový diagram. V tomto případě půjde o velice jednoduchý stavový diagram pouze se třemi stavy.
68
Žádost o dodatečné informace
Počáteční stav: Schválení požadavku
Informace doplněny
Schválení nebo zamítnutí
Čeká se na dodatečné informace
Workflow dokončeno Požadavek schválen nebo zamítnut
Takto vytvořený stavový diagram odpovídá výše popsanému procesu schválení. Je jasné, že mezi stavem schválení a čekání na dodatečné informace může probíhat nekonečná smyčka.
69
12.
Integrace Workflow Foundation do SharePointu
Podpora workflow je ve Windows SharePoint Services docílena pomocí integrace objektového modelu SharePointu a Workflow Foundation. Jak bylo zmíněno v kapitole o základech Workflow Foundation, její využití nezáleží na hostující aplikaci. Pomocí komponenty WorkflowRuntime je možné hostovat workflow v jakékoliv aplikaci. V našem případě je hostitelskou aplikací MS SharePoint. Integrace workflow do SharePointu se od výše popsané integrace do „okénkové“ aplikace v některých detailech liší, princip je ale v zásadě stejný. Objektový model SharePointu již obsahuje komponentu WorkflowRuntime, která je připravena spouštět workflow. Jak víme z popisu Workflow Foundation, zbývá tedy ještě dořešit umístění dynamické knihovny workflow a komunikace workflow s okolním světem.
SharePoint Object Model Workflow Runtime
GAC Global Assembly Cache
Workflow Instance Workflow Instance
Workflow.dll Workflow Instance
Runtime Services SQL Persistance
SQL Server Obrázek 47: SharePoint a Workflow – propojení
Windows SharePoint Services již obsahují RuntimeServices a současně nám nedovolují žádné další komunikační služby přidat. Nemůžeme tedy napsat vlastní službu, která by umožnila komunikaci workflow s další „vnější“ aplikací. K tomu, abychom byli schopni předat data z instance workflow uživateli, musíme využít některé speciální aktivity, které již jsou součástí objektového modelu SharePointu a tuto komunikaci nám umožní. To je detailněji popsáno v následující kapitole. Řešení druhého problému, tedy uložení dynamické knihovny workflow a její načtení do komponenty WorkflowRuntime, je na diagramu také znázorněno. Za normálních okolností se dynamická knihovna obsahující šablonu workflow připojí do projektu a workflow se vytvoří pomocí metody CreateWorkflow(třída_workflow).
70
Co se týče SharePointu, řešení je složitější. Máme sice přístup do API SharePointu, ale s určitými restrikcemi. Nemůžeme do něj například nalinkovat nové dynamické knihovny ani nemáme konkrétní přístup k objektu WorkflowRuntime uvnitř SharePointu. Knihovna s šablonou workflow musí být nahrána do místa, které bude SharePointu přístupné, a tím je GAC (Global Assembly Cache). Zároveň, abychom SharePoint na existenci nově vytvořeného workflow, které bude uloženo do GAC, upozornili, využijeme konceptu SharePoint Features, jež je vysvětlen později. WorkflowRuntime se také stará o stav workflow a jeho pravidelné ukládání do databáze (persistence). Stavem workflow nemyslíme pouze textové vyjádření stavu, například „Požadavek zamítnut“, ale celkový stav všech objektů a proměnných, nacházejících se uvnitř instance workflow.
12.1 Workflow jako sled úkolů Workflow v SharePointu jsou nejčastěji modelovaná jako sled po sobě jdoucích úkolů. Z příkladu, jejž budeme modelovat, jasně vidíme, které úkoly to budou. Úkol: Schvalte požadavek na nový software, řešitelem bude nadřízený žadatele. Úkol: Doplňte dodatečné informace, řešitelem bude libovolná osoba vybraná žadatelem. Náš příklad je pouze krátký a ukázkový. Je ale možné si představit rozšíření námi uvedeného schválení požadavku na nový software. Celý proces by mohl obsahovat například následující úkoly:
Schvalte za vedení IT, řešitel: vedoucí IT oddělení
Získejte nabídku od dodavatele, řešitel: pracovník IT oddělení
Schvalte nabídku za vedení divize, řešitel: vedoucí divize
Odešlete objednávku na dodavatele, řešitel: pracovník IT oddělení
Zjistěte datum předpokládaného obdržení softwaru, řešitel: pracovník IT oddělení
Nainstalujte software, řešitel: pracovník IT oddělení
V každém takovém kroku by se měnil stav požadavku, například „Schváleno vedením divize“ nebo „Objednávka odeslána“. Workflow v SharePointu umožňuje svázat sled úkolů s určitou položkou v seznamu, nejčastěji s dokumentem, který je uložený v knihovně dokumentů.
12.2 Workflow SharePoint aktivity Jak víme z první kapitoly, workflow se modeluje pomocí aktivit. Protože, jak bylo řečeno, workflow je v SharePointu modelované jako sled úkolů, tak i aktivity, které jsou pro vývoj workflow k dispozici, úzce souvisí s úkoly. V příkladu uvedeném v příští kapitole budou použity především tyto aktivity:
71
CreateTask – aktivita, sloužící k vytvoření nového úkolu. CreateTaskWithContentType – aktivita, sloužící k vytvoření nového úkolu, kterému zároveň přiřadí GUID typu obsahu. OnTaskChanged – aktivita, která je aktivována při změně úkolu v SharePointu.
12.3 SharePoint Features Features jsou balíčky, které umožňují rozšířit funkcionalitu jednotlivých stránek v SharePointu. Je to skupina elementů, které mohou být aktivované na určité stránce a umožňují nové funkce webu. Features snižují komplexnost vyvíjených řešení. Když chceme přidat do stránky novou funkcionalitu, není nutné přepisovat zdrojový kód stránky, ale stačí vytvořit novou feature, kterou aktivujeme na stránce a která požadované rozšíření umožní. SharePoint všechny své features uchovává ve svém centrálním úložišti ve složce FEATURES (podobně jako uživatelem vytvořené stránky najdeme ve složce LAYOUTS) na následující cestě: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\FEATURES
Každá složka v tomto adresáři reprezentuje jednu feature. Složka musí obsahovat definici v souboru feature.xml. Definice feature se následně může odkazovat na více dalších souborů libovolného typu, označovaných jako elementy, které musí být obsaženy ve stejné složce. Po vytvoření složky s potřebnými soubory je možné provést instalaci feature. Instalace se provádí pomocí nástroje STSADM, což je administrátorský nástroj pro správu SharePointu, jehož používání je popsáno níže. Soubor feature.xml, který složí k definici a instalaci nové feature, má následující strukturu: <ElementManifests> <ElementManifest Location="soubor_elementu.xml"/>
Element feature v tomto souboru musí obsahovat minimálně následující dva argumenty:
72
ID – identifikační číslo feature ve formě GUID. Scope – určuje rozsah nasazení feature, jinými slovy, zda je feature určena pro jeden web (Site), kolekci webů (Site Collection,) nebo pro celou aplikaci (Web Application). V případě workflow je soubor feature.xml vygenerován Visual Studiem, takže nevyžaduje uživatelskou editaci. V případě nových typů obsahů, které budeme muset vygenerovat, abychom umožnili uživatelům vstoupit do workflow přes webové rozhraní, je již nutné napsat soubor feature.xml ručně.
12.4 Nástroj STSADM Tento nástroj příkazového řádku umožňuje provádět celou řadu administrátorských operací. My se zde omezíme především na instalace a aktivace features, ale tím využití tohoto nástroje rozhodně nekončí. STSADM najdeme v BIN složce v centrálním úložišti SharePointu neboli v následujícím umístění: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN\STSADM.EXE
Následuje popis a syntaxe operací, které bude nutné používat: Stsadm Stsadm Stsadm Stsadm
–o –o –o –o
installfeature –name MyFeature (-force) uninstallfeature –name MyFeature (-force) activatefeature –name MyFeature –url http://server/site deactivatefeature –name MyFeature –url http://server/site
Je dobré si všimnout, že zatímco instalace se provádí bez určení URL stránky, tedy pro celý SharePoint, aktivaci feature provádíme pouze na určitém konkrétním webu. K aktivaci feature není nutné utilitu STSADM používat, protože ji lze provést přímo z webového rozhraní SharePointu.
12.5 Napojení úkolů v SharePointu na webové formuláře Jak již bylo řečeno, workflow jsou v SharePointu modelována jako sled úkolů. Úkoly jsou v SharePointu uchovávány jednoduše jako položky seznamu, tedy objekty SPListItem, které obsahují pole jako „Přiřazeno“, „Termín splnění“ a podobné. Ve standardním zobrazení tato položka vypadá jako jakákoliv jiná položka seznamu, tedy jednoduchá tabulka s páry „Jméno sloupce“ a „Hodnota“. Pakliže bude vytvořen úkol „Schvalte požadavek na software“, nebudeme chtít zobrazit tabulku s hodnotami tohoto úkolu, ale webový formulář, zobrazující požadavek a umožňující schválení nebo zamítnutí. Abychom toho docílili, bude nutné definovat vlastní typy obsahu (Content Types) pro zobrazení jednotlivých úkolů. Nám budou stačit dva nové typy obsahu, a to pro dva úkoly, které budou ve workflow zastoupeny:
Schvalte požadavek na software
Doplňte dodatečné informace
73
12.6 Vlastní typy obsahu SharePoint uchovává jednoznačné identifikační číslo pro různé typy obsahu (Content Types). Existuje tedy identifikace pro všechny typy souborů i pro ostatní obsah, jakým mohou být položky seznamů, webové formuláře, grafy, ankety, položky úkolů a další. Protože workflow je sled úkolů a každý úkol je pouze objektem SPListItem, je nutné dosáhnout toho, aby se při otevření této položky SPListItem neotevřelo standardní zobrazení položky seznamu, ale formulář definovaný pro tento úkol. Toho dosáhneme definováním nového typu obsahu pro každý úkol, který bude workflow obsahovat. Každý typ obsahu v SharePointu má určeno, jak má být zobrazen. Při definici typu obsahu tedy určíme jeho zobrazení pomocí speciálního webového formuláře, který pro tento typ obsahu vytvoříme. V momentě, kdy je pomocí SharePoint Workflow CreateTaskWithContentType aktivity vytvářen nový úkol, má konkrétně nastaven i typ obsahu. Když uživatel otevře tento úkol v SharePointu, otevře se mu vytvořený webový formulář. Abychom definice nových typů obsahů zprostředkovali SharePointu, vytvoříme feature, kterou bude možné aktivovat na konkrétním webu a tím i přidat typy obsahu do daného webu. Typy obsahu je následně vždy nutné povolit na konkrétním seznamu, který bude položky tohoto typu obsahovat. Vytvoříme-li tedy typ obsahu pro úkol „Schválení požadavku“, bude nutné tento typ obsahu povolit na seznamu úkolů. Typ obsahu vytvoříme jako XML soubor, se speciálním elementem ContentType. Tento XML soubor je nutné zahrnout do feature, která SharePointu tento typ obsahu zprostředkuje.
74
13.
Architektura aplikace
Cílem příkladu bude vytvořit jednoduché workflow, umožňující schválení zaměstnaneckého požadavku na nový software. Řešení je vhodně rozdělit na následující tři části.
13.1 Návrh vstupního formuláře (formuláře požadavku) Návrh formuláře požadavku na software a vytvoření knihovny dokumentů, do které se budou požadavky ukládat, provedeme pomocí aplikace MS InfoPath. Použití MS InfoPath není nutnou podmínkou, ale má dvě následující výhody:
Umožňuje využití výhod integrace MS InfoPath se SharePointem. To nám dovolí nejprve navrhnout formulář a následně ho publikovat do SharePointu jako knihovnu dokumentů. Tím bude vytvořena knihovna dokumentů, jejíž sloupce budou přesně odpovídat polím ve formuláři.
Vyplněný formulář uchovaný v knihovně dokumentů SharePointu je vlastně XML soubor, jehož elementy odpovídají polím ve formuláři navrženém pomocí MS InfoPath. To nám umožní jednoduchou programovou editaci formuláře. V případě, že uživatel například schválí požadavek, bude moci programově přepsat pole stavu požadavku na „Schváleno“, a to pouze použitím standardních nástrojů .NET Frameworku pro editaci XML souborů.
13.2 Návrh a zpracování webových formulářů, sloužících jako vstupní body pro uživatele aplikace V této části navrhneme dva webové formuláře pro dva základní úkoly, které budou uživatelé se systémem provádět: Schválení požadavku. Formulář, který zobrazí informace o požadavku a umožní ho uživateli schválit, zamítnout nebo požádat o dodatečné informace.
Doplnění dodatečných informací k požadavku. Formulář, který zobrazí základní informace o požadavku a umožní uživateli doplnit dodatečné informace.
Při vývoji využijeme znalostí popsaných v kapitole a publikaci vlastních stránek do SharePointu, ve které je popsána implementace vlastních stránek do SharePointu jejich publikováním do složky LAYOUTS v úložišti SharePointu. Kromě této techniky bude nutné zajistit přenos informací z webového formuláře do workflow tak, aby po schválení formuláře instance workflow dostala informaci a workflow mohlo podle obdržené informace přejít do nového stavu. Protože workflow v SharePointu je sledem úkolů, bude nutné zajistit, aby se při otevření úkolu zobrazil správný formulář. To nám umožní vytvoření vlastních typů obsahu pro oba dva formuláře. Když je pak ve workflow vytvořen daný úkol, bude mu přidělen právě jeho typ obsahu, a tím zaručíme, že při otevření tohoto úkolu v SharePointu se otevře ten správný formulář.
13.3 Návrh a zpracování workflow Workflow namodelujeme ve Visual Studiu 2008, a to jako stavové workflow.
75
Výsledná dynamická knihovna bude nainstalována do Global Assembly Cache, čímž ji zpřístupníme SharePointu. Aby toto workflow mohl SharePoint použít, Visual Studio za nás vytvoří feature, do které bude workflow zabaleno. Tuto feature pak již bude možné aktivovat na jednotlivé weby a workflow následně bude možné použít v seznamech daného webu. Každý krok workflow je specifikován jako úkol přidělený uživateli. Úkoly ve workflow jdou vytvořit pomocí dvou speciálních aktivit:
CreateTask
CreateTaskWithContentType
My použijeme aktivitu CreateTaskWithContentType, protože nám umožní vytvořit úkol konkrétního typu a následné zobrazení formuláře vytvořeného pro daný úkol.
13.4 Přehled architektury aplikace Celkovou architekturu aplikace popisuje následující diagram.
Windows Server SharePoint Workflow Runtime
FEATURES
Workflow Instance
workflow.xml approveFormCT.xml
Webový formulář
Schválit dokument LAYOUTS
Zamítnout dokument form.aspx
Požádat o dodatečné informace Odeslat
Zrušit
Global Assembly Cache Forms.dll
SQL Server
.NET
Workflow.dll IIS - BIN Forms.dll
Obrázek 48: Architektura aplikace
Dynamická knihovna workflow je uložena v Global Assembly Cache a definice workflow je aktivována jako feature na dané stránce. V momentě, kdy je na dokumentu spuštěna nová instance workflow, SharePoint pomocí definice zjistí, kterou dynamickou knihovnu má k inicializaci workflow použít.
76
V momentě, kdy je workflow již spuštěné a objeví se v něm aktivita CreateTaskWithContentType, tedy vytvoření úkolu, SharePoint vytvoří novou položku v seznamu úkolů, tedy objekt typu SPListItem, a přiřadí mu typ obsahu, a tedy i zobrazovací formulář. Typy obsahu jsou vytvořeny a aktivovány jako feature na webu SharePointu. V momentě, kdy uživatel otevře daný úkol v SharePointu, použije se formulář, který byl připraven ve složce LAYOUTS. Tento formulář odkazuje na dynamickou knihovnu, která je ve složce BIN Internet Information Services Serveru, ale zároveň, protože přistupuje k objektovému modelu SharePointu, musí být nainstalována i v Global Assembly Cache.
77
14.
Návrh formuláře požadavku pomocí nástroje MS InfoPath
V této kapitole popíšeme, jak vytvořit jednoduchý formulář představující požadavek zaměstnance na nový software. Tento formulář publikujeme do SharePointu, tak abychom vytvořili knihovnu dokumentů, jejíž sloupce budou přesně odpovídat polím požadavku. Tato kapitola není návodem na používání aplikace MS InfoPath, pouze zde budou popsány některé kroky užitečné při návrhu formulářů určených k publikaci na SharePointu. Zároveň je dobré poznamenat, že použití InfoPath formuláře není podmínkou. Můžeme připojit workflow k jakékoliv položce v seznamu SharePointu, tedy i k jakémukoliv jinému dokumentu. Jelikož vyplněný InfoPath formulář není nic jiného než XML soubor, tak nám umožní jednak čtení, ale zároveň i zpětný zápis do požadavku pomocí standardních tříd jmenného prostoru System.xml. Pro SharePoint existuje rozšíření InfoPath Form Services, umožňující zobrazování InfoPath formulářů přímo v okně webového prohlížeče. Pokud bychom navrhovali formulář pro SharePoint, na kterém je rozšíření InfoPath Form Services nainstalováno, byl by jeho návrh, co se některých aspektů týče (například ukládání do knihovny dokumentů v SharePointu), odlišný a snadnější. Zde ale budeme postupovat tak, aby byl formulář kompatibilní a funkční i na SharePointu bez InfoPath Services.
14.1 Návrh formuláře a jeho publikování Navrhovaný formulář by měl vypadat zhruba takto:
Obrázek 49: Design formuláře
78
Formulář obsahuje čtyři pole, která bude moci uživatel vyplnit, a to „Datum požadavku“, „Jméno žadatele“, „Požadovaný software“ a „Předpokládaná cena“. Další dvě pole, tedy pole „Stav požadavku“ a „Schvalovatel požadavku“, budou jen pro čtení. Jejich modifikaci budeme provádět prostřednictvím workflow a uživatelé nebudou mít možnost změnit hodnoty těchto polí. Pomocí okna vlastností jednotlivých polí nastavíme jejich jména, například pole pro požadovaný software jsme pojmenovali jednoduše „software“.
Obrázek 50: Dialog vlastností pole „Software“ ve formuláři
Tlačítko „Odeslat“ zatím necháme pouze tak, jak je, a formulář publikujeme do SharePointu. Zvolíme tedy File -> Publish -> To SharePoint Server with or without InfoPath Form Services. V dalším dialogu potom vybereme publikování formuláře jako knihovny dokumentů, tedy: Document Library -> Create New Document Library. V nově otevřeném dialogu bude nutné nastavit jméno nové knihovny dokumentů a její popis. Po stisknutí tlačítka „Next“ se otevře dialog, umožňující nastavit propagaci vybraných polí do SharePointu. Označíme zde tedy pole, pro které chceme v SharePointu vytvořit odpovídající sloupec. Čím více polí přidáme, tím více možností filtrování a řazení budeme následně v SharePointu mít. Zvolíme tedy „Add“ a v následujícím dialogu vybereme pole a nastavíme, jak má být pojmenován sloupec v knihovně dokumentů.
79
Obrázek 51: Nastavení propagace polí do SharePointu
V následujícím kroku již jen potvrdíme a stiskem tlačítka „Publish“ publikujeme nový formulář, čímž vytvoříme novou knihovnu dokumentů. Otevřeme-li tuto knihovnu, můžeme vyzkoušet vytvoření nového dokumentu v této knihovně. Pokud vše proběhlo v pořádku, měl by se zobrazit námi vytvořený formulář.
14.2 Tlačítko „Odeslat“ – uložení formuláře do knihovny v SharePointu Vrátíme se zpět do návrhu formuláře a pokusíme se přidat akci k tlačítku „Odeslat“ tak, aby po stisknutí došlo k uložení formuláře do SharePointu a jeho zavření. K tomu je nutné vytvořit nový datový zdroj, sloužící pro uložení do SharePointu. Zvolíme tedy: „Tools“, „Data Connections“, „Add“. Otevře se nový dialog, ve kterém vybereme: „Create a new connection to“, „Submit data“. V dalším dialogu potom vybereme: „To a document library on a SharePoint site“.
80
Obrázek 52: Výběr datového zdroje pro uložení do SharePointu
V novém dialogu bude nutné zadat adresu knihovny dokumentů a zároveň jméno, pod jakým se požadavek uloží. Knihovnu dokumentů jsme vytvořili v předchozím kroku, takže teď jen zkopírujeme její adresu. Pozor na interpunkci, SharePoint používá ve svých adresách pouze znaky anglické abecedy, takže pokud jste svou knihovnu pojmenovali „Požadavky“, adresa bude podobná té následující: http://server/site/Poadavky Nyní musíme zvolit jméno, pod kterým se požadavek uloží do knihovny. Je vhodné použít pole vepsaná uživatelem, tak aby od sebe mohly být požadavky v knihovně odlišené. Můžeme zvolit například kombinaci „Jméno – datum“. Kliknutím na ikonu funkce se zobrazí nové okno pro podrobnější zadání funkce. Můžeme použít funkci „concat“, která skládá řetězce. Metodě dáme tři argumenty, dva z nich budou vybraná pole a třetím argumentem bude pouze řetězec sloužící k jejich spojení.
81
Obrázek 53: Využití funkce pro spojení slov v SharePointu
Vyplněný dialog pro nastavení datového připojení do ukládání do SharePointu by měl vypadat následovně:
Obrázek 54: Nastavení datového zdroje pro ukládání do SharePointu
Po kliknutí na „OK“ již jen zadáme jméno pro nově vytvořené datové připojení, například „saveToSP“. S takto vytvořeným datovým připojením už budeme moct uložit požadavek do knihovny.
82
Otevřeme nyní okno vlastností tlačítka „Odeslat“ a kliknutím na „Rules“ se dostaneme do sekce pro přidávání pravidel, která se provedou při stisku tlačítka. Zde zvolíme „Add“ pro přidání nového pravidla a otevře se následující dialog.
Obrázek 55: Vytvoření nového pravidla pro ukládání do SharePointu
V tomto dialogu pojmenujeme pravidlo a zvolíme „Add Action“, čímž se otevře dialog pro určení akce, která se má provést. V tomto dialogu již jen vybereme „Submit data using data connection“ a zvolíme datové připojení na uložení do knihovny v SharePointu tak, jak ukazuje následující obrázek.
Obrázek 56: Vytvoření nové akce pro ukládání do SharePointu
83
Vrátíme se k původnímu dialogu a stiskem „Add Action“ přidáme ještě jednu akci. Zde vybereme „Close the form“, tak aby byl formulář po úspěšném odeslání do knihovny dokumentů uzavřen. Tím jsme nastavili akci, která po stisku tlačítka zavolá
14.3 Tipy a triky pro vytváření formulářů Zde uvedeme jen dva základní tipy, které se často hodí při vytváření formulářů. 14.3.1. Zisk aktuálního data Jedním z ulehčení při vyplňování formuláře může být například automatické vyplnění aktuálního data do pole „Datum požadavku“. To umožníme přidáním pravidla, které se provede po otevření formuláře. Je tedy potřeba provést následující kroky: „Tools“ -> „Form Options“ -> „Open and Save“ -> „Rules“ -> „Add“ V tomto okně pojmenujeme nové pravidlo a přidáme novou akci. Zvolíme „Add Action“, otevře se nový dialog pro vytvoření nové akce. V něm nastavíme typ akce na „Set a fields value“, jako cílové pole vybereme pole obsahující datum. Pro vyplnění pole „Value“ otevřeme pomocný dialog kliknutím na ikonu funkce (malé f). Otevře se dialog, ve kterém zvolíme „Insert Function“. Z kategorií nabízených funkcí vybereme „Data and Time“ a funkci „today()“.
Obrázek 57: Vytvoření akce pro nastavení hodnoty pole na aktuální datum
To nám zaručí, že po otevření dialogu se do pole „Datum požadavku“ automaticky dotáhne aktuální datum. 14.3.2. Zisk aktuálního uživatele Často je potřeba získat informace o aktuálním přihlášeném uživateli, tedy o osobě vyplňující formulář. Získat tyto informace nám umožní jedna z webových služeb SharePointu. Najdeme ji na adrese: http://server/_vti_bin/UserProfileService.asmx
84
Pro přístup k této službě v InfoPathu je potřeba vytvořit nové datové připojení, které nasměrujeme na výše uvedenou URL. Po odeslání požadavku se zobrazí seznam metod, které můžeme použít. Zde vybereme metodu GetUserProfileByName. Tato metoda vrátí pro dané jméno uživatelský profil, tedy vrátí podrobná data o uživateli. Pokud ovšem nespecifikujeme jméno a necháme tento parametr prázdný, obdržíme aktuálního uživatele. Klíčem k tomu, abychom dostali informace o aktuálním uživateli, je tedy použít tuto metodu bez parametrů, takže při vytváření datového připojení přeskočíme zadávání parametrů. Dále nastavíme, aby byla tato webová služba volána při otevření formuláře a její hodnoty uloženy ve formuláři. Tato metoda vrátí pole pojmenované PropertyData, což je vlastně tabulka obsahující data jako uspořádané dvojice klíč – hodnota. Pokud tedy chceme nastavit hodnotu některého pole na jméno a příjmení aktuálního uživatele, musíme filtrovat hodnoty ve vráceném poli PropertyData, tak abychom získali právě jen jméno nebo příjmení. Otevřeme okno vlastností pole, do kterého chceme vepsat jméno a příjmení, a následně v tomto okně klikneme na ikonu funkce, pomocí které lze nastavit hodnotu vybraného pole. V následujícím dialogu vybereme „Insert Field Or Group“. Nyní je potřeba najít pole obsahující hodnotu, kterou chceme získat z webové služby. Najdeme ho ve struktuře výše vytvořeného datového zdroje, jedná se o pole „Value“.
Obrázek 58: Získání hodnoty z webové služby SharePointu
85
Nyní je potřeba zvolit možnost „Filter Data“ a určit, že chceme získat pouze pole, které odpovídá klíči „FirstName“. V nově otevřeném dialogu přidáme nový filtr a v tomto filtru vybereme filtrování podle hodnoty pole. Vybereme pole „Name“, které obsahuje klíč pro datovou hodnotu.
Obrázek 59: Výběr pole použitého pro filtrování
Nyní dokončíme nastavení filtru.
Obrázek 60: Nastavení filtrování
Výsledná funkce bude vypadat následovně: Value[Name = "FirstName"] Pokud ovšem chceme vložit jméno i příjmení, můžeme použít funkci concat, sloužící ke spojování řetězů, a upravíme tak výslednou funkci. concat(Value[Name = "FirstName"]; " "; Value[Name = "LastName"])
86
Obrázek 61: Výsledná funkce pro zisk aktuálního uživatele
Takto jsme vytvořili nový datový zdroj napojený na webovou službu. K získání dat z tohoto zdroje dojde ihned po otevření formuláře. Získaná data je nutné následně filtrovat, a tím zobrazit v požadovaném poli jen ty informace, které potřebujeme.
87
15.
Návrh a implementace webového rozhraní
Náplní této kapitoly bude vytvoření webových stránek, které uživatelé použijí k interakci s workflow systémem. Vytvoříme dva webové formuláře, první z nich umožní schválení dokumentu nadřízeným žadatele a druhý umožní žadateli vložení dodatečných informací. Oba formuláře integrujeme do SharePointu a výsledek bude vypadat zhruba takto (ukázka formuláře pro schválení požadavku):
Obrázek 62: Ukázka výsledného formuláře
Při vývoji těchto stránek bude použito techniky rozebrané v předchozím textu, která popisovala publikaci vlastních webových stránek do složky LAYOUTS.
15.1 Vytvoření projektu Ve Visual Studiu vytvoříme nový projekt typu WebApplication. Visual Studio vygeneruje třídu Default, kterou nebudeme používat a můžeme ji smazat. Cílem bude vytvořit dva formuláře: jeden pro schválení požadavku a druhý pro případné doplnění dodatečných informací k požadavku. Vytvoříme tedy tyto formuláře přidáním dvou nových položek typu WebForm do projektu. V našem příkladu jsou formuláře
88
pojmenované ApproveForm.aspx (schvalovací formulář) a AddInfoForm.aspx (formulář pro doplnění vlastností).
15.2 ASPX formulář pro schválení Začneme vytvořením formuláře, který umožní schválení. Formulář jsme v této ukázce pojmenovali ApproveForm.aspx. Smažeme celý obsah kromě direktivy Page, která odkazuje na soubor s logikou. <%@ Page Language="C#" AutoEventWireup="True" CodeBehind="ApproveForm.aspx.cs" Inherits="RequestWeb.ApproveForm" %>
Pro vložení obsahu použijeme kontejner Master Page SharePointu pojmenovaný PlaceHolderMain, do kterého je možné vložit obsah stránky.
89
Jméno žadatele: | <%#this.Name%> |
Datum požadavku: | <%#this.Date%> |
Software: | <%#this.Software%> |
Předpokládaná cena: | <%#this.Price%> |
Informace od žadatele: | <%#this.AddedInfo%> |
Schválit Zamítnout Požádat o dodatečné informace |
Vyplňte dodatečné informace které požadujete: | |
| |
90
Obsahem stránky je jednoduchá tabulka se dvěma sloupci. V levém sloupci je vždy popis a v pravém sloupci jsou vložené proměnné, které popisují daný úkol a požadavek. Hodnoty těchto proměnných vkládáme do formuláře pomocí techniky ASP.NET data binding. V jednoduchosti lze říci, že například na místo <%#this.TaskTitle%>
ASP.NET vloží obsah proměnné TaskTitle, obsažené ve třídě formuláře, tedy například titulek úkolu: „Schvalte požadavek na software“. Kromě takto napojených proměnných formulář obsahuje jednu komponentu RadioButtonList, obsahující tři položky (Schválit, Zamítnout, Požádat o dodatečné informace) s hodnotami 1, 2, 3, které uživateli umožní zvolit akci. Dále jsou zde dvě tlačítka „Odeslat“ a „Zrušit“, umožňující odeslat vybranou akci do workflow („Odeslat“) nebo neprovádět žádnou akci a vrátit prohlížeč na předchozí stránku („Zrušit“). Formulář také obsahuje definice kaskádových stylů použitých v uvedené tabulce. <style> table.main td{border-left-width:0px;border-right-width:0px} table.main{border-spacing:0px;border-collapse:collapse} tr.header {background-color:#3B6B9C; color:White;} td.info {color:Red} td.topBorder {border-top:1px solid #C1DAD7}
15.3 Zdrojový soubor formuláře Ještě než budeme definovat metody, je vhodné určit objekty, které bude stránka potřebovat k získání potřebných dat jak z položky úkolu, tak z položky požadavku. //Web SharePointu private SPWeb teamSite; //Položka seznamu, která reprezentuje požadavek private SPListItem document; //Položka seznamu, která reprezentuje aktuální úkol private SPListItem task; //Vybraný seznam úkolů private SPList taskList; //Dodatečné vlastnosti úkolu private Hashtable wfProperties;
Všechny uvedené objekty jsou poměrně jednoznačné. Poslední zde uvedený objekt typu Hashtable slouží k získání informací odeslaných do formuláře z workflow. V tomto objektu získáme proměnné, které budeme vkládat do položky úkolu během jeho vytváření aktivitou CreateTaskWithContentType ve workflow. Úkol obsahuje standardně vlastnosti jako DueDate (Datum dokončení), AssignedTo (Přiřazeno). Pokud chceme z workflow poslat do formuláře jakoukoliv další informaci (zde například
91
informace dodatečně doplněné uživatelem), použijeme objekt ExtendedProperties, který je definován na položce úkolu (SPListItem) Podobně jako v příkladu zabývajícím se vývojem vlastních webových stránek je opět nutné přepsat metodu OnPreInit(), ve které získáme aktuální web SharePointu a přepíšeme Master Page: protected override void OnPreInit(EventArgs e) { base.OnPreInit(e); //ziskame SPWeb this.teamSite = SPControl.GetContextWeb(Context); //nastavi se masterpage teto stranky stejny jako masterpage webu this.MasterPageFile = teamSite.MasterUrl; }
Dalším zásadním krokem bude přepsání metody OnLoad, v níž získáme všechny výše definované objekty, které jsou následně použité pro zobrazení informací ve webové stránce. protected void Page_Load(object sender, EventArgs e) { Guid taskListGUID = new Guid(Request.Params["List"]); taskList = teamSite.Lists[taskListGUID]; int taskID = Convert.ToInt16(Request.Params["ID"]); task = taskList.GetItemById(taskID); Guid wfInstanceGuid = new Guid(task[SPBuiltInFieldId.WorkflowInstanceID] as String); SPWorkflow workflow = new SPWorkflow(teamSite, wfInstanceGuid); SPList documentlist = teamSite.Lists[workflow.ListId]; document = documentlist.Items[workflow.ParentItem.UniqueId]; wfProperties = SPWorkflowTask.GetExtendedPropertiesAsHashtable(task); addedInfoLayer.Visible = AddedInfo != String.Empty; this.DataBind(); }
Když je webový formulář otevřen, jsou mu parametrem připojeným k URL adrese odeslána identifikační čísla seznamu, ve kterém se úkol nachází, a úkolu samotného. Část URL adresy může vypadat například následujícím způsobem: http://sr-sp-vptest/education/_layouts/WorkflowForms/ApproveForm.aspx?List=99b08c53-e3df-408c93cd-ec31974573d7&ID=64&Source= V této adrese jsou zdůrazněny právě ty části, které použijeme. V OnLoad() metodě tedy získáme tyto parametry a pomocí nich získáme objekt SPList reprezentující seznam a objekt typu SPListItem reprezentující samotný úkol.
92
Guid taskListGUID = new Guid(Request.Params["List"]); taskList = teamSite.Lists[taskListGUID]; int taskID = Convert.ToInt16(Request.Params["ID"]); task = taskList.GetItemById(taskID);
V dalším kroku je nutné získat dokument, ke kterému je workflow připojené. Nejprve zjistíme identifikační číslo instance workflow, která je spojená s tímto úkolem. Guid wfInstanceID = new Guid(task[SPBuiltInFieldId.WorkflowInstanceID] as String);
Následně si vytvoříme objekt SPWorkflow, použitím získaného identifikačního čísla. Z tohoto objektu již je možné získat seznam dokumentů a následně i dokument samotný. SPWorkflow workflow = new SPWorkflow(teamSite, wfInstanceID); SPList documentlist = teamSite.Lists[workflow.ListId]; document = documentlist.Items[workflow.ParentItem.UniqueId];
Poslední, co budeme potřebovat, je objekt typu Hashtable, reprezentující vlastnosti úkolu, které vložíme do úkolu při jeho vytváření ve workflow. Tento objekt nám tedy bude sloužit jako komunikační prostředek, který umožní workflow posílat do formulářů libovolné objekty. K získání tohoto objektu je v Objektovém modelu SharePointu speciální statická metoda. wfProperties = SPWorkflowTask.GetExtendedPropertiesAsHashtable(task);
Poslední řádky již jen zkontrolují, zda zobrazit vrstvu dodatečných informací, které mohou být do formuláře z workflow poslány, a poslední volání zaručí nahrazení proměnných v ASPX formuláři jejich hodnotami (ASP.NET Data Binding).
15.4 Získání proměnných z požadavku a z úkolu Nyní definujeme všechny proměnné, které jsou metodou Data Binding vloženy do těla formuláře. K získání těchto proměnných používáme právě objekty vytvořené v přepsané metodě OnLoad.
93
public String Name { get { return document["Jméno"] as String; } } public String Software { get { return document["Software"] as String; } } public String Price { get { return document["Cena"] as String; } } public String Date { get { return document["Datum požadavku"] as String; } }
Při přístupu k jednotlivým polím v požadavku používáme názvy sloupců knihovny dokumentů. Následující vlastnosti jsou získávány přímo ze samotné položky reprezentující úkol. Při přístupu k těmto vlastnostem opět používáme statickou třídu SPBuildInFieldId, která zpřístupňuje GUID pro vestavěné sloupce SharePointu. V případě sloupce AssignedToSharePoint vrací řetězec, který reprezentuje uživatele ve formě: „ID#Jméno Příjmení“, je tedy nutné tento text oříznout. public String AssignedTo { get { String assignedTo = task[SPBuiltInFieldId.AssignedTo] as String; if (assignedTo.Contains("#")) { assignedTo = assignedTo.Substring(assignedTo.IndexOf("#")+1); return assignedTo; } else { return String.Empty; } } } public String TaskTitle { get { return task[SPBuiltInFieldId.Title] as String; } }
Poslední vlastnost, kterou bude nutné zobrazit, je text dodatečných informací doplněných žadatelem, ale to pouze v případě, že workflow vstupuje poprvé do prvního stavu a schvalovatel v předchozím kroku žádal o tyto informace. Tyto informace pošle do webového formuláře přímo workflow, které navrhneme v další kapitole. K získání těchto informací využijeme vlastnosti úkolu, konkrétně objekt
94
ExtendedProperties, do kterého lze vložit libovolné objekty na straně workflow a tyto objekty později „vybrat“ na straně webového formuláře, nebo naopak. Následuje tedy definice vlastnosti AddedInfo. public String AddedInfo { get { if(wfProperties!= null && wfProperties.Contains("AddedInfo")) { return wfProperties["AddedInfo"] as String; }else{ return String.Empty; } } }
V případě proměnné „AddedInfo“ kontrolujeme, zda objekt „wfProperties“ není prázdný. Metoda GetExtendedPropertiesAsHashtable(task) vrací null, v případě, že úkolu žádné ExtendedProperties nebyly přiřazeny. V této proměnné si uložíme řetězec reprezentující dodatečné informace doplněné uživatelem a obdržené od instance workflow. Pakliže schvalovatel požádal o dodatečné informace a žadatel tyto informace poskytl, dojde ke druhému vstupu do „schvalovacího stavu“ a k druhému vytvoření „schvalovacího“ úkolu, kterému je z workflow poslán řetězec reprezentující informace poskytnuté žadatelem.
15.5 Odeslání informací zpět do workflow Stav úkolu je měněn v momentě, kdy uživatel zmáčkne tlačítko „Odeslat“. V té chvíli se provede následující procedura: Hashtable table = GetReturnTable(); if (document.File.CheckOutStatus == SPFile.SPCheckOutStatus.None) { if (task[SPBuiltInFieldId.TaskStatus].ToString() != "Dokončeno") { bool returnVal = SPWorkflowTask.AlterTask(this.task, table, true); if (returnVal == false) { ReturnError("Nepodařilo se odeslat do Workflow změnu stavu"); } } else { ReturnError("Tento úkol již byl jednou odeslán."); } } else { ReturnError("Schvalujete dokument, který je právě otevřen. Zkuste to později."); }
95
Nejprve se zavolá metoda GetReturnTable, jež vrací objekt typu Hashtable, který se použije ke změně stavu objektu. Pomocí této Hashtable se upraví vlastnosti úkolu. Úprava vlastností úkolu je provedena pomocí metody AlterTask, tak jak je popsáno níže. private Hashtable GetReturnTable() { Hashtable table = new Hashtable(); table.Add("Changed", 1); table.Add(SPBuiltInFieldId.PercentComplete, "100"); table.Add(SPBuiltInFieldId.TaskStatus, "Dokončeno"); table.Add("Action", rdbSelect.SelectedValue); if (rdbSelect.SelectedValue == "3") { table.Add("RequestedInfo", txtInfo.Text); } return table; }
Ještě před samotnou aktualizací úkolu jsou provedeny dvě kontroly. Nejprve je zjištěno, zda daný schvalovaný dokument nemá některý uživatel rezervován k editaci. V takovém případě by došlo k chybě při pozdějším zapisování do samotného dokumentu a navíc by nadřízený schvaloval neaktuální verzi dokumentu. Druhá kontrola již pouze zjišťuje, zda úkol nemá pole „Stav“ nastaveno na „Dokončeno“, tedy zda úkol již nebyl řešen. Dalším krokem je již samotná aktualizace úkolu. Ta se provádí pomocí volání statické metody AlterTask. Tato metoda má tři parametry. Prvním parametrem je objekt SPListItem, reprezentující úkol, který se má upravit. Druhým parametrem je objekt Hashtable, jenž reprezentuje vlastnosti, které se mají na dané položce změnit. A posledním parametrem je binární hodnota určující, zda spustit volání této metody synchronně, nebo asynchronně. Tato metoda vytváří při svém spuštění nové vlákno, které se stará o změnu úkolu, je tedy možné pokračovat dál bez čekání na výsledek updatu nebo čekat, až dojde k provedené změně. Metoda vrátí binární hodnotu určující, zda se změna úkolu povedla. Pokud existuje vlastnost úkolu (tedy vlastnost objektu SPListItem) pojmenovaná stejně jako některý z klíčů v objektu Hashtable, dojde k úpravě hodnoty této vlastnosti. Pokud ovšem takový klíč ve vlastnostech položky SPListItem neexistuje, je tato „nová“ vlastnost přidána do objektu ExtendedProperties. Ve výše uvedeném příkladu je použit jako klíč GUID SPBuiltInFieldId.TaskStatus,který ve vlastnostech objektu SPListItem zaručeně najdeme, dojde tedy pouze k úpravě hodnoty této vlastnosti. Naopak vlastnost „Action“ slouží pro vnitřní účely workflow a dojde k jejímu uložení do objektu ExtendedProperties. Po provedené úpravě položky úkolu je zavoláno přesměrování na stránku defaultního zobrazení seznamu úkolů. Přesměrování pomocí metody Redirect umožňuje použít sadu SPRedirectFlags, a upravit tak cíl přesměrování. Hodnota UserSource zajistí navrácení do původně otevřené stránky, ze které byl úkol otevřen. Hodnota DoNotEndResponse zaručí, že webový server neukončí vlákno aktuálně
96
zpracovávající otevřenou webovou stránku ihned po přesměrování, ale dokončí zpracování stránky. Pokud by tato hodnota nebyla ve volání metody Redirect přítomná, došlo by k ThreadAbortException. SPUtility.Redirect(this.taskList.DefaultViewUrl, SPRedirectFlags.UseSource | SPRedirectFlags.DoNotEndResponse, HttpContext.Current);
Ve chvíli, kdy jsou změny úkolu odeslány do workflow, je možné provést poslední krok a tím je změna stavu požadavku, tedy změna obsahu pole „Stav požadavku“ a „Schvalovatel požadavku“.
15.6 Úprava hodnot v požadavku Pakliže se povedlo změnit úkol (tedy jeho stav), posledním nutným krokem bude změnit stav požadavku, tedy změnit hodnotu pole „Stav“ v požadavku a do pole „Schvalovatel“ vepsat, kdo provedl schválení nebo zamítnutí požadavku. Vyplněný soubor požadavku uložený v knihovně dokumentů má formát XML. Zdroj může vypadat následujícím způsobem: <my:myFields xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:my="http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-0503T20:40:31" xmlns:xd="http://schemas.microsoft.com/office/infopath/2003" xml:lang="en-us"> <my:date>2010-05-10 <my:name>Pavel Novák <my:software>MS Visual Studio 2010, Ultimate <my:price>1000 Kč <my:state>Zamítnuto <my:approver>Fajfr Jan
Elementy, které XML soubor obsahuje, přesně odpovídají polím požadavku. Hlavní element „my:myFields“ odpovídá jménu hlavního datového zdroje formuláře stejně tak jako definované namespace „my“ tomu uvedenému ve formuláři. Pokud otevřeme formulář v editačním módu, můžeme si zobrazit namespace formuláře takto: Na záložce „Data Source“ vybereme libovolné z polí a po kliknutí na „Properties“ zvolíme záložku „Details“.
97
Obrázek 63: Zjištění namespace formuláře v MS InfoPath
K editaci XML souboru můžeme zvolit v .NETu více cest, my zde použijeme namespace System.Xml. Abychom se k XML datům dostali, použijeme objekt SPFile, reprezentující soubor uložený v SharePointu. Referenci na něj získáme z položky požadavku, tedy opět z objektu SPListItem. SPFile file = document.File; MemoryStream inStream = new MemoryStream(file.OpenBinary()); XmlDocument doc = new XmlDocument(); doc.Load(inStream); inStream.Close();
Abychom mohli v tomto XML dokumentu navigovat a pohybovat se po konkrétních elementech, je nutné použít třídu XMLNamespaceManager a již výše zmíněný řetězec, který reprezentuje namespace požadavku. private const String formNamespace = "my"; private const String formURI = "http://schemas.microsoft.com/office/infopath/2003/myXSD/2010-05-03T20:40:31"; XmlNode root = doc.DocumentElement; XmlNamespaceManager xmlNSManager = new XmlNamespaceManager(doc.NameTable); xmlNSManager.AddNamespace(formNamespace, formURI);
Nyní již můžeme získávat a editovat požadované elementy. Prvním elementem bude pole „Approver“, tedy schvalovatel. Získáme tento element, pomocí Objektového modelu SharePointu získáme jméno aktuálně přihlášeného uživatele a vepíšeme jej do elementu. K získání elementu použijeme metodu SelectSingleNode, která je definovaná na objektu XmlNode. Tato metoda získá element ve struktuře XML souboru na základě XPath výrazu a XmlNamespace. XPath výraz nutný k nalezení elementu je opět
98
možné zjistit v editačním módu InfoPath formuláře. Na záložce „Data Source“ otevřeme kontextové menu na libovolném poli v hlavním datovém zdroji a zvolíme volbu „Copy XPath“, čímž se zkopíruje hledaný XPath výraz do schránky. XmlNode approver = root.SelectSingleNode("/my:myFields/my:approver", xmlNSManager); SPUser user = SPContext.Current.Web.CurrentUser; approver.InnerText = user.Name;
Podobně získáme pole „State“ neboli stav. Textovou hodnotu tohoto pole nastavíme podle položky vybrané v seznamu „rdbSelect“ (RadioButtonList). XmlNode state = root.SelectSingleNode("/my:myFields/my:state", xmlNSManager); String approvedText; if (rdbSelect.SelectedValue == "1") { approvedText = "Schváleno"; }else{ approvedText = "Zamítnuto"; } state.InnerText = approvedText;
Nyní pouze změny v objektu XmlDocument vepíšeme zpět do soboru požadavku. MemoryStream outStream = new MemoryStream(); doc.PreserveWhitespace = true; doc.Save(outStream); file.SaveBinary(outStream.ToArray()); outStream.Close();
Všimněte si nastavení proměnné PreserveWhiteSpaces na hodnotu true. Pokud by nebyl tento atribut nastaven, byly by vymazány všechny prázdné znaky. InfoPath klient s otevřením takového formuláře nemá problém, ale pokud by byl formulář „browser enabled“ a byl by otevírán v prohlížeči pomocí InfoPath Services, došlo by k chybě při jeho otevření (Schema validation found non-data type errors). Vykreslování formulářů v SharePointu je na změny v XML struktuře dokumentu „citlivější“ než InfoPath klient. Sebemenší změna ve struktuře XMLdokumentu, zde například vymazání prázdných znaků mezi elementy, může způsobit chybu při validaci a nevykreslení dokumentu.
15.7 Další metody v požadavku Obsluha tlačítka „Zrušit“ bude pouze přesměrování zpět na stránku s přehledem úkolů daného workflow: SPUtility.Redirect(this.taskList.DefaultViewUrl, SPRedirectFlags.UseSource,HttpContext.Current);
Další metodou bude posluchač události OnSelectedIndexChanged komponenty pro výběr zvolené akce, zde se provede pouze kontrola pro povolení tlačítka „Odeslat“ a zobrazení vrstvy s žádostí o dodatečné informace (pakliže je tato možnost vybrána).
99
protected void IndexChanged(object sender, EventArgs e) { btnSubmit.Enabled = rdbSelect.SelectedValue != null && task[SPBuiltInFieldId.TaskStatus].ToString() != "Dokončeno"; infoLayer.Visible = rdbSelect.SelectedValue == "3"; }
Poslední metodou ve formuláři pak bude metoda sloužící pro výpis chybové hlášky používaná v ostatních metodách formuláře. public void ReturnError(string errorMessage) { Response.Write(String.Format("<sctipt>alert({0})",errorMessage)); }
15.8 Formulář pro dodání dodatečných informací Tento formulář zde již nebude rozebrán do detailu, většina použitého kódu se dá převzít z formuláře pro schválení. Formulář bude obsahovat sumář požadavku a TextBox, do kterého bude moci žadatel doplnit požadované informace.
Obrázek 64: Ukázka formuláře pro dodání dodatečných informací
Jediným podstatným rozdílem zde budou informace, které odesíláme zpět do workflow. Není nutné odesílat identifikaci akce, kterou uživatel vybral, takže vložíme pouze text reprezentující doplněné informace. Hashtable returnTable = new Hashtable(); returnTable.Add("Changed", 1); returnTable.Add(SPBuiltInFieldId.PercentComplete, "100"); returnTable.Add(SPBuiltInFieldId.TaskStatus, "Dokončeno"); returnTable.Add("AddedInfo", txtInfo.Text); SPWorkflowTask.AlterTask(this.task, returnTable, true);
100
Tento formulář nebude provádět žádné změny v požadavku, není nutné měnit ani stav schvalovatele požadavku.
15.9 Publikování formulářů Formuláře budeme publikovat do složky LAYOUTS v centrálním úložišti SharePointu. Podrobně je tato část popsána již v jedné z předchozích kapitol, která se zabývá publikováním webových stránek do SharePointu. Zde je pouze přehled nutných kroků:
Nakopírování ASPX souborů do složky LAYOUTS
Vytvoření aplikace pomocí konfigurace Internet Information Services serveru (nutné pouze, pokud budou formuláře v samostatné složce)
Nahrání dynamických knihoven do BIN složky IIS serveru
Podepsání dynamické knihovny a její instalace do Global Assembly Cache
Po posledním kroku restart IIS serveru
Nyní by měly být formuláře připraveny k použití. V této chvíli ještě není možné je otestovat, protože formuláře se snaží při načítání ze HTTP požadavku získat ID seznamu a ID položky úkolu. Tyto hodnoty jsou automaticky vloženy do HTTP požadavku SharePointem, během požadavku na zobrazení úkolu.
15.10 Vytvoření vlastních typů obsahu pro jednotlivé úkoly Nyní, když máme formuláře hotové, vytvoříme vlastní typy obsahu, ve kterých použijeme tyto formuláře. Tím umožníme použití formulářů jako vstupních rozhraní pro uživatele našeho workflow. Definicí „typu obsahu“ je soubor elementu ve formátu XML, se specifickou strukturou.
101
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <XmlDocuments> <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url"> http://server/site/ApproveForm.aspx http://server/site/ApproveForm.aspx <Edit>http://server/site/ApproveForm.aspx
Element ContentType definuje typ obsahu. Jeho součástí jsou následující atributy: ID – identifikátor typu obsahu, který je složen ze dvou částí:
Prefix 0x01080100, který určuje, že se jedná o úkol pro workflow
Vygenerovaný GUID, pro jednoznačnou identifikaci
Prefixy typů obsahů tvoří stromovou strukturu; například k prefixu, který označuje „úkol ve workflow“ se dospěje následujícím způsobem: 0x01 – položka seznamu 0x0108 – úkol 0x01080100 – úkol pro workflow Existuje více prefixů, například následující strom určuje „XML dokument“: 0x01 – položka seznamu 0x0101 – dokument 0x010101 – XML dokument Group – volitelný atribut, řetězec určující, do jaké skupiny spadá tento typ obsahu. Podstatná informace v této definici typu obsahu je obsažena v elementu FormUris. Zde najdeme URL adresy použité ke zobrazení typu obsahu. Můžeme určit jiné webové adresy, tedy vytvořit různé webové formuláře pro vytvoření, editaci a zobrazení položky daného typu obsahu. Podobný ContentType vytvoříme i pro druhý úkol, tedy pro úkol přidání informací.
102
<Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <XmlDocuments> <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url"> http://server/site/AddInfoForm.aspx http://server/site/AddInfoForm.aspx <Edit>http://server/site/AddInfoForm.aspx
Upozornění: Definice typu obsahu musí obsahovat element FieldRefs, specifikující sloupce použité v typu obsahu, i v případě, kdy je tento element prázdný tak jako v předchozích ukázkách. Kdyby tento element nebyl zastoupen, došlo by při programové změně úkolu pomocí statické metody SPWorkflowTask.AlterTask k NullReferenceException. V tomto případě jde nejspíše o chybu v SharePointu. V momentě, kdy máme k dispozici definice typů obsahu, je nutné vytvořit feature a zabalit tyto soubory jako elementy do této feature. <ElementManifests> <ElementManifest Location="ApproveContentType.xml"/> <ElementManifest Location="InfoContentType.xml"/>
Nyní nakopírujeme složku se souborem „feature.xml“ a soubory elementů typů obsahu do složky FEATURES v centrálním úložišti SharePointu a následně pomocí nástroje STSADM nainstalujeme feature.
103
Jelikož atribut Scope, tedy rozsah feature, je nastaven na hodnotu „Site“, stačí nám aktivovat tuto feature pouze na kořenové stránce SharePointu. stsadm –o installfeature –name WorkflowForms (-force) stsadm –o activatefeature –name WorkflowForms –url http://sr-sp-vptest/
Tím jsme vytvořili vlastní typy obsahu pro úkoly „Schvalte požadavek“ a „Doplňte dodatečné informace“. Správná otázka by nyní byla: Jak v průběhu workflow vytvořit úkol daného typu obsahu? Odpověď je jednoduchá, slouží k tomu aktivita CreateTaskWithContentType, ze skupiny aktivit Windows SharePoint Services. O jejím použití se dočtete v následující kapitole o vývoji a modelování workflow.
15.11 Povolení typů obsahu Jakmile jsou typy obsahu vytvořeny a feature je s nimi nainstalována a aktivována na vybrané stránce, je nutné je povolit na konkrétním seznamu v SharePointu, na kterém budou používány. Postupujeme následující způsobem: Navigujeme na stránku seznamu:
Settings (Nastavení)
Advanced Settings (Upřesnit nastavení)
Allow management of content types (Umožnit správu typů obsahu?)
Content Types (Typy obsahu)
Add from existing site content types (Přidat ze stávajících typů obsahu webu)
Zde bychom již měli v nabídce najít typy obsahu, pod jmény, která jsme jim dali v předchozím kroku. Po přidání by měl seznam obsahovat čtyři typy obsahu: „Úkol“, „Úkol pro workflow“ a naše dva speciální typy, tak jak ukazuje následující obrázek:
Obrázek 65: Aktivování vlastních datových typů na seznamu v SharePointu
104
16.
Návrh a implementace workflow
Ve Visual Studiu vytvoříme nový projekt typu SharePoint 2007 State Machine Workflow. Pokud postupujete podle tohoto návodu, tak je vhodné přidat tento projekt do společného řešení (Solution) s projektem webových formulářů. Usnadníte si tak společné ladění obou projektů. Po vytvoření projektu bude nutné zadat URL adresu stránky, na niž chceme workflow vyvíjet, a po jejím správném zadání se objeví formulář, pomocí kterého určíme, ke kterému seznamu chceme workflow připojit. Dále na tomto formuláři určíme, který seznam se použije jako „History list“ (tedy pro logování historie workflow) a který seznam použijeme jako seznam úkolů („Task list“). Pro úkoly je možné si vytvořit vlastní seznam nebo použít seznam úkolů, jenž je standardně vytvořen na stránkách SharePointu.
Obrázek 66: Nastavení projektu workflow ve Visual Studiu
Po úspěšném zadání nás čeká již jen poslední formulář, na kterém lze vybrat, v jaké chvíli se workflow na dokumentu spustí. Povolíme manuální spuštění a automatické spuštění po vytvoření položky.
105
Obrázek 67: Nastavení podmínek spouštění workflow
16.1 Soubory feature a workflow Jak již bylo řečeno, zkompilované workflow bude nainstalováno do Global Assembly Cache. Abychom toto workflow zpřístupnili SharePointu, je nutné vytvořit feature, která SharePointu sdělí, kde konkrétní dynamickou knihovnu najít. Za tímto účelem obsahuje projekt workflow soubory „feature.xml“ a „workflow.xml“. Tyto soubory jsou vygenerovány pomocí Visual Studia během vytváření projektu.
16.2 Úpravy workflow Po vytvoření projektu se zobrazí design automaticky vygenerované třídy „Workflow1“ s prázdným počátečním stavem, který bude obsahovat jednu EventDriven aktivitu. Uvnitř této EventDriven aktivity najdeme aktivitu OnWorkflowActivated. Nejprve je vhodné přejmenovat třídu „Workflow1“. Pokud bychom se rozhodli pro přejmenování až později, kdy by workflow již bylo hotové, museli bychom ručně měnit vlastnosti většiny aktivit. V tomto příkladu je třída přejmenována a pojmenována „RequestWF“. Jakmile tak učiníme, musíme také upravit hodnotu CodeBesideClass v souboru „workflow.xml“ tak, aby odpovídala novému jménu. CodeBesideClass="RequestWF.RequestWF"
16.3 Příprava proměnných Dalším vhodným krokem je příprava proměnných, které budeme používat v průběhu programování workflow. Do třídy „RequestWF“ vložíme následující proměnné: GUID hodnoty specifikující vlastní typy obsahu, které jsme si vygenerovali v minulé kapitole. Budeme je používat ke správnému nastavení typů obsahu úkolu, které budeme pomocí aktivit CreateTaskWithContentType vytvářet. public string APPROVE_CONTENT_TYPE = "0x0108010085BF0534780145e1B1A2B1A93C4A1308"; public string ADD_INFO_CONTENT_TYPE = "0x0108010082C193682745444199D3CD555EE21574";
Dále si definujeme konstanty, jež nám pomohou při tvorbě workflow s určením, kterou akci uživatel s dokumentem provedl. Nejprve uložíme vybranou akci od proměnné „selectedAction“ a následně
106
budeme pomocí IfElse aktivit porovnávat s jednotlivými konstantami, do kterého stavu má workflow přejít. public byte selectedAction; public const byte APPROVED = 1; public const byte REJECTED = 2; public const byte ADD_INFO = 3;
Proměnné, které nám dají informaci, zda uživatel již změnil úkol, tedy zda provedl schválení, zamítnutí nebo doplnění informací: public bool approveTaskChanged = false; public bool addInfoTaskChanged = false;
Proměnné, ve kterých si uložíme informace, jež bude schvalovatel dodatečně požadovat nebo žadatel doplní, když je o to požádán: private String requestedInfo; private String addedInfo;
Poslední proměnná bude uživatelské jméno osoby, která vytvořila požadavek. Tomuto uživateli později přiřadíme úkol s žádostí o dodatečné informace: private String requesterLogin;
Všechny tyto proměnné budeme potřebovat během vytváření workflow na různých místech, ale považujeme za vhodné je zde takto popsat a v dalším textu se na ně pouze odkazovat.
16.4 Modelování workflow Upravíme vygenerovaný workflow diagram tak aby odpovídal stavovému diagramu aplikace. Z počátečního stavu (zde přejmenován na „approveState“) lze přejít do stavu, kdy uživatel přidává dodatečné informace („addInfoState“), nebo do konečného stavu („approvingFinishedState“). Připravte si prozatím stavy workflow a vložené EventDriven a StateInitialization aktivity. Detaily jednotlivých aktivit budou popsány dále. Stav „approveState“ obsahuje kromě již implicitně vložené aktivity EventDriven, obsahující OnWorkflowActivated aktivity, ještě aktivitu StateInitialization, sloužící k vytvoření nového úkolu, a další EventDriven aktivitu, obsahující OnTaskChanged aktivitu čekající na změnu nově vytvořeného úkolu. Stav „addInfoState“ obsahuje obdobně aktivity pro vytvoření úkolu (StateInitialization) a aktivitu pro změnu tohoto úkolu (EventDriven).
107
Obrázek 68: Stavový diagram workflow ve Visual Studiu
Vygenerovaný diagram obsahoval jeden stav s aktivitou typu EventDriven (v diagramu výše přejmenovaná na „workflowActivatedEvent“. Tato aktivita již automaticky obsahovala aktivitu OnWorkflowActivated, tak jak to ukazuje následující obrázek.
Obrázek 69: Stav schválení – aktivita OnWorkflowActivated
Budeme chtít, aby se po aktivaci workflow provedly určité kroky. Toho dosáhneme správným nastavením a použitím této aktivity. V okně vlastností najdeme vlastnost Invoked. Ta odkazuje na metodu, která má být spuštěna při vstupu workflow do této aktivity. Zde můžeme buď vyplnit jméno metody anebo dvojklikem na aktivitu nechat Visual Studio vygenerovat požadovanou metodu. Otevře se soubor třídy „RequestWF“ s nově vygenerovanou metodou. V momentě aktivace workflow budeme chtít zjistit, kdo je autorem požadavku, tak abychom v případě, že si schvalovatel vyžádá dodatečné informace, byli schopni přidat nový úkol „Doplňte dodatečné informace“ právě žadateli. To provedeme následujícím způsobem:
108
private void onWorkflowActivated_Invoked(object sender, ExternalDataEventArgs e) { requesterLogin = workflowProperties.Item.File.Author.LoginName; }
K získání autora požadavku použijeme proměnnou „WorkflowProperties“, také automaticky vygenerovanou při založení projektu, na kterou je napojená vlastnost WorkflowProperties aktivity OnWorkflowActivated, jejíž přehled vlastností je vidět na následujícím obrázku.
Obrázek 70: Vlastnosti aktivity OnWorkflowActivated
Tato proměnná obsahuje užitečné informace o workflow, jakými jsou:
Seznam dokumentů, ke kterému je workflow připojené
Seznam úkolů k danému požadavku
Uživatele, který započal workflow
Konkrétní položku seznamu, ke které se toto workflow váže
Právě z posledního zmíněného objektu, tedy z položky dokumentu, ke kterému je workflow připojené, můžeme získat autora tohoto dokumentu.
16.5 Vytvoření nového úkolu Nyní popíšeme podrobně aktivitu StateInitialization ve stavu „approveState“, ve které dojde k vytvoření úkolu. Do této aktivity vložíme pouze jednu vnitřní aktivitu, a to CreateTaskWithContentType.
109
Obrázek 71: Stav schválení – aktivita StateInitialization
Nyní bude nutné nastavit vlastnosti této aktivity. Je zde hned několik vlastností, které musíme nastavit. ContentTypeId – určuje typ obsahu nově vytvořeného úkolu. Správným nastavením určíme, který formulář použije SharePoint ke zobrazení nově vytvořeného úkolu. Právě zde použijeme GUID, které jsme vygenerovali pro typy obsahu v předchozí kapitole. Toto ID máme uložené jako globální proměnnou třídy „RequestWF“. Můžeme tedy pouze napojit tuto vlastnost na výše definovanou proměnnou. Napojení vlastnosti se ve Visual Studiu provádí kliknutí na ikonu se třemi tečkami v rohu dané vlastnosti. Pokud jsme si uložili GUID jako řetězcovou konstantu do třídy RequestWF, měli bychom jí být schopni lokalizovat na panelu „Bind to an existing member“. Další možností by bylo vložit text reprezentující GUID přímo v okně vlastností. CorrelationToken – je značka, jež jednoznačně určí, ke kterému úkolu se vložená aktivita vztahuje. Všechny aktivity týkající se úkolů musí mít správně nastavený CorrelationToken. K úkolu se mohou vztahovat aktivity CreateTask, CompleteTask, OnTaskChanged, UpdateTask. Ty aktivity, které se vztahují ke společnému úkolu, musí mít nastavený CorrelationToken na stejnou hodnotu. V této chvíli můžeme vytvořit nový CorrelationToken. Je potřena nastavit vlastníka tohoto tokenu. Jako vlastníka nastavíme stav „approveState“, čímž zpřístupníme tento CorrelationToken všem aktivitám v daném stavu. TaskId – GUID jednoznačně určující úkol v SharePointu. Napojíme tuto vlastnost na nové pole postupem „Bind to a new member“, „Create Field“ a designér nám automaticky vytvoří proměnnou, ke které budeme moci přistupovat a programově pro úkol vytvořit nové ID. TaskProperties – vlastnosti úkolu. Tuto položku využijeme pro nastavení standardních (AssignedTo, DueDate) i nestandardních (jakékoliv jiné) vlastností úkolů. Právě nastavení nestandardních vlastností nám umožní odeslat libovolný objekt do webových formulářů, pomocích, který bude uživatel pracovat s workflow systémem. Opět napojíme tuto vlastnost na nové pole („Bind to a new member, Create Field“), ke kterému budeme přistupovat programově. Důležité je pro proměnnou zvolit vhodné jméno,
110
protože k ní budeme přistupovat během vytváření úkolu. My jsme ji zde pojmenovali „approveTaskProperties“. MethodInvoking – Zde se specifikuje metoda, která bude volána při vstupu workflow do této aktivity. Dvojklikem na objekt aktivity nám Visual Studio tuto metodu vygeneruje. Jakmile dojde k vygenerování metody, otevře se třída „RequestWF“ a zobrazí se vygenerovaná metoda. Můžeme v této chvíli rovnou pokračovat a vepsat do metody následující řádky. private void createApproveTask_MethodInvoked(object sender, EventArgs e) { approveTaskId = Guid.NewGuid(); approveTaskProperties = new SPWorkflowTaskProperties(); approveTaskProperties.Title = "Schvalte požadavek na nový Software"; approveTaskProperties.AssignedTo = "domena\\uzivatel"; if (addedInfo != null) { approveTaskProperties.ExtendedProperties.Add("AddedInfo",addedInfo); } requestedInfo = null; }
Pracujeme zde s poli, která vygenerovalo Visual Studio v předchozím kroku, během nastavování vlastností. Nejprve vygenerujeme nový GUID pro nový úkol v SharePointu. Následně vygenerujeme pro tento úkol nový objekt vlastností (SPWorkflowTaskProperties). Nastavíme nadpis úkolu a přidělíme úkol uživateli. Zde je nutné nastavit login uživatele ve tvaru „doména\uživatel“. Pro začátek budeme předpokládat, že znáte login schvalovatele dokumentů, takže ho sem doplníme již v kódu. Poslední část nemusí být ještě zřejmá. Ve workflow máme vytvořenu proměnnou „addedInfo“, která obsahuje dodatečné informace, jež žadatel vyplní, pokud je o ně tázán. Jak tyto informace získáme z druhého úkolu „Doplňte dodatečné informace“, bude vysvětleno později. Zde kontrolujeme, zda toto pole není prázdné, a pokud není, uložíme jeho hodnotu do objektu ExtendedProperties, který je součástí vlastností. Objekt ExtendedProperties je typu Hashtable, proto můžeme uložit řetězec do této tabulky pod klíčem „AddedInfo“. V momentě otevření formuláře tyto ExtendedProperties získáváme a čteme z nich objekty, které nám odeslalo workflow. Jedná se v zásadě o vše, co bychom chtěli zobrazit a nejsme schopni to přečíst ani z položky úkolu (Title, AssignedTo), ani z položky samotného požadavku (Software, Jméno žadatele atd.). Při prvním vstupu workflow do „approveState“ stavu je proměnná „addedInfo“ zcela jistě prázdná. Jakmile uživatel požádá o dodatečné informace a žadatel tyto informace v dalším úkolu vyplní, vstoupí workflow podruhé do tohoto schvalovacího stavu. V té chvíli již ale bude v proměnné „addedInfo“ uloženo vše, co uživatel doplnil, takže dojde ke zobrazení těchto dodatečných informací ve formuláři úkolu.
111
Tím jsme vyřešili vytvoření úkolu. Nyní je nutné definovat změny, které nastanou v případě, že uživatel provede určitou akci, tedy kdy dojde ke změně tohoto úkolu. Pro úplnost ještě uvádíme přehled vlastností CreateTaskWithContentType aktivity.
Obrázek 72: Vlastnosti aktivity CreateTaskWithContentType
16.6 Změna úkolu Změně úkolu je vyhrazena druhá EventDriven aktivita v inicializačním stavu, v projektu pojmenována „approveChangedEvent“. V této aktivitě budeme chtít zpracovat uživatelskou akci a na základě dat obdržených z webového formuláře přejít do požadovaného stavu, zde buď koncového, anebo stavu pro přidání dodatečných informací. Zpracování se provede pomocí aktivity OnTaskChanged. V závislosti na výsledku se pomocí IfElse aktivity vybere jedna z možných větví a pomocí SetState aktivity se přejde do požadovaného stavu, tak jak je to znázorněno na následujícím obrázku.
112
Obrázek 73: Detail EventDriven aktivity – reakce na změnu ve stavu úkolu
Nejprve se podíváme na nastavení aktivity OnTaskChanged. Zde je nutné nastavit minimálně následující vlastnosti: CorrelationToken – jak již bylo zmíněno, musí být nastaven na stejný token jako u aktivity, která tento úkol vytváří. Tím dojde ke spojení požadovaných aktivit a WorkflowRuntime bude vědět, že se týkají stejného úkolu. TaskId – je potřeba napojit na již existující pole obsahující ID úkolu, které bylo vytvořeno během vytváření úkolu. AfterProperties – jedná se o objekt typu Hashtable, který po změně úkolu, tedy po změně položky SPListItem, jež reprezentuje úkol, vrátí vlastnosti na této položce SPListItem změněné. Tento objekt napojíme na nové pole (zde pojmenované „approveAfterProperties“), pomocí kterého následně získáme hodnoty vložené do úkolu pomocí webového formuláře.
113
Obrázek 74: Vlastnosti aktivity OnTaskChanged
Invoked – opět specifikuje metodu, k jejímuž spuštění dojde při vstupu workflow do této aktivity. Dvojklikem lze vygenerovat automaticky. Tuto metodu upravíme následujícím způsobem. private void onApproveTaskChanged_Invoked(object sender, ExternalDataEventArgs e) { object changed = approveAfterProperties.ExtendedProperties["Changed"]; this.approveTaskChanged = Convert.ToBoolean(changed); object action = approveAfterProperties.ExtendedProperties["Action"]; this.selectedAction = Convert.ToByte(action); if (this.selectedAction == ADD_INFO) { object info = approveAfterProperties.ExtendedProperties["RequestedInfo"]; requestedInfo = info as String; } }
V této metodě se snažíme získat informace, které byly odeslány do workflow pomocí metody SPWorkflowTask.AlterTask z webového formuláře. Pomocí této metody jsme upravili vlastnosti úkolu tak, aby obsahoval i vlastnosti definované v objektu Hashtable, který se předával jako argument metodě SPWorkflowTask.AlterTask. Teď k těmto objektům můžeme přistoupit podobným způsobem, tedy najdeme objekty v Hashtable pod těmi samými klíči, pod kterými jsme je do objektu Hashtable ve webovém formuláři ukládali. Prvním získávaným objektem je informace o tom, zda byl úkol opravdu editován naším webovým formulářem. Protože Hashtable vrací vždy pro daný klíč instanci třídy Object, je nutné přetypování. object changed = approveAfterProperties.ExtendedProperties["Changed"]; this.approveTaskChanged = Convert.ToBoolean(changed);
114
Dále je nutné zjistit, kterou akci uživatel vybral, a také tuto akci si uložit do globální proměnné. Pokud uživatel vybral akci „Požádat o dodatečné informace“, tak z objektu ExtendedProperties získáme ještě řetězec specifikující, co konkrétně schvalovatel požaduje. Pro kontrolu vybrané akce používáme konstantu „ADD_INFO“. Získané hodnoty si ukládáme do dříve definovaných globálních proměnných. Nyní, když jsme získali informace z webového formuláře, je nutné na jejich základě rozhodnout, do kterého stavu má workflow přejít. Na obrázku detailu aktivity „approveChangedEvent“ jsou vidět dvě větve. Jedna přechází do konečného stavu a druhá do stavu sloužícího pro přidání informací. Nejprve nastavíme podmínku pro větev, která přechází do stavu pro přidání dodatečných informací. Použijeme deklarativní podmínku (Declarative Rule Condition) tak, jak ukazuje následující obrázek:
Obrázek 75: Nastavení deklarativního pravidla pro přechod do stavu přidání informací
Jinými slovy, chceme přejít do této větve v případě, že byl úkol změněn a vybraná akce měla hodnotu konstanty ADD_INFO. this.selectedAction == RequestWF.RequestWF.ADD_INFO && this.approveTaskChanged
V případě druhé větve budeme chtít podmínku upravit. Nutné bude, aby byl úkol změněn a vybraná akce neměla hodnostu konstanty ADD_INFO, tedy aby měla hodnotu konstanty APPROVE nebo REJECT, ale to zde již není podstatné. this.selectedAction != RequestWF.RequestWF.ADD_INFO && this.approveTaskChanged
Pak zbývá již jen upravit vlastnosti TargetStateName u aktivit SetState a máme vyřešenou změnu úkolu, tedy změnu stavu požadavku, a můžeme přejít k úpravě stavu, který slouží k přidání dodatečných informací.
115
16.7 Stav přidání dodatečných informací Modelování tohoto stavu bude již mnohem jednodušší. První aktivitou bude StateInitialization. V této aktivitě opět vytvoříme nový úkol, ve kterém žadatel doplní požadované informace. Struktura této aktivity bude podobná jako v případě prvního stavu, bude tedy obsahovat pouze jednu CreateTaskWithContentType aktivitu.
Opět zde bude nutné nastavit vlastnosti, které byly nastavovány i v případě prvního stavu, tedy především: CorrelationToken, TaskId, TaskProperties a Invoked, tj. odkaz na metodu, která se má vyvolat. Struktura této metody bude opět velice podobná té již dříve uvedené. private void createAddInfoTask_MethodInvoked(object sender, EventArgs e) { addInfoTaskId = Guid.NewGuid(); addInfoTaskProperties = new SPWorkflowTaskProperties(); addInfoTaskProperties.Title = "Doplňte dodatečné informace"; addInfoTaskProperties.AssignedTo = requesterLogin; addInfoTaskProperties.ExtendedProperties.Add("RequestedInfo", requestedInfo); }
Zde jsou pouze dvě změny. Úkol je přiřazen osobě, která vyplňovala požadavek, login této osoby máme uložen v globální proměnné „requesterLogin“. A dále je do objektu ExtendedProperties přidána hodnota proměnné „requestedInfo“. Tu jsme získali z minulého úkolu, v momentě, kdy schvalovatel požádal o dodatečné informace. Jakmile tuto proměnnou vložíme do objektu ExtendedProperties, můžeme k ní přistupovat pomocí objektu Hashtable získaného ve webovém formuláři voláním. wfProperties = SPWorkflowTask.GetExtendedPropertiesAsHashtable(task);
Teď je již nutné pouze zpracovat změnu tohoto úkolu. Změnu zpracujeme pomocí aktivity OnTaskChanged. Následující obrázek ukazuje detail EventDriven aktivity, která obsahuje OnTaskChanged aktivitu a následně aktivitu SetState, jež přejde zpět do schvalovacího stavu za podmínek určených aktivitou typu IfElse.
116
U aktivity OnTaskChanged je nutné nastavit CorrelationToken a TaskId tak, aby odpovídaly hodnotám z výše uvedené aktivity CreateTaskWithContentType. Dále je nutné napojit vlastnost AfterProperties na novou proměnnou, která umožní získat potřebná data po změně úkolu. Posledním krokem bude určení metody, která má být zavolána pomocí vlastnosti Invoked. Tato metoda bude obsahovat následující kód: private void onAddInfoChanged_Invoked(object sender, ExternalDataEventArgs e) { object changed = addInfoAfterProperties.ExtendedProperties["Changed"]; this.addInfoTaskChanged = Convert.ToBoolean(changed); if (addInfoTaskChanged) { object info = addInfoAfterProperties.ExtendedProperties["AddedInfo"]; this.addedInfo = info as String; } }
Zde opět používáme vlastnosti úkolu po změně, tedy objekt AfterProperties, abychom získali informace z webového formuláře. Jednak proměnnou indikující, zda byl formulář změněn, a jednak dodatečné informace, tedy řetězec, který vyplnil žadatel. Zde se tedy opět odkazujeme na klíče, pod kterými jsme vložili informace do objektu Hashtable, jenž byl použit ke změně úkolu. Zde je pro doplnění uvedena ta část kódu webového formuláře, ve které vytváříme objekt Hashtable, abychom s jeho pomocí editovali položku SPListItem reprezentující úkol.
117
Hashtable returnTable = new Hashtable(); returnTable.Add("Changed", 1); returnTable.Add(SPBuiltInFieldId.PercentComplete, "100"); returnTable.Add(SPBuiltInFieldId.TaskStatus, "Dokončeno"); returnTable.Add("AddedInfo", txtInfo.Text);
Právě pod klíčem „AddedInfo“ jsme tedy schopni získat řetězec reprezentující informace, které uživatel doplnil. Jakmile máme zpracovánu událost o změně úkolu, je již jen potřeba zaručit, aby došlo k přechodu do počátečního stavu. Avšak pouze, pokud byl úkol opravdu změněn a dodatečné informace doplněny. Za aktivitu OnTaskChanged je tedy vložena IfElse aktivita, která kontroluje, zda došlo ke změně úkolu. Podmínka této aktivity je opět zadána pomocí deklarativního pravidla (Declarative Rule Condition) a pouze odkazuje na proměnnou, ve které je již indikace změny úkolu uložená. Stačí tedy nastavit podmínku na: this.addInfoTaskChanged Vložená aktivita SetState má nastaven jako cílový stav počáteční „schvalovací“ stav našeho workflow.
16.8 Ladění aplikace Visual Studio 2008 nám usnadňuje ladění workflow. Stačí pouze spustit projekt stisknutím klávesy F5 a automaticky se otevře okno prohlížeče přesměrované na stránku se seznamem, ke kterému je workflow připojeno. Zde je možné vkládat „breakpointy“ na libovolná místa, i na jednotlivé aktivity ve workflow diagramech, a můžeme tak odkrokovat celou aplikaci. Pokud vložíme projekt webového formuláře do stejného řešení jako u projektu workflow a projekt workflow necháme nastaven jako inicializační („Set As Start Up Project“ v kontextovém menu Solution Exploreru), budeme moci ladit zároveň i kód webových formulářů. SharePoint používá pro svůj běh proces označený „w3wp“. Visual Studio po stisknutí F5 provede hned několik úkonů:
Nainstaluje nebo aktualizuje dynamickou knihovnu v Global Assembly Cache
Nainstaluje a aktivuje feature obsahující workflow na nastavenou stránku v SharePointu
Provede restart IIS serveru
Připojí Debugger k procesu „w3wp“ na lokálním počítači
Všechny tyto kroky bychom mohli provést ručně, nicméně Visual Studio ušetří hodně času právě tím, že vše provede jednorázově a za nás. Webové stránky ve složce LAYOUTS jsou také spouštěny procesem w3wp. Pokud tedy máme stránky ve stejném projektu jako workflow a debugger je připojen k procesu w3wp, Visual Studio nám umožní ladit i webové formuláře.
118
16.8.1. Ladění na vzdáleném počítači Pokud ovšem převedeme vytvořené řešení do produkčního prostředí, tedy většinou na jiný než vývojový počítač, kde nebude nainstalované Visual Studio 2008, budeme muset použít vzdálené ladění, tj. připojit Debugger k procesům běžícím na jiném počítači. K tomu je nutné spustit na hostitelském stroji nástroj Remote Debugger 2008. Ten je možné samostatně stáhnout nebo jej můžete najít v instalaci vašeho Visual Studia. Jakmile spustíme tento nástroj na hostitelském stroji, můžeme se vzdáleně z Visual Studia připojit k tomuto stroji a připojit Debugger k procesu w3wp. Zvolíme v menu „Tools“, „Attach to Process“ a v novém dialogu zadáme do pole „Qualifier“ jméno nebo IP adresu vzdáleného počítače. Po aktualizaci seznamu procesů bychom již měli být schopni lokalizovat proces w3wp. Samozřejmě je nutné mít na hostitelském a vývojovém počítači stejné verze dynamických knihoven.
16.9 Deployment – přenos do produkčního prostředí Pro přenesení workflow do produkčního prostředí je vhodné si uvědomit, které části je nutné převést a kam jednotlivé dynamické knihovny umístit a nainstalovat. Zde ještě jednou krátký přehled: Global Assembly Cache
Dynamická knihovna workflow
Dynamická knihovna webových formulářů
BIN složka IIS serveru
Dynamická knihovna webových formulářů
Složka FEATURES
Feature pro vložení nových typů obsahu
Feature obsahující odkaz na workflow
Složka TEMPLATES
Webové formuláře
Aby proces instalace několika nových funkcí mohl být proveden jednorázově, lze využít technologii SharePoint Solutions. SharePoint Solutions jsou balíčky dodatečných funkčností zkomprimovaných do jednoho souboru, které lze jednorázovou instalací nasadit na konkrétní portál SharePointu. Řešení se skládají především z features a webových stránek, ale mohou obsahovat i další položky, například webové části (SharePoint Web Parts). Instalace řešení se provádí pomocí nástroje STSADM. SharePoint Solutions jsou soubory s příponou WSP, jež musí obsahovat XML soubor „manifest.xml“, který definuje obsah řešení. Zde se konkrétně tvorbou WSP balíčků nebudeme zabývat. Je vhodné poznamenat, že existuje celá řada open source nástrojů, které mohou usnadnit tvorbu řešení. Jedním z nejlepších je bezesporu nástroj WSPBuilder, který je lze integrovat do Visual Studia 2008, a nastavit tak, aby po kompilaci došlo vždy ke zkompilování všech částí projektu do WSP balíčku a ten mohl být následně bez dalších komplikací převeden do produkčního prostředí.
119
16.10 Ukázka fungování systému Vložení požadavku se provádí otevřením šablony na seznamu požadavků. Pokud jsou na SharePoint serveru povoleny InfoPath Services, je možné požadavek vyplnit přímo jako webovou stránku. Pokud tomu tak není, je nutné mít nainstalovaný InfoPath na klientském počítači.
Obrázek 76: Zadání požadavku
Po kliknutí na tlačítko „Odeslat“ se okno s formulářem zavře a zobrazí se přehled požadavků s již vloženým vyplněným formulářem. Zde si můžete všimnout, že sloupce tohoto seznamu odpovídají polím formuláře stejně jako hodnoty vložené do těchto polí.
Obrázek 77: Seznam požadavků
V pravém rohu tohoto seznamu je u vloženého požadavku sloupec, ve kterém je stav workflow. Protože je povoleno automatické spuštění workflow ihned po vložení požadavku je zde již workflow spuštěné (hodnota „Probíhá“ nebo „In Progress“ podle jazykové mutace SharePointu). Po kliknutí na tento odkaz se otevře stránka s bližšími informacemi o workflow.
120
Obrázek 78: Stav workflow v prostředí SharePointu
Na této stránce je vidět mimo jiné, kým a kdy bylo workflow započato, ke kterému dokumentu se vztahuje, jaký je jeho status a ve spodní části seznam úkolů, které se k tomuto workflow vztahují. Zde vidíme, že byl vytvořen první úkol s názvem „Schvalte požadavek na nový software“. Po kliknutí na odkaz se otevře webová stránka, kterou jsme pro tento úkol vytvořili.
Obrázek 79: Úkol schválení požadavku
Pro tuto chvíli jsme jako schvalovatel zvolili žádost o dodatečné informace a vyplnili jsme, co konkrétně po žadateli požadujeme. Po kliknutí na tlačítko „Odeslat“ se opět vrátíme na stránku s informacemi o workflow, zde se změnil seznam úkolů.
121
Obrázek 80: Stav workflow po dokončení více úkolů
Je vidět, že je zde druhý úkol, přidělený osobě, která vyplňovala žádost. Stav prvního úkolu je nastaven na „Dokončeno“. Po kliknutí na odkaz úkolu se otevře připravený formulář, s žádostí o dodatečné informace.
Obrázek 81: Úkol sloužící k doplnění informací
Jakmile uživatel stiskne tlačítko „Odeslat“, formulář se zavře a uživatel se ocitne zpět na stránce s informacemi o workflow. Zde je opět možné otevřít nový úkol, ve kterém je schvalovatel žádán o schválení. Pokud tentokrát schvalovatel provede schválení či zamítnutí, stav workflow stejně jako stav všech úkolů v tomto workflow bude nastaven na „Completed“ nebo „Dokončeno“. Samozřejmě, pokud je na seznamu úkolů nastaveno automatické odesílání e-mailů, uživatelé obdrží informaci o přiřazení nového úkolu poštou.
16.11 Závěr Závěrem ještě jednou popíšeme, které kroky byly potřeba k vytvoření workflow v SharePointu. 1. Vytvoření seznamu s dokumenty, na kterých bude spuštěno workflow, případně použití nástroje MS InfoPath k vytvoření toho seznamu včetně šablony dokumentu. 2. Vytvoření webových formulářů jako rozhraní pro uživatele workflow, publikování těchto formulářů do SharePointu.
122
3. Vytvoření vlastních typů obsahu, které se budou odkazovat na vytvořené webové formuláře, aktivace těchto typů obsahu na jednotlivých stránkách a jejich povolení na jednotlivých seznamech. 4. Vytvoření workflow pomocí Visual Studia. Použití aktivit CreateTaskWithContentType, které umožní vytvoření úkolů konkrétních typů. Z tohoto přehledu je vidět, že proces tvorby workflow není úplně snadný a požaduje na vývojáři znalosti hned z několika oblastí: Workflow Foundation, SharePoint Object Model, ASP.NET, SharePoint Features, SharePoint Content Types a případně i znalost nástroje InfoPath. Nicméně doufáme, že tato publikace vysvětluje právě základy těchto jednotlivých oblastí a umožní tyto znalosti spojit při tvorbě nového workflow v SharePointu.
123
17.
Tipy a triky pro vývoj workflow v SharePointu
Poslední kapitola bude obsahovat několik tipů, které se mohou hodit v případě, že vyvíjíte rozsáhlé workflow v SharePointu.
17.1 Programové povolení typů obsahu na seznamu Abychom byli schopni použít pro interakci uživatele s workflow přes webové formuláře, používáme úkoly s jednoznačně určeným typem obsahu. Tyto typy obsahu je potom nutné ručně povolit na konkrétním seznamu. Zde si ukážeme, jak to provést pomocí objektového modelu SharePointu například při aktivaci workflow. Máme tedy definovaný seznam, na kterém chceme daný typ povolit,a řetězec reprezentující GUID vlastního typu obsahu. SPList taskList; String taskContentType;
Nejprve je nutné zjistit, zda jsou na daném seznamu povoleny vlastní typy obsahu, a pokud tomu tak není, tak je povolit. if (taskList.ContentTypesEnabled != true) { taskList.ContentTypesEnabled = true; }
Dále vytvoříme objekt SPContentType, který reprezentuje typ obsahu v objektovém modelu SharePointu. SPContentTypeId ctID = new SPContentTypeId(taskContentType); SPContentType contentType = taskList.ParentWeb.Site.RootWeb.ContentTypes[ctID];
Pokud se podařilo tento objekt vytvořit, projdeme postupně všechny objekty SPContentType povolené na vybraném seznamu a porovnáváme s požadovaným typem obsahu. Pokud se nepodařilo objekt vytvořit, znamená to, že daný typ není aktivován na daném webu (proto je nutné testovat na null). Pokud se nepodaří daný typ na seznamu najít, přidáme ho do seznamu typů obsahu.
124
if (contentType != null) { bool contenTypeExists = false; foreach (SPContentType ct in taskList.ContentTypes) { if (ct.Name == contentType.Name) { contenTypeExists = true; break; } } if (contenTypeExists != true) { taskList.ContentTypes.Add(contentType); }
Je vhodné si pro výše uvedenou proceduru vytvořit například metodu se dvěma parametry (seznam a typ obsahu), kterou můžeme zavolat vždy při aktivaci workflow (například pomocí OnWorkflowActivated aktivity), a zkontrolovat tak, zda použité typy obsahu opravdu existují a jsou povolené.
17.2 Posluchače událostí seznamu Posluchače událostí seznamu využijeme například ve chvíli, kdy nám nevyhovují standardní e-maily odesílané SharePointem v momentě vytvoření nového úkolu. Pokud bychom chtěli například vložit do e-mailu více informací, budeme za tímto účelem muset naprogramovat posluchač události, který se v momentě přidání nové položky postará o odeslání e-mailu. Nejprve je nutné posluchač vytvořit a následně ho můžeme registrovat s daným seznamem. 17.2.1. Implementace posluchače události ItemAdded Existuje více událostí, o nichž seznam v SharePointu pukod nastanou informuje všechny posluchače, které jsou se seznamem registrovány. Nejběžnější a nejpoužívanější jsou události týkající se položek: ItemAdded, ItemUpdated a ItemDeleted. Zde si ukážeme, jak po zachycení události ItemAdded na seznamu úkolů odeslat e-mail, který obsahuje informace nejen o úkolu samotném, ale i dokumentu, na němž je spuštěno workflow, se kterým je úkol svázán. Posluchačem události je třída dědící od třídy SPItemEventReceiver, která může obsahovat přepsané metody reagující na jednotlivé události. Zde přepíšeme metodu ItemAdded. class TaskEventReceiver : SPItemEventReceiver { public override void ItemAdded(SPItemEventProperties properties) { } }
Do této metody umístíme postupně následující volání. Nejprve je nutné získat aktuální přidanou položku, tedy objekt SPListItem reprezentující aktuální úkol. SPListItem task = properties.ListItem;
125
Ve standardním e-mailu jsou obsaženy pouze informace, které jsme schopni získat z této položky. My bychom ale chtěli do e-mailu vložit i informace z dokumentu, se kterým je tento úkol svázán (tedy například z původního požadavku). Použijeme zde část kódu, která již byla použita v přepsané metodě OnLoad webových formulářů. Guid wfInstanceID = new Guid(task[SPBuiltInFieldId.WorkflowInstanceID] as String); SPWorkflow workflow = new SPWorkflow(task.Web, wfInstanceID); SPList documentlist = task.Web.Lists[workflow.ListId]; Guid wfId = new Guid(task[SPBuiltInFieldId.WorkflowInstanceID] as String); SPListItem document = documentlist.Items[workflow.ParentItem.UniqueId];
Nyní, v momentě, kdy máme obě položky – úkol i dokument, se kterým je aktuální úkol svázán – již není problém získat potřebné informace a vložit je do e-mailu k odeslání. Například získáme původního autora dokumentu (požadavku) a datum a termín splnění úkolu následujícím způsobem: String deadline = task[SPBuiltInFieldId.TaskDueDate] as String; String requesterName = document[SPBuiltInFieldId.Author] as String;
Samotné odeslání pak můžeme provést pomocí tříd ze jmenného prostoru System.Net.Mail. 17.2.2. Registrace posluchače událostí se seznamem Přidání posluchače událostí k seznamu SharePointu provedeme také pomocí objektového modelu SharePointu. Dynamickou knihovnu, která obsahuje posluchače událostí, musíme nainstalovat do Global Assembly Cache. Dynamická knihovna musí mít „silné“ jméno, aby mohla být nainstalována do Global Assembly Cache, a toto jméno následně použijeme i k registraci posluchače s vybraným seznamem v SharePointu. string assembly = "TaskEventReceiver, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1d979d634c90501d"; string className = "TaskEventReceiver.TaskEventReceiver"; AddEventReceiver("http://server/site", "Úkoly", assembly, className);
A zde následuje definice metody „AddEventReceiver“. Počítáme s tím, že metodu „GetSPList“ sloužící k získání objektu SPList máte již implementovanou nebo ji vytvoříte podle základních příkladů z kapitoly o objektovém modelu SharePointu. private void AddReceiver(String site,String lName, String assembly, String cName) { SPList list = GetSPList(site, lName); list.EventReceivers.Add(SPEventReceiverType.ItemAdded, assembly, cName); }
Pro úplnost zde uvedeme i metodu pro odebrání posluchače událostí ze seznamu.
126
private void RemoveReceiver(String site, String lName, String assembly, String cName) { SPList list = GetSPList(site, lName); bool found = false; SPEventReceiverDefinition erd = null; for (int i = 0; i < list.EventReceivers.Count; ++i) { erd = list.EventReceivers[i]; if (erd.Assembly == assembly && erd.Class == cName) { found = true; break; } } if (found) { erd.Delete(); } }
17.3 Nastavení práv k úkolu Pokud chceme povolit editaci úkolu, tedy například schválení nebo zamítnutí, jen některým uživatelům, musíme nastavit uživatelská práva na konkrétní položku SPListItem. Pokud vytváříme úkoly pomocí workflow aktivit SharePointu, umožní nám to vlastnost SpecialPermissions aktivity CreateTaskWithContentType. Tuto vlastnost lze napojit na proměnnou typu HybridDictionary. HybridDictionary je speciálním typem kolekce, který, pokud je kolekce malá, ukládá objekty do spojového seznamu, ale jakmile je již položek více (desítky), je kolekce implementována jako objekt Hashtable. V projektu si tedy můžeme vytvořit vlastnost, která nám vrátí objekt HybridDictionary, do něhož uložíme uživatelská práva. public HybridDictionary TaskPermission { get { HybridDictionary permsCollection = new HybridDictionary(); permsCollection.Add("domain\\login", SPRoleType.Administrator); return permsCollection; } }
Vlastnost SpecialPermissions potom napojíme na tuto proměnnou („Bind to an existing member“). Klíč objektu v HybridDictionary nastavíme na uživatelské jméno nebo jméno skupiny a jako objekt přiřadíme typ uživatelských práv, která uživatel obdrží. Tato práva jsou definována ve statické třídě SPRoleType.
127
18.
Závěr
V této příručce jsme se pokusili shrnout některá pravidla a doporučení pro tvorbu workflow v SharePointu 2007. Aby byl programátor schopen vytvářet workflow v SharePointu, musí zvládnout jak platformu Workflow Foundation, tak objektové rozhraní SharPointu (SharePoint Object Model). Právě proto je každé z těchto oblastí věnována jedna část této příručky.
18.1 Shrnutí obsahu příručky V první části o Workflow Foundation je na jednoduchém příkladu aplikace simulující platební bankomat ukázáno, jak namodelovat a v desktopové aplikaci použít stavové workflow. Druhá část o objektovém modelu SharePointu obsahuje dva příklady, které ilustrují základní techniky práce se seznamy a položkami, a jeden příklad na vkládání vlastních webových stránek do SharePointu. Jakmile uživatel zvládne obsah těchto dvou kapitol, může se pustit do poslední, komplexní části o vývoji workflow v SharePointu. Zde je na jednoduchém příkladu workflow schválení „Požadavku na nový software“ vysvětleno, jak namodelovat a použít stavové workflow v SharePointu. Nejprve je teoreticky popsán způsob zakomponování Workflow Foundation do SharePointu a následně je rozebráno navrhované řešení. Programátor se v této části mimo jiné dozví, jak využít nástroje MS InfoPath k návrhu formuláře požadavku a jak namodelovat workflow jako sled po sobě jdoucích úkolů. V poslední části je dále zmíněno několik typů a triků, které se mohou hodit při tvorbě workflow v SharePointu.
18.2 Shrnutí programování workflow v SharePointu Workflow jsou v SharePointu chápána jako sled po sobě jdoucích a navazujících úkolů. V SharePointu se workflow vždy musí vztahovat k položce v seznamu, ať již je to dokument anebo blíže nedefinovaná položka obsahující libovolné pole. Workflow tedy vyjadřuje průchod položky přes určité stavy, a měl by tak odpovídat business procesu, který se snažíme namodelovat. V případě workflow vztahujícího se k dokumentu jednoduše modelujeme pohyb dokumentu po firmě. K tomu, abychom umožnili uživatelům interakci se systémem, musíme navrhnout webové formuláře, které umožní schválit nebo zamítnout dokument. Takových úkolů, jež mohou uživatelé se systémem provádět, může být více: doplňování informace, hromadné vytváření, vkládání příloh a další. K tomu, abychom přiřadili webový formulář k úkolu jako jeho grafickou reprezentaci, použijeme vlastní typy obsahu, které SharePoint umožňuje definovat.
128
Pro vytvoření celého řešení je nutné používat SharePoint Features, které umožnují přidávat do SharePointu dodatečné funkce, mezi nimi právě workflow. SharePoint tedy umožňuje vývojářům modelovat business procesy, a to především ty, které souvisí s oběhem dokumentů. V integraci s MS Visual Studiem se jedná o poměrně silný nástroj, pomocí něhož lze implementovat v podstatě libovolně složité workflow. Řada již vytvořených aktivit ulehčuje běžné programátorské úlohy, jako je odesílání e-mailů, konzumace webových služeb nebo reakce na externí události. Zapojení Workflow Foundation do SharePointu je jedinečnou šancí pro firmy zmapovat a namodelovat své business procesy a zapojit je do již funkční infrastruktury intranetového portálu postaveného na technologii MS SharePoint.
129
Autor: Bc. Jan Fajfr SharePoint 2007 a Workflow Anotace:
Modelování a programování elektronického oběhu dokumentů na platformě SharePoint. Integrace objektového modelu SharePointu a Workflow Foundation.
Vydání: Rok prvního vydání: Jazyková korektura: Vydal:
první 2010 Jana Otevřelová Artax a.s., Žabovřeská 16, 616 00 Brno pro Microsoft s.r.o., Vyskočilova 1461/2a, 140 00 Praha 4
Text je přepracovanou verzí bakalářské práce vypracované na katedře počítačů Elektrotechnické fakulty Českého vysokého učení technického v Praze, obhájené dne 29.6.2009.
130
131