Cara membuat dan menjalankan alur kerja yang berjalan lama
Salah satu fitur utama dari Windows Workflow Foundation (WF) adalah kemampuan runtime untuk bertahan dan membongkar alur kerja yang menganggur ke database. Langkah-langkah dalam Cara: Menjalankan Alur Kerja menunjukkan dasar-dasar hosting alur kerja menggunakan aplikasi konsol. Contoh ditunjukkan alur kerja awal, penangan siklus hidup alur kerja, dan melanjutkan bookmark. Untuk mendemonstrasikan ketekunan alur kerja secara efektif, host alur kerja yang lebih kompleks diperlukan yang mendukung memulai dan melanjutkan beberapa instans alur kerja. Langkah dalam tutorial ini menunjukkan cara membuat aplikasi host formulir Windows yang mendukung memulai dan melanjutkan beberapa instans alur kerja, ketekunan alur kerja, dan menyediakan dasar untuk fitur lanjutan seperti pelacakan dan pembuatan versi yang ditunjukkan dalam langkah tutorial berikutnya.
Catatan
Langkah tutorial ini dan langkah-langkah selanjutnya menggunakan ketiga jenis alur kerja dari Cara: Membuat Alur Kerja.
Untuk membuat database persistensi
Buka SQL Server Management Studio dan hubungkan ke server lokal, misalnya .\SQLEXPRESS. Klik kanan node Databases di server lokal, dan pilih Database Baru. Beri nama database baru WF45GettingStartedTutorial, terima semua nilai lainnya, dan pilih OK.
Catatan
Pastikan Anda memiliki izin Buat Database di server lokal sebelum membuat database.
Pilih Buka, File dari menu File. Jelajahi folder berikut: C:\Windows\Microsoft.NET\Framework\v4.0.30319\sql\en
Pilih dua file berikut dan klik Buka.
SqlWorkflowInstanceStoreLogic.sql
SqlWorkflowInstanceStoreSchema.sql
Pilih SqlWorkflowInstanceStoreSchema.sql dari menu Jendela. Pastikan bahwa WF45GettingStartedTutorial dipilih di menu dropdown Database yang Tersedia dan pilih Eksekusi dari menu Kueri.
Pilih SqlWorkflowInstanceStoreLogic.sql dari menu Jendela. Pastikan bahwa WF45GettingStartedTutorial dipilih di menu dropdown Database yang Tersedia dan pilih Eksekusi dari menu Kueri.
Peringatan
Penting untuk melakukan dua langkah sebelumnya dalam urutan yang benar. Jika kueri dijalankan tidak sesuai urutan, kesalahan terjadi dan database persistensi tidak dikonfigurasi dengan benar.
Untuk menambahkan referensi ke rakitan DurableInstancing
Klik kanan NumberGuessWorkflowHost di Penjelajah Solusi dan pilih Tambahkan Referensi.
Pilih Rakitan dari daftar Tambahkan Referensi, dan ketik
DurableInstancing
ke dalam kotak Cari Rakitan. Tindakan ini akan menyaring rakitan dan membuat referensi yang diinginkan lebih mudah untuk dipilih.Centang kotak di samping System.Activities.DurableInstancing dan System.Runtime.DurableInstancing dari daftar Hasil Pencarian, dan klik OK.
Untuk membuat formulir host alur kerja
Klik kanan NumberGuessWorkflowHost di Penjelajah Solusi dan pilih Tambahkan, Item Baru.
Di daftar template Terinstal, pilih Formulir Windows, ketik
WorkflowHostForm
di kotak Nama, dan klik Tambahkan.Konfigurasikan properti berikut pada formulir.
Properti Nilai FormBorderStyle FixedSingle MaximizeBox Salah Ukuran 400, 420 Tambahkan kontrol berikut ke formulir dalam urutan yang ditentukan dan konfigurasikan properti seperti yang diarahkan.
Menguasai Property: Nilai Kancing Nama: NewGame
Lokasi: 13, 13
Ukuran: 75, 23
Teks: Game BaruLabel Lokasi: 94, 18
Teks: Tebak angka dari 1 hinggaComboBox Nama: NumberRange
DropDownStyle: DropDownList
Item: 10, 100, 1000
Lokasi: 228, 12
Ukuran: 143, 21Label Lokasi: 13, 43
Teks: Jenis alur kerjaComboBox Nama: Jenis Alur Kerja
DropDownStyle: DropDownList
Item: StateMachineNumberGuessWorkflow, FlowchartNumberGuessWorkflow, SequentialNumberGuessWorkflow
Lokasi: 94, 40
Ukuran: 277, 21Label Nama: WorkflowVersion
Lokasi: 13, 362
Teks: Versi alur kerjaGroupBox Lokasi: 13, 67
Ukuran: 358, 287
Teks: PermainanCatatan
Saat menambahkan kontrol berikut, masukkan ke dalam GroupBox.
Menguasai Property: Nilai Label Lokasi: 7, 20
Teks: ID Instans Alur KerjaComboBox Nama: InstanceId
DropDownStyle: DropDownList
Lokasi: 121, 17
Ukuran: 227, 21Label Lokasi: 7, 47
Teks: TebakKotak Teks Nama: Tebak
Lokasi: 50, 44
Ukuran: 65, 20Kancing Nama: EnterGuess
Lokasi: 121, 42
Ukuran: 75, 23
Teks: Masukkan TebakanKancing Nama: QuitGame
Lokasi: 274, 42
Ukuran: 75, 23
Teks: KeluarKotak Teks Nama: WorkflowStatus
Lokasi: 10, 73
Multiline: Benar
ReadOnly: True
ScrollBars: Vertikal
Ukuran: 338, 208Atur properti AcceptButton formulir ke EnterGuess.
Contoh berikut mengilustrasikan formulir yang telah diisi.
Untuk menambahkan properti dan metode pembantu dari formulir
Langkah-langkah di bagian ini menambahkan properti dan metode pembantu ke kelas formulir yang mengonfigurasi UI formulir untuk mendukung menjalankan dan melanjutkan alur kerja tebakan angka.
Klik kanan WorkflowHostForm di Penjelajah Solusi dan pilih Lihat Kode.
Tambahkan pernyataan
using
(atauImports
) berikut di bagian atas file dengan pernyataanusing
(atauImports
) lainnya.Imports System.Activities Imports System.Activities.DurableInstancing Imports System.Data.SqlClient Imports System.IO Imports System.Windows.Forms
using System.Activities; using System.Activities.DurableInstancing; using System.Data.SqlClient; using System.IO; using System.Windows.Forms;
Tambahkan deklarasi anggota berikut ke kelas WorkflowHostForm.
Penting
Microsoft menyarankan agar Anda menggunakan alur autentikasi paling aman yang tersedia. Jika Anda menyambungkan ke Azure SQL, Identitas Terkelola untuk sumber daya Azure adalah metode autentikasi yang direkomendasikan.
Const connectionString = "Server=.\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI" Dim store As SqlWorkflowInstanceStore Dim workflowStarting As Boolean
const string connectionString = "Server=.\\SQLEXPRESS;Initial Catalog=WF45GettingStartedTutorial;Integrated Security=SSPI"; SqlWorkflowInstanceStore store; bool workflowStarting;
Catatan
Jika string koneksi Anda berbeda, perbarui
connectionString
untuk mereferensikan ke database Anda.Tambahkan properti
WorkflowInstanceId
ke kelasWorkflowFormHost
.Public ReadOnly Property WorkflowInstanceId() As Guid Get If InstanceId.SelectedIndex = -1 Then Return Guid.Empty Else Return New Guid(InstanceId.SelectedItem.ToString()) End If End Get End Property
public Guid WorkflowInstanceId { get { return InstanceId.SelectedIndex == -1 ? Guid.Empty : (Guid)InstanceId.SelectedItem; } }
Kotak kombo
InstanceId
menampilkan daftar id instans alur kerja yang bertahan, dan propertiWorkflowInstanceId
mengembalikan alur kerja yang dipilih saat ini.Tambahkan penangan untuk peristiwa
Load
formulir. Untuk menambahkan penangan, alihkan ke Tampilan Desain untuk formulir, klik ikon Peristiwa di bagian atas jendela Properti, dan klik dua kali Muat.Private Sub WorkflowHostForm_Load(sender As Object, e As EventArgs) Handles Me.Load End Sub
private void WorkflowHostForm_Load(object sender, EventArgs e) { }
Tambahkan kode berikut ke
WorkflowHostForm_Load
.' Initialize the store and configure it so that it can be used for ' multiple WorkflowApplication instances. store = New SqlWorkflowInstanceStore(connectionString) WorkflowApplication.CreateDefaultInstanceOwner(store, Nothing, WorkflowIdentityFilter.Any) ' Set default ComboBox selections. NumberRange.SelectedIndex = 0 WorkflowType.SelectedIndex = 0 ListPersistedWorkflows()
// Initialize the store and configure it so that it can be used for // multiple WorkflowApplication instances. store = new SqlWorkflowInstanceStore(connectionString); WorkflowApplication.CreateDefaultInstanceOwner(store, null, WorkflowIdentityFilter.Any); // Set default ComboBox selections. NumberRange.SelectedIndex = 0; WorkflowType.SelectedIndex = 0; ListPersistedWorkflows();
Saat formulir dimuat,
SqlWorkflowInstanceStore
dikonfigurasi, kotak kombo rentang dan jenis alur kerja diatur ke nilai default, dan instans alur kerja yang bertahan ditambahkan ke kotak komboInstanceId
.Tambahkan penangan
SelectedIndexChanged
untukInstanceId
. Untuk menambahkan penangan, alihkan ke Tampilan Desain untuk formulir, pilihInstanceId
kotak kombo, klik ikon Peristiwa di bagian atas jendela Properti, dan klik dua kali SelectedIndexChanged.Private Sub InstanceId_SelectedIndexChanged(sender As Object, e As EventArgs) Handles InstanceId.SelectedIndexChanged End Sub
private void InstanceId_SelectedIndexChanged(object sender, EventArgs e) { }
Tambahkan kode berikut ke
InstanceId_SelectedIndexChanged
. Setiap kali pengguna memilih alur kerja dengan menggunakan kotak kombo, penangan ini memperbarui jendela status.If InstanceId.SelectedIndex = -1 Then Return End If ' Clear the status window. WorkflowStatus.Clear() ' Get the workflow version and display it. ' If the workflow is just starting then this info will not ' be available in the persistence store so do not try and retrieve it. If Not workflowStarting Then Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) WorkflowVersion.Text = _ WorkflowVersionMap.GetIdentityDescription(instance.DefinitionIdentity) ' Unload the instance. instance.Abandon() End If
if (InstanceId.SelectedIndex == -1) { return; } // Clear the status window. WorkflowStatus.Clear(); // Get the workflow version and display it. // If the workflow is just starting then this info will not // be available in the persistence store so do not try and retrieve it. if (!workflowStarting) { WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(this.WorkflowInstanceId, store); WorkflowVersion.Text = WorkflowVersionMap.GetIdentityDescription(instance.DefinitionIdentity); // Unload the instance. instance.Abandon(); }
Tambahkan metode
ListPersistedWorkflows
berikut ke kelas formulir.Private Sub ListPersistedWorkflows() Using localCon As New SqlConnection(connectionString) Dim localCmd As String = _ "SELECT [InstanceId] FROM [System.Activities.DurableInstancing].[Instances] ORDER BY [CreationTime]" Dim cmd As SqlCommand = localCon.CreateCommand() cmd.CommandText = localCmd localCon.Open() Using reader As SqlDataReader = cmd.ExecuteReader(CommandBehavior.CloseConnection) While (reader.Read()) ' Get the InstanceId of the persisted Workflow. Dim id As Guid = Guid.Parse(reader(0).ToString()) InstanceId.Items.Add(id) End While End Using End Using End Sub
using (var localCon = new SqlConnection(connectionString)) { string localCmd = "SELECT [InstanceId] FROM [System.Activities.DurableInstancing].[Instances] ORDER BY [CreationTime]"; SqlCommand cmd = localCon.CreateCommand(); cmd.CommandText = localCmd; localCon.Open(); using (SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection)) { while (reader.Read()) { // Get the InstanceId of the persisted Workflow. Guid id = Guid.Parse(reader[0].ToString()); InstanceId.Items.Add(id); } } }
ListPersistedWorkflows
mengkueri penyimpanan instans untuk instans alur kerja yang bertahan, dan menambahkan id instans ke kotak kombocboInstanceId
.Tambahkan metode
UpdateStatus
berikut dan delegasi yang sesuai ke kelas formulir. Metode ini memperbarui jendela status pada formulir dengan status alur kerja yang sedang berjalan.Private Delegate Sub UpdateStatusDelegate(msg As String) Public Sub UpdateStatus(msg As String) ' We may be on a different thread so we need to ' make this call using BeginInvoke. If InvokeRequired Then BeginInvoke(New UpdateStatusDelegate(AddressOf UpdateStatus), msg) Else If Not msg.EndsWith(vbCrLf) Then msg = msg & vbCrLf End If WorkflowStatus.AppendText(msg) ' Ensure that the newly added status is visible. WorkflowStatus.SelectionStart = WorkflowStatus.Text.Length WorkflowStatus.ScrollToCaret() End If End Sub
private delegate void UpdateStatusDelegate(string msg); public void UpdateStatus(string msg) { // We may be on a different thread so we need to // make this call using BeginInvoke. if (InvokeRequired) { BeginInvoke(new UpdateStatusDelegate(UpdateStatus), msg); } else { if (!msg.EndsWith("\r\n")) { msg += "\r\n"; } WorkflowStatus.AppendText(msg); WorkflowStatus.SelectionStart = WorkflowStatus.Text.Length; WorkflowStatus.ScrollToCaret(); } }
Tambahkan metode
GameOver
berikut dan delegasi yang sesuai ke kelas formulir. Ketika alur kerja selesai, metode ini memperbarui UI formulir dengan menghapus id instans alur kerja yang diselesaikan dari kotak kombo InstanceId.Private Delegate Sub GameOverDelegate() Private Sub GameOver() If InvokeRequired Then BeginInvoke(New GameOverDelegate(AddressOf GameOver)) Else ' Remove this instance from the InstanceId combo box. InstanceId.Items.Remove(InstanceId.SelectedItem) InstanceId.SelectedIndex = -1 End If End Sub
private delegate void GameOverDelegate(); private void GameOver() { if (InvokeRequired) { BeginInvoke(new GameOverDelegate(GameOver)); } else { // Remove this instance from the combo box. InstanceId.Items.Remove(InstanceId.SelectedItem); InstanceId.SelectedIndex = -1; } }
Untuk mengonfigurasi penyimpanan instans, penangan siklus hidup alur kerja, dan ekstensi
Tambahkan metode
ConfigureWorkflowApplication
ke kelas formulir.Private Sub ConfigureWorkflowApplication(wfApp As WorkflowApplication) End Sub
private void ConfigureWorkflowApplication(WorkflowApplication wfApp) { }
Metode ini mengonfigurasi
WorkflowApplication
, menambahkan ekstensi yang diinginkan, dan menambahkan penangan untuk peristiwa siklus hidup alur kerja.Di
ConfigureWorkflowApplication
, tentukanSqlWorkflowInstanceStore
untukWorkflowApplication
.' Configure the persistence store. wfApp.InstanceStore = store
// Configure the persistence store. wfApp.InstanceStore = store;
Selanjutnya, buat instans
StringWriter
dan tambahkan ke kumpulanExtensions
dariWorkflowApplication
. SaatStringWriter
ditambahkan ke ekstensi, ia menangkap semua output aktivitasWriteLine
. Saat alur kerja menjadi tidak aktif, outputWriteLine
dapat diekstraksi dariStringWriter
dan ditampilkan pada formulir.' Add a StringWriter to the extensions. This captures the output ' from the WriteLine activities so we can display it in the form. Dim sw As New StringWriter() wfApp.Extensions.Add(sw)
// Add a StringWriter to the extensions. This captures the output // from the WriteLine activities so we can display it in the form. var sw = new StringWriter(); wfApp.Extensions.Add(sw);
Tambahkan penangan berikut untuk peristiwa
Completed
. Ketika alur kerja berhasil diselesaikan, jumlah giliran yang diambil untuk menebak nomor ditampilkan ke jendela status. Jika alur kerja berakhir, informasi pengecualian yang menyebabkan penghentian akan ditampilkan. Di akhir penangan, metodeGameOver
dipanggil, yang menghapus alur kerja yang sudah selesai dari daftar alur kerja.wfApp.Completed = _ Sub(e As WorkflowApplicationCompletedEventArgs) If e.CompletionState = ActivityInstanceState.Faulted Then UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}{vbCrLf}{e.TerminationException.Message}") ElseIf e.CompletionState = ActivityInstanceState.Canceled Then UpdateStatus("Workflow Canceled.") Else Dim turns As Integer = Convert.ToInt32(e.Outputs("Turns")) UpdateStatus($"Congratulations, you guessed the number in {turns} turns.") End If GameOver() End Sub
wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) { if (e.CompletionState == ActivityInstanceState.Faulted) { UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}\r\n{e.TerminationException.Message}"); } else if (e.CompletionState == ActivityInstanceState.Canceled) { UpdateStatus("Workflow Canceled."); } else { int turns = Convert.ToInt32(e.Outputs["Turns"]); UpdateStatus($"Congratulations, you guessed the number in {turns} turns."); } GameOver(); };
Tambahkan penangan
Aborted
danOnUnhandledException
berikut. MetodeGameOver
tidak dipanggil dari penanganAborted
karena ketika instans alur kerja dibatalkan, metode tidak dihentikan, dan dimungkinkan untuk melanjutkan instans di lain waktu.wfApp.Aborted = _ Sub(e As WorkflowApplicationAbortedEventArgs) UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}{vbCrLf}{e.Reason.Message}") End Sub wfApp.OnUnhandledException = _ Function(e As WorkflowApplicationUnhandledExceptionEventArgs) UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}{vbCrLf}{e.UnhandledException.Message}") GameOver() Return UnhandledExceptionAction.Terminate End Function
wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}\r\n{e.Reason.Message}"); }; wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}\r\n{e.UnhandledException.Message}"); GameOver(); return UnhandledExceptionAction.Terminate; };
Tambahkan penangan
PersistableIdle
berikut. Penangan ini mengambil ekstensiStringWriter
yang telah ditambahkan, mengekstrak output dari aktivitasWriteLine
, dan menampilkannya di jendela status.wfApp.PersistableIdle = _ Function(e As WorkflowApplicationIdleEventArgs) ' Send the current WriteLine outputs to the status window. Dim writers = e.GetInstanceExtensions(Of StringWriter)() For Each writer In writers UpdateStatus(writer.ToString()) Next Return PersistableIdleAction.Unload End Function
wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { // Send the current WriteLine outputs to the status window. var writers = e.GetInstanceExtensions<StringWriter>(); foreach (var writer in writers) { UpdateStatus(writer.ToString()); } return PersistableIdleAction.Unload; };
Enumerasi PersistableIdleAction memiliki tiga nilai: None, Persist, dan Unload. Persist menyebabkan alur kerja bertahan tetapi tidak menyebabkan alur kerja dibongkar. Unload menyebabkan alur kerja bertahan dan dibongkar.
Contoh berikut adalah metode
ConfigureWorkflowApplication
yang telah selesai.Private Sub ConfigureWorkflowApplication(wfApp As WorkflowApplication) ' Configure the persistence store. wfApp.InstanceStore = store ' Add a StringWriter to the extensions. This captures the output ' from the WriteLine activities so we can display it in the form. Dim sw As New StringWriter() wfApp.Extensions.Add(sw) wfApp.Completed = _ Sub(e As WorkflowApplicationCompletedEventArgs) If e.CompletionState = ActivityInstanceState.Faulted Then UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}{vbCrLf}{e.TerminationException.Message}") ElseIf e.CompletionState = ActivityInstanceState.Canceled Then UpdateStatus("Workflow Canceled.") Else Dim turns As Integer = Convert.ToInt32(e.Outputs("Turns")) UpdateStatus($"Congratulations, you guessed the number in {turns} turns.") End If GameOver() End Sub wfApp.Aborted = _ Sub(e As WorkflowApplicationAbortedEventArgs) UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}{vbCrLf}{e.Reason.Message}") End Sub wfApp.OnUnhandledException = _ Function(e As WorkflowApplicationUnhandledExceptionEventArgs) UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}{vbCrLf}{e.UnhandledException.Message}") GameOver() Return UnhandledExceptionAction.Terminate End Function wfApp.PersistableIdle = _ Function(e As WorkflowApplicationIdleEventArgs) ' Send the current WriteLine outputs to the status window. Dim writers = e.GetInstanceExtensions(Of StringWriter)() For Each writer In writers UpdateStatus(writer.ToString()) Next Return PersistableIdleAction.Unload End Function End Sub
private void ConfigureWorkflowApplication(WorkflowApplication wfApp) { // Configure the persistence store. wfApp.InstanceStore = store; // Add a StringWriter to the extensions. This captures the output // from the WriteLine activities so we can display it in the form. var sw = new StringWriter(); wfApp.Extensions.Add(sw); wfApp.Completed = delegate(WorkflowApplicationCompletedEventArgs e) { if (e.CompletionState == ActivityInstanceState.Faulted) { UpdateStatus($"Workflow Terminated. Exception: {e.TerminationException.GetType().FullName}\r\n{e.TerminationException.Message}"); } else if (e.CompletionState == ActivityInstanceState.Canceled) { UpdateStatus("Workflow Canceled."); } else { int turns = Convert.ToInt32(e.Outputs["Turns"]); UpdateStatus($"Congratulations, you guessed the number in {turns} turns."); } GameOver(); }; wfApp.Aborted = delegate(WorkflowApplicationAbortedEventArgs e) { UpdateStatus($"Workflow Aborted. Exception: {e.Reason.GetType().FullName}\r\n{e.Reason.Message}"); }; wfApp.OnUnhandledException = delegate(WorkflowApplicationUnhandledExceptionEventArgs e) { UpdateStatus($"Unhandled Exception: {e.UnhandledException.GetType().FullName}\r\n{e.UnhandledException.Message}"); GameOver(); return UnhandledExceptionAction.Terminate; }; wfApp.PersistableIdle = delegate(WorkflowApplicationIdleEventArgs e) { // Send the current WriteLine outputs to the status window. var writers = e.GetInstanceExtensions<StringWriter>(); foreach (var writer in writers) { UpdateStatus(writer.ToString()); } return PersistableIdleAction.Unload; }; }
Untuk mengaktifkan memulai dan melanjutkan beberapa jenis alur kerja
Untuk melanjutkan instans alur kerja, host harus memberikan definisi alur kerja. Dalam tutorial ini ada tiga jenis alur kerja, dan langkah-langkah tutorial selanjutnya akan memperkenalkan beberapa versi jenis ini. WorkflowIdentity
menyediakan cara bagi aplikasi host untuk mengaitkan informasi pengidentifikasi dengan instans alur kerja yang bertahan. Langkah-langkah di bagian ini menunjukkan cara membuat kelas utilitas guna membantu memetakan identitas alur kerja dari instans alur kerja yang bertahan ke definisi alur kerja yang sesuai. Untuk informasi selengkapnya tentang WorkflowIdentity
dan pembuatan versi, lihat Menggunakan WorkflowIdentity dan Versioning.
Klik kanan NumberGuessWorkflowHost di Penjelajah Solusi dan pilih Tambahkan, Kelas. Ketik
WorkflowVersionMap
ke dalam kotak Nama, lalu klik Tambahkan.Tambahkan pernyataan
using
atauImports
berikut di bagian atas file dengan pernyataanusing
atauImports
lainnya.Imports System.Activities Imports NumberGuessWorkflowActivities
using System.Activities; using NumberGuessWorkflowActivities;
Ganti deklarasi kelas
WorkflowVersionMap
dengan deklarasi berikut.Public Module WorkflowVersionMap Dim map As Dictionary(Of WorkflowIdentity, Activity) ' Current version identities. Public StateMachineNumberGuessIdentity As WorkflowIdentity Public FlowchartNumberGuessIdentity As WorkflowIdentity Public SequentialNumberGuessIdentity As WorkflowIdentity Sub New() map = New Dictionary(Of WorkflowIdentity, Activity) ' Add the current workflow version identities. StateMachineNumberGuessIdentity = New WorkflowIdentity With { .Name = "StateMachineNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } FlowchartNumberGuessIdentity = New WorkflowIdentity With { .Name = "FlowchartNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } SequentialNumberGuessIdentity = New WorkflowIdentity With { .Name = "SequentialNumberGuessWorkflow", .Version = New Version(1, 0, 0, 0) } map.Add(StateMachineNumberGuessIdentity, New StateMachineNumberGuessWorkflow()) map.Add(FlowchartNumberGuessIdentity, New FlowchartNumberGuessWorkflow()) map.Add(SequentialNumberGuessIdentity, New SequentialNumberGuessWorkflow()) End Sub Public Function GetWorkflowDefinition(identity As WorkflowIdentity) As Activity Return map(identity) End Function Public Function GetIdentityDescription(identity As WorkflowIdentity) As String Return identity.ToString() End Function End Module
public static class WorkflowVersionMap { static Dictionary<WorkflowIdentity, Activity> map; // Current version identities. static public WorkflowIdentity StateMachineNumberGuessIdentity; static public WorkflowIdentity FlowchartNumberGuessIdentity; static public WorkflowIdentity SequentialNumberGuessIdentity; static WorkflowVersionMap() { map = new Dictionary<WorkflowIdentity, Activity>(); // Add the current workflow version identities. StateMachineNumberGuessIdentity = new WorkflowIdentity { Name = "StateMachineNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; FlowchartNumberGuessIdentity = new WorkflowIdentity { Name = "FlowchartNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; SequentialNumberGuessIdentity = new WorkflowIdentity { Name = "SequentialNumberGuessWorkflow", Version = new Version(1, 0, 0, 0) }; map.Add(StateMachineNumberGuessIdentity, new StateMachineNumberGuessWorkflow()); map.Add(FlowchartNumberGuessIdentity, new FlowchartNumberGuessWorkflow()); map.Add(SequentialNumberGuessIdentity, new SequentialNumberGuessWorkflow()); } public static Activity GetWorkflowDefinition(WorkflowIdentity identity) { return map[identity]; } public static string GetIdentityDescription(WorkflowIdentity identity) { return identity.ToString(); } }
WorkflowVersionMap
berisi tiga identitas alur kerja yang dipetakan ke tiga definisi alur kerja dari tutorial ini dan digunakan di bagian berikut saat alur kerja dimulai dan dilanjutkan.
Untuk memulai alur kerja baru
Tambahkan penangan
Click
untukNewGame
. Untuk menambahkan penangan, alihkan ke Tampilan Desain untuk formulir, dan klik dua kaliNewGame
. PenanganNewGame_Click
ditambahkan dan tampilan beralih ke tampilan kode untuk formulir. Setiap kali pengguna mengeklik tombol ini, alur kerja baru dimulai.Private Sub NewGame_Click(sender As Object, e As EventArgs) Handles NewGame.Click End Sub
private void NewGame_Click(object sender, EventArgs e) { }
Tambahkan kode berikut ke penangan klik. Kode ini membuat kamus argumen input untuk alur kerja, dikunci dengan nama argumen. Kamus ini memiliki satu entri yang berisi rentang angka yang dihasilkan secara acak yang diambil dari kotak kombo rentang.
Dim inputs As New Dictionary(Of String, Object)() inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem))
var inputs = new Dictionary<string, object>(); inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem));
Selanjutnya, tambahkan kode berikut yang memulai alur kerja.
WorkflowIdentity
dan definisi alur kerja yang sesuai dengan jenis alur kerja yang dipilih diambil menggunakan kelas pembantuWorkflowVersionMap
. Selanjutnya, instansWorkflowApplication
baru dibuat menggunakan definisi alur kerja,WorkflowIdentity
, dan kamus argumen input.Dim identity As WorkflowIdentity = Nothing Select Case WorkflowType.SelectedItem.ToString() Case "SequentialNumberGuessWorkflow" identity = WorkflowVersionMap.SequentialNumberGuessIdentity Case "StateMachineNumberGuessWorkflow" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity Case "FlowchartNumberGuessWorkflow" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity End Select Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(identity) Dim wfApp = New WorkflowApplication(wf, inputs, identity)
WorkflowIdentity identity = null; switch (WorkflowType.SelectedItem.ToString()) { case "SequentialNumberGuessWorkflow": identity = WorkflowVersionMap.SequentialNumberGuessIdentity; break; case "StateMachineNumberGuessWorkflow": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity; break; case "FlowchartNumberGuessWorkflow": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity; break; }; Activity wf = WorkflowVersionMap.GetWorkflowDefinition(identity); WorkflowApplication wfApp = new WorkflowApplication(wf, inputs, identity);
Selanjutnya, tambahkan kode berikut yang menambahkan alur kerja ke daftar alur kerja dan menampilkan informasi versi alur kerja pada formulir.
' Add the workflow to the list and display the version information. workflowStarting = True InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id) WorkflowVersion.Text = identity.ToString() workflowStarting = False
// Add the workflow to the list and display the version information. workflowStarting = true; InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id); WorkflowVersion.Text = identity.ToString(); workflowStarting = false;
Panggil
ConfigureWorkflowApplication
untuk mengonfigurasi penyimpanan instans, ekstensi, dan penangan siklus hidup alur kerja untuk instansWorkflowApplication
ini.' Configure the instance store, extensions, and ' workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp)
// Configure the instance store, extensions, and // workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp);
Terakhir, hubungi
Run
.' Start the workflow. wfApp.Run()
// Start the workflow. wfApp.Run();
Contoh berikut adalah penangan
NewGame_Click
yang telah selesai.Private Sub NewGame_Click(sender As Object, e As EventArgs) Handles NewGame.Click ' Start a new workflow. Dim inputs As New Dictionary(Of String, Object)() inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem)) Dim identity As WorkflowIdentity = Nothing Select Case WorkflowType.SelectedItem.ToString() Case "SequentialNumberGuessWorkflow" identity = WorkflowVersionMap.SequentialNumberGuessIdentity Case "StateMachineNumberGuessWorkflow" identity = WorkflowVersionMap.StateMachineNumberGuessIdentity Case "FlowchartNumberGuessWorkflow" identity = WorkflowVersionMap.FlowchartNumberGuessIdentity End Select Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(identity) Dim wfApp = New WorkflowApplication(wf, inputs, identity) ' Add the workflow to the list and display the version information. workflowStarting = True InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id) WorkflowVersion.Text = identity.ToString() workflowStarting = False ' Configure the instance store, extensions, and ' workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp) ' Start the workflow. wfApp.Run() End Sub
private void NewGame_Click(object sender, EventArgs e) { var inputs = new Dictionary<string, object>(); inputs.Add("MaxNumber", Convert.ToInt32(NumberRange.SelectedItem)); WorkflowIdentity identity = null; switch (WorkflowType.SelectedItem.ToString()) { case "SequentialNumberGuessWorkflow": identity = WorkflowVersionMap.SequentialNumberGuessIdentity; break; case "StateMachineNumberGuessWorkflow": identity = WorkflowVersionMap.StateMachineNumberGuessIdentity; break; case "FlowchartNumberGuessWorkflow": identity = WorkflowVersionMap.FlowchartNumberGuessIdentity; break; }; Activity wf = WorkflowVersionMap.GetWorkflowDefinition(identity); var wfApp = new WorkflowApplication(wf, inputs, identity); // Add the workflow to the list and display the version information. workflowStarting = true; InstanceId.SelectedIndex = InstanceId.Items.Add(wfApp.Id); WorkflowVersion.Text = identity.ToString(); workflowStarting = false; // Configure the instance store, extensions, and // workflow lifecycle handlers. ConfigureWorkflowApplication(wfApp); // Start the workflow. wfApp.Run(); }
Untuk melanjutkan alur kerja
Tambahkan penangan
Click
untukEnterGuess
. Untuk menambahkan penangan, alihkan ke Tampilan Desain untuk formulir, dan klik dua kaliEnterGuess
. Setiap kali pengguna mengeklik tombol ini, alur kerja dilanjutkan.Private Sub EnterGuess_Click(sender As Object, e As EventArgs) Handles EnterGuess.Click End Sub
private void EnterGuess_Click(object sender, EventArgs e) { }
Tambahkan kode berikut untuk memastikan bahwa alur kerja dipilih dalam daftar alur kerja, dan tebakan pengguna valid.
If WorkflowInstanceId = Guid.Empty Then MessageBox.Show("Please select a workflow.") Return End If Dim userGuess As Integer If Not Int32.TryParse(Guess.Text, userGuess) Then MessageBox.Show("Please enter an integer.") Guess.SelectAll() Guess.Focus() Return End If
if (WorkflowInstanceId == Guid.Empty) { MessageBox.Show("Please select a workflow."); return; } int guess; if (!Int32.TryParse(Guess.Text, out guess)) { MessageBox.Show("Please enter an integer."); Guess.SelectAll(); Guess.Focus(); return; }
Selanjutnya, ambil
WorkflowApplicationInstance
dari instans alur kerja yang bertahan.WorkflowApplicationInstance
mewakili instans alur kerja yang bertahan yang belum dikaitkan dengan definisi alur kerja.DefinitionIdentity
dariWorkflowApplicationInstance
berisiWorkflowIdentity
dari instans alur kerja yang bertahan. Dalam tutorial ini, kelas utilitasWorkflowVersionMap
digunakan untuk memetakanWorkflowIdentity
ke definisi alur kerja yang benar. Setelah definisi alur kerja diambil,WorkflowApplication
dibuat, menggunakan definisi alur kerja yang benar.Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) ' Use the persisted WorkflowIdentity to retrieve the correct workflow ' definition from the dictionary. Dim wf As Activity = _ WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity) ' Associate the WorkflowApplication with the correct definition Dim wfApp As New WorkflowApplication(wf, instance.DefinitionIdentity)
WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(WorkflowInstanceId, store); // Use the persisted WorkflowIdentity to retrieve the correct workflow // definition from the dictionary. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity); // Associate the WorkflowApplication with the correct definition var wfApp = new WorkflowApplication(wf, instance.DefinitionIdentity);
Setelah
WorkflowApplication
dibuat, konfigurasikan penyimpanan instans, penangan siklus hidup alur kerja, dan ekstensi dengan memanggilConfigureWorkflowApplication
. Langkah-langkah ini harus dilakukan setiap kaliWorkflowApplication
baru dibuat, dan harus dilakukan sebelum instans alur kerja dimuat ke dalamWorkflowApplication
. Setelah dimuat, alur kerja dilanjutkan dengan tebakan pengguna.' Configure the extensions and lifecycle handlers. ' Do this before the instance is loaded. Once the instance is ' loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp) ' Load the workflow. wfApp.Load(instance) ' Resume the workflow. wfApp.ResumeBookmark("EnterGuess", userGuess)
// Configure the extensions and lifecycle handlers. // Do this before the instance is loaded. Once the instance is // loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp); // Load the workflow. wfApp.Load(instance); // Resume the workflow. wfApp.ResumeBookmark("EnterGuess", guess);
Terakhir, kosongkan kotak teks tebakan dan siapkan formulir untuk menerima tebakan lain.
' Clear the Guess textbox. Guess.Clear() Guess.Focus()
// Clear the Guess textbox. Guess.Clear(); Guess.Focus();
Contoh berikut adalah penangan
EnterGuess_Click
yang telah selesai.Private Sub EnterGuess_Click(sender As Object, e As EventArgs) Handles EnterGuess.Click If WorkflowInstanceId = Guid.Empty Then MessageBox.Show("Please select a workflow.") Return End If Dim userGuess As Integer If Not Int32.TryParse(Guess.Text, userGuess) Then MessageBox.Show("Please enter an integer.") Guess.SelectAll() Guess.Focus() Return End If Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) ' Use the persisted WorkflowIdentity to retrieve the correct workflow ' definition from the dictionary. Dim wf As Activity = _ WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity) ' Associate the WorkflowApplication with the correct definition Dim wfApp As New WorkflowApplication(wf, instance.DefinitionIdentity) ' Configure the extensions and lifecycle handlers. ' Do this before the instance is loaded. Once the instance is ' loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp) ' Load the workflow. wfApp.Load(instance) ' Resume the workflow. wfApp.ResumeBookmark("EnterGuess", userGuess) ' Clear the Guess textbox. Guess.Clear() Guess.Focus() End Sub
private void EnterGuess_Click(object sender, EventArgs e) { if (WorkflowInstanceId == Guid.Empty) { MessageBox.Show("Please select a workflow."); return; } int guess; if (!Int32.TryParse(Guess.Text, out guess)) { MessageBox.Show("Please enter an integer."); Guess.SelectAll(); Guess.Focus(); return; } WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(WorkflowInstanceId, store); // Use the persisted WorkflowIdentity to retrieve the correct workflow // definition from the dictionary. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity); // Associate the WorkflowApplication with the correct definition var wfApp = new WorkflowApplication(wf, instance.DefinitionIdentity); // Configure the extensions and lifecycle handlers. // Do this before the instance is loaded. Once the instance is // loaded it is too late to add extensions. ConfigureWorkflowApplication(wfApp); // Load the workflow. wfApp.Load(instance); // Resume the workflow. wfApp.ResumeBookmark("EnterGuess", guess); // Clear the Guess textbox. Guess.Clear(); Guess.Focus(); }
Untuk menghentikan alur kerja
Tambahkan penangan
Click
untukQuitGame
. Untuk menambahkan penangan, alihkan ke Tampilan Desain untuk formulir, dan klik dua kaliQuitGame
. Setiap kali pengguna mengeklik tombol ini, alur kerja yang dipilih saat ini dihentikan.Private Sub QuitGame_Click(sender As Object, e As EventArgs) Handles QuitGame.Click End Sub
private void QuitGame_Click(object sender, EventArgs e) { }
Tambahkan kode berikut ke penangan
QuitGame_Click
. Kode ini pertama-tama memeriksa untuk memastikan bahwa alur kerja dipilih dalam daftar alur kerja. Kemudian memuat instans yang bertahan ke dalamWorkflowApplicationInstance
, menggunakanDefinitionIdentity
untuk menentukan definisi alur kerja yang benar, dan kemudian menginisialisasiWorkflowApplication
. Selanjutnya ekstensi dan penangan siklus hidup alur kerja dikonfigurasi dengan panggilan keConfigureWorkflowApplication
. SetelahWorkflowApplication
dikonfigurasi, kode dimuat, dan kemudianTerminate
dipanggil.If WorkflowInstanceId = Guid.Empty Then MessageBox.Show("Please select a workflow.") Return End If Dim instance As WorkflowApplicationInstance = _ WorkflowApplication.GetInstance(WorkflowInstanceId, store) ' Use the persisted WorkflowIdentity to retrieve the correct workflow ' definition from the dictionary. Dim wf As Activity = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity) ' Associate the WorkflowApplication with the correct definition. Dim wfApp As New WorkflowApplication(wf, instance.DefinitionIdentity) ' Configure the extensions and lifecycle handlers. ConfigureWorkflowApplication(wfApp) ' Load the workflow. wfApp.Load(instance) ' Terminate the workflow. wfApp.Terminate("User resigns.")
if (WorkflowInstanceId == Guid.Empty) { MessageBox.Show("Please select a workflow."); return; } WorkflowApplicationInstance instance = WorkflowApplication.GetInstance(WorkflowInstanceId, store); // Use the persisted WorkflowIdentity to retrieve the correct workflow // definition from the dictionary. Activity wf = WorkflowVersionMap.GetWorkflowDefinition(instance.DefinitionIdentity); // Associate the WorkflowApplication with the correct definition var wfApp = new WorkflowApplication(wf, instance.DefinitionIdentity); // Configure the extensions and lifecycle handlers ConfigureWorkflowApplication(wfApp); // Load the workflow. wfApp.Load(instance); // Terminate the workflow. wfApp.Terminate("User resigns.");
Untuk membangun dan menjalankan aplikasi
Klik dua kali Program.cs (atau Module1.vb) di Penjelajah Solusi untuk menampilkan kode.
Tambahkan pernyataan
using
(atauImports
) berikut di bagian atas file dengan pernyataanusing
(atauImports
) lainnya.Imports System.Windows.Forms
using System.Windows.Forms;
Hapus atau komentari kode hosting alur kerja yang ada dari Cara: Jalankan Alur Kerja, dan ganti dengan kode berikut.
Sub Main() Application.EnableVisualStyles() Application.Run(New WorkflowHostForm()) End Sub
static void Main(string[] args) { Application.EnableVisualStyles(); Application.Run(new WorkflowHostForm()); }
Klik kanan NumberGuessWorkflowHost di Penjelajah Solusi dan pilih Properti. Di tab Aplikasi, tentukan Aplikasi Windows untuk Jenis output. Langkah ini bersifat opsional, tetapi jika tidak diikuti, jendela konsol ditampilkan di samping formulir.
Tekan Ctrl+Shift+B untuk membuat aplikasi.
Pastikan NumberGuessWorkflowHost diatur sebagai aplikasi startup, dan tekan Ctrl+F5 untuk memulai aplikasi.
Pilih rentang permainan tebak-tebakan dan jenis alur kerja yang akan dimulai, lalu klik Game Baru. Masukkan tebakan di kotak Tebakan dan klik Buka untuk mengirimkan tebakan Anda. Perhatikan bahwa output dari aktivitas
WriteLine
ditampilkan pada formulir.Mulai beberapa alur kerja menggunakan jenis alur kerja dan rentang angka yang berbeda, masukkan beberapa tebakan, dan beralih di antara alur kerja dengan memilih dari daftar ID Instans Alur Kerja.
Perhatikan bahwa saat Anda beralih ke alur kerja baru, tebakan dan progres alur kerja sebelumnya tidak ditampilkan di jendela status. Alasan status tidak tersedia karena tidak diambil dan disimpan di mana saja. Pada langkah tutorial berikutnya, Cara: Membuat Peserta Pelacakan Kustom, Anda membuat peserta pelacakan kustom yang menyimpan informasi ini.