Archive for category development

Validation error on compiling unused Activity with custom ActivityValidator

Although I’ve worked with WWF (Windows Workflow Foundation) during all 2009, I haven’t posted anything about the technology yet, so I thought it was maybe the time to do it. I’ll start with one of the bases of the implementation of custom ActivityValidator classes. Despite being simple, that is an error that strikes new workflow developers quite often.

When creating a custom ActivityValidator, you might receive a compilation error from the newly created validator, even when the custom Activity it is targeted against is not in use yet.

But how come? Let’s take a look at the example below:

[ActivityValidator(typeof(MyCustomValidator))]
public partial class MyCustomActivity : Activity
{
    public static DependencyProperty PriceProperty = DependencyProperty.Register("Price", typeof(float), typeof(MyCustomActivity));

    [DescriptionAttribute("Price")]
    [CategoryAttribute("Price Category")]
    [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
    public float Price
    {
        get
        {
            return ((float)(base.GetValue(MyCustomActivity.PriceProperty)));
        }
        set
        {
            base.SetValue(MyCustomActivity.PriceProperty, value);
        }
    }

	public MyCustomActivity()
	{
		InitializeComponent();
	}
}

public class MyCustomValidator : ActivityValidator
{
    public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
    {
        MyCustomActivity myCustomActivity = obj as MyCustomActivity;
        ValidationErrorCollection errors = base.Validate(manager, obj);

        if (myCustomActivity == null)
        {
            throw new ArgumentException("MyCustomValidator can only be used to validate MyCustomActivity instances.", "obj");
        }

        if (myCustomActivity.Price <= 0)
        {
            errors.Add(new ValidationError("'Price' must be greater than zero.", 1));
        }

        return errors;
    }
}

In the example above, when you build the project you will receive an error such as

Error 1 Activity 'MyCustomActivity' validation failed: 'Price' must be greater than zero.

Well, that is not nice. You are not even using MyCustomActivity yet!

The reason for that is simple: validators are run during runtime, but also during build time! To avoid the error, we simply check if the custom activity is in use. How? Take a peak:

public class MyCustomValidator : ActivityValidator
{
    public override ValidationErrorCollection Validate(ValidationManager manager, object obj)
    {
        MyCustomActivity myCustomActivity = obj as MyCustomActivity;
        ValidationErrorCollection errors = base.Validate(manager, obj);

        if (myCustomActivity == null)
        {
            throw new ArgumentException("MyCustomValidator can only be used to validate MyCustomActivity instances.", "obj");
        }

        if (myCustomActivity.Parent != null)
        {
            if (myCustomActivity.Price <= 0)
            {
                errors.Add(new ValidationError("'Price' must be greater than zero.", 1));
            }
        }

        return errors;
    }
}

As you can see, all we did was checking if the activity parent is not null (line 13).

Try to build now, no error will be triggered. Then drop MyCustomActivity to a workflow, don't fill in Price and build again. The error is now there, correctly returned!

Well, that was it... No black magic but surely resourceful! I hope it helps!

Tags: , , , , , , ,

Oh no, not AG_E_PARSER_UNKNOWN_TYPE!

You are coding an UserControl for your Silverlight 2 application that might change the world. You are almost done with it, already told all the guys that the first round is on you. You are thrilled about your fabulous coding skills.

And then you find him. An horrendous, terrible, dreadful enemy. His name: AG_E_PARSER_UNKNOWN_TYPE.

You don't want to cross his path.

You start looking for reasons of such an error, but all you find is despair. No hints, no clues, you start loosing your temper – and possibly your hair. You curse the framework for not supplying you with enough information: just a plain AG_E_PARSER_UNKNOWN_TYPE on your xaml file. Googling does not help you much, as few have faced that horrible vilain.

Fear not, friend, as I have found him myself, and I am going to share the secrets of some of his weak spots. Explore them, and I hope you defeat him the way I did.

Jokes apart, that was an error that took me a while to figure it out. Everything happened when I was creating user controls that were related to each other by their parent class. And impressively I run into two different situations in the same task that lead me to AG_E_PARSER_UNKNOWN_TYPE.

My solution was structured as follows:

using System;
using System.ComponentModel;

namespace MySolution
{
    public abstract class MyBaseClass : UserControl
    {
    }

    public partial class MyClass1 : MyBaseClass
    {
    }

