Posts Tagged ‘PostSharp’

Cross-thread operations with PostSharp

Tuesday, January 26th, 2010

When you try to inform User Interface (UI) about the background operation progress or completion, you can not do it from the background thread.

UI doesn’t like to be informed about anything from a different thread: you’ll get “System.InvalidOperationException: Cross-thread operation not valid: Control ‘xxx’ accessed from a thread other than the thread it was created on.” exception from WinForms control, if you try:

public void ShowStatus(ApplicationStatus status)
{
    this._lblServiceAddress.Text = "Connected to: "
        + status.WebServiceAddress;
    this._lblUserId.Text = "Working as: "
        + status.UserId;
}

The easiest sollution is to use BeginInvoke method on the control Control or Form:

public void ShowStatus(ApplicationStatus status)
{
    this.BeginInvoke((MethodInvoker)(() =>
        {
            this._lblServiceAddress.Text = "Connected to: "
                + status.WebServiceAddress;
            this._lblUserId.Text = "Working as: "
                + status.UserId;
        }));
}

Well, it’s fun to write this once, but if you have many operations done in background sooner or later you’d like to have something nicer. Like an attribute for example:

[ThreadAccessibleUI]
public void ShowStatus(ApplicationStatus status)
{
    this._lblServiceAddress.Text = "Connected to: " + status.WebServiceAddress;
    this._lblUserId.Text = "Working as: " + status.UserId;
}

Here’s the attribute implementation of such attribute using PostSharp 1.5:

/// <summary>
/// PostSharp attribute.
/// Use it to mark Control's methods that
/// are invoked from background thread.
/// </summary>
/// <remarks>
/// Be careful as BeginInvoke uses the message queue.
/// This means that the interface will be refreshed
/// when application has a chance to process its messages.
/// </remarks>
[AttributeUsage(AttributeTargets.Method)]
[Serializable] // required by PostSharp
public class ThreadAccessibleUIAttribute : OnMethodInvocationAspect
{
    public override void OnInvocation(
        MethodInvocationEventArgs eventArgs)
    {
        Control control = eventArgs.Instance as Control;
        if (control == null)
            throw new ApplicationException(
                "ThreadAccessibleUIAttribute" +
                "can be applied only to methods on Control class");

        // The form may be closed before
        // this method is called from another thread.
        if (control.Created == false)
            return;

        control.BeginInvoke((MethodInvoker)eventArgs.Proceed);
    }
};

Introducing PostSharp to your team

Wednesday, September 16th, 2009

PostSharp is AOP (Aspect-Oriented-Programming) framework (www.sharpcrafters.com).
It transparently inserts itself in the build process and post-processes the compiled assembly.

To enable PostSharp in your project you need to download and run the PostSharp installer, and add appropriate references in your project.

However if your project is in SVN, and you are not the only one compiling it (other developers, CI machine) most likely you don’t want to run PostSharp installer on all the machines.

There is a way to introduce PostSharp transparently to your project.

  • Put all the PostSharp files in the LibPostSharp folder of your project and add this folder to SVN.
  • Modify the .csproj file: After the last ItemGroup following xml must be inserted:
  <propertyGroup>
    <dontImportPostSharp>True</dontImportPostSharp>
    <!-- Add the next line if you are using Visual Studio 2010 -->
    <!-- <postSharpUseCommandLine>True</postSharpUseCommandLine>-->
  </propertyGroup>
  • Modify the .csproj file: After the
<import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" />

following xml must be inserted:

<import Project="..LibPostSharpPostSharp.targets" />

The whole change should be similar to this sample:

</itemGroup>
  <propertyGroup>
    <dontImportPostSharp>True</dontImportPostSharp>
  </propertyGroup>
  <import Project="$(MSBuildToolsPath)Microsoft.CSharp.targets" />
  <import Project="..LibPostSharpPostSharp-1.5.targets" />
</project>

INotifyPropertyChanged with PostSharp 1.5

Tuesday, September 15th, 2009

If you are doing WPF development, most likely you are tired of writing property implementations that raise PropertyChanged event manually:

public class MainWindowViewModel : ViewModel
{
    private string _message;

    public string Message
    {
        get
        {
            return _message;
        }
        set
        {
            _message = value;
            OnPropertyChanged("Message");
        }
    }

    // ...
}

PostSharp is a great tool to make such things simplier.

Let’s look at the specific ViewModel class that has a Message property that is bound to some UI element using XAML:

public class MainWindowViewModel : ViewModel
{
    [RaisePropertyChanged]
    public string Message { get; set; }

    // ...
}

Notice the RaisePropertyChanged attribute, which we’ll implement later.

Here’s our base ViewModel class that provides actual implementation of the INotifyPropertyChanged interface:

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged
        = delegate { };

    public void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this,new PropertyChangedEventArgs(propertyName));
    }
};

Finally the PostSharp attribute:

[Serializable]  // required by PostSharp
public class RaisePropertyChangedAttribute : OnMethodBoundaryAspect
{
    private string _propertyName;

    /// <summary>
    /// Executed at runtime, after the method.
    /// </summary>
    public override void OnExit(MethodExecutionEventArgs eventArgs)
    {
        ViewModel viewModel = (ViewModel)eventArgs.Instance;
        viewModel.OnPropertyChanged(_propertyName);
    }

    public override bool CompileTimeValidate(MethodBase method)
    {
        if (IsPropertySetter(method))
        {
            _propertyName = GetPropertyName(method);
            return true;
        }
        return false;
    }

    private static string GetPropertyName(MethodBase method)
    {
        return method.Name.Replace"set_", "");
    }

    private static bool IsPropertySetter(MethodBase method)
    {
        return method.Name.StartsWith("set_");
    }
};

Note that we are validating if the method is in fact a property only during compilation time using CompileTimeValidate method.

During compile time appropriate invocations of OnPropertyChanged method will be injected after every set operation applied to the Message property.