Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
AsyncCodeActivity menyediakan penulis aktivitas kelas dasar untuk digunakan yang memungkinkan aktivitas turunan untuk menerapkan logika eksekusi asinkron. Ini berguna untuk aktivitas kustom yang harus melakukan pekerjaan asinkron tanpa menahan benang penjadwal alur kerja dan memblokir aktivitas apa pun yang bisa berjalan paralel. Topik ini memberikan gambaran umum tentang cara membuat aktivitas asinkron kustom menggunakan AsyncCodeActivity.
Menggunakan AsyncCodeActivity
System.Activities menyediakan penulis aktivitas kustom dengan kelas dasar yang berbeda untuk persyaratan penulisan aktivitas yang berbeda. Masing-masing membawa semantik tertentu dan menyediakan penulis alur kerja (dan runtime aktivitas) kontrak yang sesuai. Aktivitas yang berbasis AsyncCodeActivity adalah aktivitas yang melakukan pekerjaan secara asinkron relatif terhadap utas penjadwal dan logika eksekusinya dinyatakan dalam kode terkelola. Sebagai akibat dari pelaksanaan yang asinkron, AsyncCodeActivity dapat menyebabkan titik tidak aktif selama eksekusi. Karena sifat volatil dari pekerjaan asinkron, AsyncCodeActivity selalu menciptakan blok tanpa persisten selama durasi pelaksanaan aktivitas. Ini mencegah runtime alur kerja dari mempertahankan instans alur kerja di tengah proses pekerjaan asinkron, dan juga mencegah instans alur kerja untuk terlepas saat kode asinkron sedang dijalankan.
Metode AsyncCodeActivity
Aktivitas yang berasal dari AsyncCodeActivity dapat membuat logika eksekusi asinkron dengan mengesampingkan BeginExecute metode dan EndExecute dengan kode kustom. Ketika dipanggil oleh runtime, metode ini diteruskan AsyncCodeActivityContext.
AsyncCodeActivityContext memungkinkan pembuat aktivitas untuk memberikan status bersama di seluruh BeginExecute/ EndExecute properti konteks UserState . Dalam contoh berikut, GenerateRandom aktivitas menghasilkan angka acak secara asinkron.
public sealed class GenerateRandom : AsyncCodeActivity<int>
{
static Random r = new Random();
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
// Create a delegate that references the method that implements
// the asynchronous work. Assign the delegate to the UserState,
// invoke the delegate, and return the resulting IAsyncResult.
Func<int> GetRandomDelegate = new Func<int>(GetRandom);
context.UserState = GetRandomDelegate;
return GetRandomDelegate.BeginInvoke(callback, state);
}
protected override int EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
// Get the delegate from the UserState and call EndInvoke
Func<int> GetRandomDelegate = (Func<int>)context.UserState;
return (int)GetRandomDelegate.EndInvoke(result);
}
int GetRandom()
{
// This activity simulates taking a few moments
// to generate the random number. This code runs
// asynchronously with respect to the workflow thread.
Thread.Sleep(5000);
return r.Next(1, 101);
}
}
Contoh aktivitas sebelumnya berasal dari AsyncCodeActivity<TResult>, dan memiliki OutArgument<int> yang lebih tinggi bernama Result. Nilai yang dikembalikan oleh metode GetRandom diekstrak dan dikembalikan oleh penimpaan EndExecute, dan nilai ini ditetapkan sebagai nilai Result. Aktivitas asinkron yang tidak mengembalikan hasil harus berasal dari AsyncCodeActivity. Dalam contoh berikut, aktivitas DisplayRandom didefinisikan yang diturunkan dari AsyncCodeActivity. Aktivitas ini seperti GetRandom aktivitas tetapi alih-alih mengembalikan hasil, aktivitas ini menampilkan pesan ke konsol.
public sealed class DisplayRandom : AsyncCodeActivity
{
static Random r = new Random();
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
// Create a delegate that references the method that implements
// the asynchronous work. Assign the delegate to the UserState,
// invoke the delegate, and return the resulting IAsyncResult.
Action GetRandomDelegate = new Action(GetRandom);
context.UserState = GetRandomDelegate;
return GetRandomDelegate.BeginInvoke(callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
// Get the delegate from the UserState and call EndInvoke
Action GetRandomDelegate = (Action)context.UserState;
GetRandomDelegate.EndInvoke(result);
}
void GetRandom()
{
// This activity simulates taking a few moments
// to generate the random number. This code runs
// asynchronously with respect to the workflow thread.
Thread.Sleep(5000);
Console.WriteLine($"Random Number: {r.Next(1, 101)}");
}
}
Perhatikan bahwa karena tidak ada nilai pengembalian, DisplayRandom menggunakan Action alih-alih Func<T,TResult> untuk memanggil delegasinya, dan delegasi tidak mengembalikan nilai.
AsyncCodeActivity juga memberikan Cancel penimpaan. Sementara BeginExecute dan EndExecute merupakan penimpaan wajib, Cancel bersifat opsional, dan dapat ditimpa sehingga aktivitas dapat membersihkan status asinkron yang belum selesai ketika sedang dibatalkan atau dihentikan. Jika pembersihan dimungkinkan dan AsyncCodeActivity.ExecutingActivityInstance.IsCancellationRequested adalah true, aktivitas harus memanggil MarkCanceled. Setiap pengecualian yang dilemparkan dari metode ini berakibat fatal bagi instans alur kerja.
protected override void Cancel(AsyncCodeActivityContext context)
{
// Implement any cleanup as a result of the asynchronous work
// being canceled, and then call MarkCanceled.
if (context.IsCancellationRequested)
{
context.MarkCanceled();
}
}
Memanggil Metode Asinkron pada Kelas
Banyak kelas dalam .NET Framework menyediakan fungsionalitas asinkron, dan fungsionalitas ini dapat dipanggil secara asinkron dengan menggunakan AsyncCodeActivity aktivitas berbasis. Dalam contoh berikut, sebuah aktivitas dibuat yang membuat file secara asinkron dengan menggunakan kelas FileStream.
public sealed class FileWriter : AsyncCodeActivity
{
public FileWriter()
: base()
{
}
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
string tempFileName = Path.GetTempFileName();
Console.WriteLine("Writing to file: " + tempFileName);
FileStream file = File.Open(tempFileName, FileMode.Create);
context.UserState = file;
byte[] bytes = UnicodeEncoding.Unicode.GetBytes("123456789");
return file.BeginWrite(bytes, 0, bytes.Length, callback, state);
}
protected override void EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
FileStream file = (FileStream)context.UserState;
try
{
file.EndWrite(result);
file.Flush();
}
finally
{
file.Close();
}
}
}
Status Berbagi Antara Metode BeginExecute dan EndExecute
Dalam contoh sebelumnya, FileStream objek yang dibuat di BeginExecute diakses di EndExecute. Ini dimungkinkan file karena variabel diteruskan dalam AsyncCodeActivityContext.UserState properti di BeginExecute. Ini adalah metode yang benar untuk berbagi status antara BeginExecute dan EndExecute. Salah menggunakan variabel anggota di kelas turunan (FileWriter dalam hal ini) untuk berbagi status antara BeginExecute dan EndExecute karena objek aktivitas dapat direferensikan oleh beberapa instans aktivitas. Mencoba menggunakan variabel anggota untuk berbagi status dapat mengakibatkan nilai dari satu ActivityInstance nilai yang menimpa atau mengkonsumsi nilai dari yang lain ActivityInstance.
Mengakses Nilai Argumen
Lingkungan dari AsyncCodeActivity terdiri dari argumen yang ditentukan pada aktivitas. Argumen ini dapat diakses dari BeginExecute/EndExecute penimpaan AsyncCodeActivityContext menggunakan parameter . Argumen tidak dapat diakses dalam delegasi, tetapi nilai argumen atau data lain yang diinginkan dapat diteruskan ke delegasi menggunakan parameternya. Dalam contoh berikut, aktivitas pembangkit angka acak didefinisikan yang mendapatkan batas atas inklusif dari argumennya Max . Nilai argumen diteruskan ke kode asinkron saat delegasi dipanggil.
public sealed class GenerateRandomMax : AsyncCodeActivity<int>
{
public InArgument<int> Max { get; set; }
static Random r = new Random();
protected override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
// Create a delegate that references the method that implements
// the asynchronous work. Assign the delegate to the UserState,
// invoke the delegate, and return the resulting IAsyncResult.
Func<int, int> GetRandomDelegate = new Func<int, int>(GetRandom);
context.UserState = GetRandomDelegate;
return GetRandomDelegate.BeginInvoke(Max.Get(context), callback, state);
}
protected override int EndExecute(AsyncCodeActivityContext context, IAsyncResult result)
{
// Get the delegate from the UserState and call EndInvoke
Func<int, int> GetRandomDelegate = (Func<int, int>)context.UserState;
return (int)GetRandomDelegate.EndInvoke(result);
}
int GetRandom(int max)
{
// This activity simulates taking a few moments
// to generate the random number. This code runs
// asynchronously with respect to the workflow thread.
Thread.Sleep(5000);
return r.Next(1, max + 1);
}
}
Tindakan Penjadwalan atau Aktivitas Anak Menggunakan AsyncCodeActivity
AsyncCodeActivity aktivitas kustom turunan menyediakan metode untuk melakukan pekerjaan secara asinkron sehubungan dengan alur kerja, tetapi tidak memberikan kemampuan untuk menjadwalkan aktivitas atau tindakan anak. Namun, perilaku asinkron dapat dimasukkan dengan penjadwalan aktivitas anak melalui komposisi. Aktivitas asinkron dapat dibuat dan kemudian dikombinasikan dengan aktivitas turunan dari Activity atau NativeActivity untuk menyediakan perilaku asinkron serta penjadwalan aktivitas atau tindakan anak. Misalnya, aktivitas dapat dibuat yang berasal dari Activity, dan memiliki implementasinya yang Sequence berisi aktivitas asinkron serta aktivitas lain yang mengimplementasikan logika aktivitas. Untuk contoh selengkapnya tentang menyusun aktivitas menggunakan Activity dan NativeActivity, lihat Cara: Membuat Aktivitas dan Opsi Penulisan Aktivitas.