Bagikan melalui


Menggunakan Delegasi Aktivitas

Delegasi aktivitas memungkinkan pembuat aktivitas mengekspos panggilan balik dengan tanda tangan tertentu. Selama proses ini, pengguna aktivitas dapat menyediakan penangan berbasis aktivitas. Dua jenis delegasi aktivitas tersedia: ActivityAction<T> digunakan untuk menentukan delegasi aktivitas yang tidak memiliki nilai pengembalian, dan ActivityFunc<TResult> digunakan untuk menentukan delegasi aktivitas yang memang memiliki nilai pengembalian.

Delegasi aktivitas berguna dalam skenario ketika aktivitas turunan harus dibatasi untuk memiliki tanda tangan tertentu. Misalnya, aktivitas While dapat berisi semua jenis aktivitas turunan tanpa batasan, tetapi isi aktivitas ForEach<T> adalah ActivityAction<T>, dan aktivitas turunan yang pada akhirnya dijalankan oleh ForEach<T> harus memiliki InArgument<T> yang sama dari anggota koleksi yang disebutkan oleh ForEach<T>.

Menggunakan ActivityAction

Beberapa aktivitas .NET Framework 4.6.1 menggunakan tindakan aktivitas, seperti aktivitas Catch dan aktivitas ForEach<T>. Dalam setiap kasus, tindakan aktivitas mewakili lokasi tempat pembuat alur kerja menentukan aktivitas untuk memberikan perilaku yang diinginkan saat menyusun alur kerja menggunakan salah satu aktivitas ini. Dalam contoh berikut, aktivitas ForEach<T> digunakan untuk menampilkan teks ke jendela konsol. Isi ForEach<T> ditentukan dengan menggunakan ActivityAction<T> yang cocok dengan jenis ForEach<T> yang merupakan string. Aktivitas WriteLine yang ditentukan dalam Handler memiliki argumen Text yang terikat ke nilai string dalam koleksi yang diulangi oleh aktivitas ForEach<T>.

DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();

Activity wf = new ForEach<string>
{
    Body = new ActivityAction<string>
    {
        Argument = actionArgument,
        Handler = new WriteLine
        {
            Text = new InArgument<string>(actionArgument)
        }
    }
};

List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);

WorkflowInvoker.Invoke(wf, inputs);

actionArgument digunakan untuk mengalirkan item individual dalam koleksi ke WriteLine. Saat alur kerja dipanggil, keluaran berikut ditampilkan ke konsol.

HelloWorld.

Contoh dalam topik ini menggunakan sintaks inisialisasi objek. Sintaks inisialisasi objek dapat menjadi cara yang berguna untuk membuat definisi alur kerja dalam kode karena memberikan tampilan hierarkis tentang aktivitas dalam alur kerja dan menunjukkan hubungan antara aktivitas. Tidak ada persyaratan untuk menggunakan sintaks inisialisasi objek saat Anda membuat alur kerja secara terprogram. Contoh berikut secara fungsional setara dengan contoh sebelumnya.

DelegateInArgument<string> actionArgument = new DelegateInArgument<string>();

WriteLine output = new WriteLine();
output.Text = new InArgument<string>(actionArgument);

ActivityAction<string> body = new ActivityAction<string>();
body.Argument = actionArgument;
body.Handler = output;

ForEach<string> wf = new ForEach<string>();
wf.Body = body;

List<string> items = new List<string>();
items.Add("Hello");
items.Add("World.");

Dictionary<string, object> inputs = new Dictionary<string, object>();
inputs.Add("Values", items);

WorkflowInvoker.Invoke(wf, inputs);