    public partial class MyClass2 : MyBaseClass
    {
    }
}

First error in the intended code above: the MyBaseClass derivating from UserControl can’t be declared abstract. I know, it is a pain in case you want to create an abstract method within – you won’t be able to do that at all. Try a workaround like creating virtual methods throwing a NotImplementedException, and then overriding it with the real implementation.

The other situation I found that error in was related to listeners and the user control constructor. I’m not entirely sure why that happens, but if you register for a listener on the constructor class (or call any method registering it from the constructor) of your user control, you might have a chance to encounter the might evil AG_E_PARSER_UNKNOWN_ERROR is.

Also, a collegue pointed out for me a blog post with some explanations to AG_E_PARSER_UNKNOWN_ERROR and other Silverlight hell minions alike. Despite being related to Silverlight 1.1 alpha, I found the list to be trully helpful. I wish I had found that one before, the struggle would be much smaller!

Tags: , , , , , , ,

Wait messages and asynchronous calls in Silverlight 2

SilverlightToday I had a nice learning experience on how to handle “please wait” screens and asynchronous calls on Silverlight 2.

Say that you want to present a message to your user while he waits an asynchronous call to be completed. However, given the nature of the call, you can’t control how long it will take to complete, and thus that message may be just a quick blink in the screen. But what if you still want that message to be readable, even when the call answers almost instantaneously?

Using System.Threading.Thread.Sleep() is not a good option, since it will hold the current thread – that is, the UI thread. And the user will be probably pissed off for having his browser frozen by the application.

The solution: BackgroundWorker and Dispatcher classes.

System.ComponentModel.BackgroundWorker (MSDN link) is a class that allows instructions to be run on a dedicated thread, with support to cancellation and progress reporting, while Dispatcher (MSDN link) is a handy property from the UserControl class (the one used as a base class to Silverlight pages) that gives us access to the UI thread.

Let’s see a simple example on how to implement the proposed solution.

using System;
using System.ComponentModel;
using System.Threading;

public class Page : UserControl
{
    // Bogus is any given class with an asynchronous call
    private Bogus bogus;
    private BackgroundWorker bgWorker;

    public Page()
    {
        InitializeComponent();

        // Creates the BackgroundWorker and says it supports cancellation
        bgWorker = new BackgroundWorker();
        bgWorker.WorkerSupportsCancellation = true;

        // Registers the listener
        bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork);

        // Instantiate the class that runs the asynchronous call
        bogus = new Bogus();
    }

    #region Button handlers
    private void btnCallAsync_OnClicked(object sender, EventArgs e)
    {
        // Registers the listener for handling the result for the asynchronous call
        bogus.BogusCompleted += new BogusEventHandler(bogus_BogusCompleted);

        // The "please wait" message
        lblText.Text = "Please wait while operation is processed...";

        // Run the BackgroundWorker thread
        bgWorker.RunWorkerAsync();
    }

    // Handles cancelation of the asynchronous call
    private void btnCancel_OnClicked(object sender, EventArgs e)
    {
        // Let's unregister the listener so that the asynchronous call
        // result is not handled
        bogus.BogusCompleted -= new BogusEventHandler(bogus_BogusCompleted);

        // Removes the "please wait" message
        lblText.Text = string.Empty;

        // Cancels the BackgroundWorker thread
        bgWorker.CancelAsync();
    }
    #endregion Button handlers

    private void bgWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        // Let's run it unless the BackgroundWorker is pending
        // cancelation
        if(!bgWorker.CancellationPending)
        {
            // This is not UI thread, since we are inside the
            // BackgroundWorker execution thread
            Thread.Sleep(new TimeSpan(0, 0, 3));

            // After sleeping for some time to allow users to read
            // the message, we start the asynchronous call
            bogus.RunBogusAsync();
        }
    }

    private void bogus_BogusCompleted(sender object, BogusEventArgs e)
    {
        // Any operations you want to execute in the UI thread
        // as a result of the asynchronous call
        Dispatcher.BeginInvoke(() => { UIOperations(); });

        // Unregister the listener since the call was already processed
        // and it is registered back on btnCallAsync_OnClicked()
        bogus.BogusCompleted -= new BogusEventHandler(bogus_BogusCompleted);
    }
}

So now let’s see in detail what the above code does.

The xaml file includes three controls: lblText (TextBlock control), btnCallAsync and btnCancel (Button controls).

As shown on btnCallAsync_OnClicked() (lines 27 to 37), lblText will display the wait message when btnCallAsync is clicked. Additionally, it will register the listener for BogusCompleted event and trigger the execution of the background worker.

bgWorker_DoWork() (lines 54 to 68) will then sleep the BackgroundWorker thread for a while and finally call the asynchronous method RunBogusAsync() which we were originally interested in.

On BogusCompleted, bogus_BogusCompleted() (lines 70 to 79) is finally run and Dispatcher.BeginInvoke() is called (using lambda expressions) to run something on the UI thread. We also unregister the listener for BogusCompleted events, since it is registered back every time btnCallAsync is clicked.

Sure we have a problem in this approach: we sleep the thread for some seconds before calling the asynchronous call, and that might cause a long wait in case Bogus.RunBogusAsync() takes too long to execute. For example, if the asynchronous call took five seconds to complete, we would keep the user waiting for eight seconds.

As an exercise, put the BackgroundWorker thread to sleep after the call to Bogus.RunBogusAsync(), and only if the asynchronous call didn’t take more than three seconds, so that the total wait would be at least three seconds, but no unnecessary extra time when.

Tags: , , , ,

Dev is back

Not devil, development.

Após longo tempo sem postar, acho que agora é a hora. Voltar a trabalhar com desenvolvimento é muito bom, e me proporcionando muitas oportunidades pra aprender novas coisas.

Após dois anos de desenvolvimento PL/SQL, sendo os últimos seis meses mais especificamente com gerência de testes, volto ao universo do desenvolvimento – .NET, C#, WCF, Workflow Foundation, Silverlight e outras coisas mais.

Estou bolando alguns artigos para publicar aqui, aguardem (quem?).

Chucknismo

Chuck Norris Facts:

Chuck Norris can rollback a TRUNCATE TABLE command.

Tags: ,