Untuk mengetahui informasi selengkapnya tentang penginisialisasi objek, lihat Cara: Menginisialisasi Objek tanpa Memanggil Konstruktor (Panduan Pemrograman C#) dan Cara: Mendeklarasikan Objek dengan Menggunakan Penginisialisasi Objek (Visual Basic).

Dalam contoh berikut, aktivitas TryCatch digunakan dalam alur kerja. ApplicationException dilemparkan oleh alur kerja, dan ditangani oleh aktivitas Catch<TException>. Handler untuk Catch<TException> tindakan aktivitas aktivitas adalah WriteLine aktivitas, dan detail pengecualian mengalir melaluinya menggunakan exDelegateInArgument<T>.

DelegateInArgument<ApplicationException> ex = new DelegateInArgument<ApplicationException>()
{
    Name = "ex"
};

Activity wf = new TryCatch
{
    Try = new Throw()
    {
        Exception = new InArgument<Exception>((env) => new ApplicationException("An ApplicationException was thrown."))
    },
    Catches =
    {
        new Catch<ApplicationException>
        {
            Action = new ActivityAction<ApplicationException>
            {
                Argument = ex,
                Handler = new WriteLine()
                {
                    Text = new InArgument<string>((env) => ex.Get(env).Message)
                }
            }
        }
    },
    Finally = new WriteLine()
    {
        Text = "Executing in Finally."
    }
};

Saat membuat aktivitas kustom yang mendefinisikan ActivityAction<T>, gunakan InvokeAction<T> untuk memodelkan pemanggilan ActivityAction<T> tersebut. Dalam contoh ini, aktivitas kustom WriteLineWithNotification ditentukan. Aktivitas ini terdiri dari Sequence yang berisi aktivitas WriteLine diikuti oleh InvokeAction<T> yang memanggil ActivityAction<T> yang mengambil satu argumen string.

public class WriteLineWithNotification : Activity
{
    public InArgument<string> Text { get; set; }
    public ActivityAction<string> TextProcessedAction { get; set; }

    public WriteLineWithNotification()
    {
        this.Implementation = () => new Sequence
        {
            Activities =
            {
                new WriteLine
                {
                    Text = new InArgument<string>((env) => Text.Get(env))
                },
                new InvokeAction<string>
                {
                    Action = TextProcessedAction,
                    Argument = new InArgument<string>((env) => Text.Get(env))
                }
            }
        };
    }
}

Saat alur kerja dibuat dengan menggunakan aktivitas WriteLineWithNotification, pembuat alur kerja menentukan logika kustom yang diinginkan dalam tindakan aktivitas Handler. Dalam contoh ini, alur kerja dibuat yang menggunakan aktivitas WriteLineWithNotification, dan aktivitas WriteLine digunakan sebagai Handler.

// Create and invoke the workflow without specifying any activity action
// for TextProcessed.
Activity wf = new WriteLineWithNotification
{
    Text = "Hello World."
};

WorkflowInvoker.Invoke(wf);

// Output:
// Hello World.

// Create and Invoke the workflow with specifying an activity action
// for TextProcessed.
DelegateInArgument<string> msg = new DelegateInArgument<string>();
Activity wf2 = new WriteLineWithNotification
{
    Text = "Hello World with activity action.",
    TextProcessedAction = new ActivityAction<string>
    {
        Argument = msg,
        Handler = new WriteLine
        {
            Text = new InArgument<string>((env) => "Handler of: " + msg.Get(env))
        }
    }
};

// Invoke the workflow with an activity action specified
WorkflowInvoker.Invoke(wf2);

// Output:
// Hello World with activity action.
// Handler of: Hello World with activity action.

Ada beberapa versi generik InvokeAction<T> dan ActivityAction<T> disediakan untuk meneruskan satu atau beberapa argumen.

Menggunakan ActivityFunc

ActivityAction<T> berguna saat tidak ada nilai hasil dari aktivitas, dan ActivityFunc<TResult> digunakan saat nilai hasil dikembalikan. Saat membuat aktivitas kustom yang mendefinisikan ActivityFunc<TResult>, gunakan InvokeFunc<TResult> untuk memodelkan pemanggilan ActivityFunc<TResult> tersebut. Dalam contoh berikut, aktivitas WriteFillerText ditentukan. Untuk menyediakan teks pengisi, InvokeFunc<TResult> ditentukan yang mengambil argumen bilangan bulat dan memiliki hasil string. Setelah teks pengisi diambil, teks ditampilkan ke konsol menggunakan aktivitas WriteLine.

public class WriteFillerText : Activity
{
    public ActivityFunc<int, string> GetText { get; set; }
    public InArgument<int> Quantity { get; set; }

    Variable<string> text = new Variable<string>
    {
        Name = "Text"
    };

    public WriteFillerText()
    {
        this.Implementation = () => new Sequence
        {
            Variables =
            {
                text
            },
            Activities =
            {
                new InvokeFunc<int, string>
                {
                    Func = GetText,
                    Argument = new InArgument<int>((env) => Quantity.Get(env)),
                    Result = new OutArgument<string>(text)
                },
                new WriteLine
                {
                    Text = new InArgument<string>(text)
                }
            }
        };
    }
}

Untuk menyediakan teks, aktivitas harus digunakan yang mengambil satu argumen int dan memiliki hasil string. Contoh ini menunjukkan aktivitas TextGenerator yang memenuhi persyaratan ini.

public class TextGenerator : CodeActivity<string>
{
    public InArgument<int> Quantity { get; set; }
    public InArgument<string> Text { get; set; }

    protected override string Execute(CodeActivityContext context)
    {
        // Provide a quantity of Random Text
        int q = Quantity.Get(context);
        if (q < 1)
        {
            q = 1;
        }

        string text = Text.Get(context) + " ";
        StringBuilder sb = new StringBuilder(text.Length * q);
        for (int i = 0; i < q; i++)
        {
            sb.Append(text);
        }

        return sb.ToString();
    }
}

Untuk menggunakan aktivitas TextGenerator dengan aktivitas WriteFillerText, tentukan sebagai Handler.

DelegateInArgument<int> actionArgument = new DelegateInArgument<int>();

Activity wf = new WriteFillerText
{
    Quantity = 5,
    GetText = new ActivityFunc<int, string>
    {
        Argument = actionArgument,
        Handler = new TextGenerator
        {
            Quantity = new InArgument<int>(actionArgument),
            Text = "Hello World."
        }
    }
};

WorkflowInvoker.Invoke(wf);