Friday, October 30, 2009

Logging proxy

I learnt today that I can create a proxy that intercepts calls to an object, do anything with the call and forward the call to the appropriate object. The same is true for the results. The whole thing is implemented by using a RealProxy implementation. I will demonstrate the functionality with .NET Remoting.

The common interface

namespace Common
{
public interface IServer
{
int Add(int a, int b);
}
}

The server implementation

using Common;

namespace Server
{
class ServerImpl: MarshalByRefObject, IServer
{
#region IServer Members

public int Add(int a, int b)
{
return a + b;
}

#endregion

public override object InitializeLifetimeService()
{
return null;
}
}
}

The server loop

static void Main()
{
// Windows Forms settings
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

// Remoting loop
RemotingServices.Marshal(new SzerverImplementacio(), "Server");
ChannelServices.RegisterChannel(new TcpChannel(8080), false);

// Windows Froms Window
Application.Run(new Form1());
}

The logging proxy

using System.Runtime.Remoting.Proxies;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Channels;
using System.Collections;
 
namespace Kliens
{
    public class LogProxy : RealProxy
    {
        String uri;
        MarshalByRefObject obj;
        IMessageSink _sinkChain;
 
        public LogProxy(Type type, string uri) : base(type)
        {
            this.uri = uri;
 
            IChannel[] registeredChannels = ChannelServices.RegisteredChannels;
            foreach (IChannel chnl in registeredChannels)
            {
                if (chnl is IChannelSender)
                {
                    IChannelSender chnlSender = (IChannelSender)chnl;
                    _sinkChain = chnlSender.CreateMessageSink(uri, null, out uri);
                    if (_sinkChain != null)
                        break;
                }
            } 
 
            if (_sinkChain == null)
            {
                throw new Exception("No channel has been found for " + uri);
            }
 
        }
 
        public override IMessage Invoke(IMessage msg)
        {
            Console.WriteLine("LogProxy.Invoke Start");
            Console.WriteLine("");
 
            // Set message URI
            msg.Properties["__Uri"] = uri;
 
            // List call properties
            Console.WriteLine("Call properties:");
            foreach (var key in msg.Properties.Keys)
            {
                Console.WriteLine("{0}: {1}", key, msg.Properties[key]);
                if (key.ToString() == "__Args")
                {
                    Console.WriteLine("Arguments:");
 
                    object[] args = (object[])msg.Properties[key];
                    foreach (var arg in args)
                    {
                        Console.WriteLine("arg: {0}", arg);
                    }
                }
            }
 
            // Process the request mesage
            IMessage retMsg = _sinkChain.SyncProcessMessage(msg);
 
            // List return properties
            Console.WriteLine("Return properties:");
            foreach (var key in retMsg.Properties.Keys)
            {
                Console.WriteLine("{0}: {1}", key, retMsg.Properties[key]);
            }
 
            // Process the return message
            return retMsg;
 
        }
    }
}

Call the server from the client

// Without logging proxy:
// IServer server = (IServer)Activator.GetObject(typeof(IServer), "tcp://localhost:8080/Server");
 
TcpChannel chnl = new TcpChannel();
ChannelServices.RegisterChannel(chnl, false);
 
LogProxy prx = new LogProxy(typeof(IServer), "Tcp://localhost:8080/Server");
IServer server = (IServer)prx.GetTransparentProxy();
MessageBox.Show(server.Add(2, 3).ToString());

Result

All the call end response properties will be listed in the Output window (or in the Console). The call will happen as there were no proxy class taking part in the call.

Apart Remoting this is a good solution for generating any kind of proxies:

  • Virtual proxies
  • Security proxies

RealProxy is a good extension point for an application.

Thursday, October 29, 2009

Hiding XAML designer by default

I hate Visual Studio 2008 XAML Designer. It’s slow and can be easily killed (I mean XAML Designer can’t be displayed, just an error message instead). I prefer Expression Blend 3 for GUI design.

So here are the steps to hide the designer and go straight to the text editor:

  1. Open Tools/Options
  2. Select Text Editor/XAML/Miscellaneous
  3. Under ‘Default View’ select ‘Always open documents in full XAML view’

After setting this option, you will still be able to change to designer using a tab, but the editor will be the default view for XAML files. Faster loading an (hopefully) less crashes.

XAML Combobox SelectedItem binding

Combobox SelectedItem binding in XAML  did not work for me at first.

This is the XAML for binding:

<ComboBox x:Name="format" DisplayMemberPath="Text" SelectedItem="{Binding Format}" IsEditable="False"   />

This is the code behind:

PublishingFormatRepository pf = new PublishingFormatRepository(Current.BookshelfPath);
List<PublishingFormat> publishingFormats = pf.All as List<PublishingFormat>;
format.ItemsSource = publishingFormats;
if (publishingFormats != null) format.SelectedItem = publishingFormats[0];

set
{
_book = value;
DataContext = _book;
}

It’s simple, it should work. I attached a binding tracer to the binding extension but there was no problem. After a while something came on my mind: object equality. I checked something like this:

_book.Format == publishingFormats[0]

It should have been true but it was false.

So the solution is simple:

[Serializable]
public class PublishingFormat : IEquatable<PublishingFormat>
{
////////////////
// Members here
////////////////

public override bool Equals(object obj)
{
return Equals(obj as PublishingFormat);
}

#region IEquatable<PublishingFormat> Members

public virtual bool Equals(PublishingFormat other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return other.Id.Equals(Id);
}

#endregion

public override int GetHashCode()
{
return Id.GetHashCode();
}

public static bool operator ==(PublishingFormat left, PublishingFormat right)
{
return Equals(left, right);
}

public static bool operator !=(PublishingFormat left, PublishingFormat right)
{
return !Equals(left, right);
}
}

The class implements the IEquatable interface and overrides the Equals function and the ==, != operators. In my case the equality will be evaluated by comparing the Id fields of the classes.

Now the simple XAML expression above works.

Link: How to: Define Value Equality for a Type (C# Programming Guide) [MSDN]

Sunday, October 18, 2009

Inheritance depth

I’m developing an application and I’m controlling code quality with NDepend. There is a CQL rule for checking inheritance depth. The built in rule is the following:

WARN IF Count > 0 IN 
SELECT TOP 10 TYPES
WHERE DepthOfInheritance >= 6
ORDER BY DepthOfInheritance DESC

The project is a WPF-based application, so I got a lot of warning. I have controls and windows, all of them starting at inheritance level 9. So I rewrote the CQL query as follows:

WARN IF Count > 0 IN 
SELECT TOP 10 TYPES
WHERE
(
(DepthOfInheritance >= 6 AND
! DeriveFrom "System.Windows.Controls.UserControl" AND
! DeriveFrom "System.Windows.Window" )
)
OR ( DepthOfInheritance >= 12 )
ORDER BY DepthOfInheritance DESC

This rule will warn me if

  • the component  is not derived from UserControl or Window and the inheritance level is higher than 6 or
  • the inheritance level is higher than 12.

In other words I allow 3 inheritance level for user controls and windows and 6 for others.

Thursday, October 15, 2009

Autofill TFS password on Codeplex

TFS login  I hate filling in TFS credentials every time I connect to TFS server on Codeplex. I’ve just found an easy way to automate it.

Microsoft Windows Vista and Windows 7 have a new component called Credential Manager. You can store Windows, Certificate-based and Generic credentials. It means these credentials can be automatically provided by Windows on request. So you just simply don’t have to type them in every time you log on somewhere.

Codeplex

These are the steps to automate the Codeplex login process:

  1. Open Credential Manager
  2. Choose Add a Windows credential
  3. Specify the Codeplex server name at Internet or network address, fill in the rest
  4. Click OK
  5. Open your TFS project

You won’t be prompted for credentials anymore.

Credential Manager

Thursday, October 8, 2009

WPF MVVM pattern

MVVM1 I’m using the WPF Model-View-ViewModel(MVVM) pattern in one of my projects. I will tell a few words about the implementation.

The first step is to create an entity class, the Model. This class stores only data. To support binding and data validation in WPF, it also implements the IDataErrorInfo interface. Entity classes can be generated by object-relational mapping (ORM) tools like NHibernate or Microsoft Entity Framework. Or you can implement them yourself using e.g. Active Record, Data Mapper, Row Data Gateway, or Table Data Gateway patterns. The entity class don’t have to implement INotifyPropertyChanged interface, this functionality will be provided by the ViewModel.

Next you create the ViewModel. This class will be the link between the Model and the View – between the data and the user interface elements. It will store and update the Model data, and it will transform the data to be displayed on the user interface. ViewModel has the same properties as the Model (or a subset of it). ViewModel can provide calculated fields to be displayed as well. All properties signal their change, so ViewModel implements INotifyProperyChanged interface and fires the appropriate event in case of property value change.
ViewModel can react on commands. It can save its content into the database (using ORM functionality or something like that. ) While you should implement every single commands if you implemented ICommand on its own, you can introduce the RelayCommand class.

   1: public class RelayCommand : ICommand
   2:     {
   3:         readonly Action<object> _execute;
   4:         readonly Predicate<object> _canExecute;
   5:  
   6:         /// <summary>
   7:         /// Creates a new command that can always execute.
   8:         /// </summary>
   9:         /// <param name="execute">The execution logic.</param>
  10:         public RelayCommand(Action<object> execute)
  11:             : this(execute, null)
  12:         {
  13:         }
  14:  
  15:         /// <summary>
  16:         /// Creates a new command.
  17:         /// </summary>
  18:         /// <param name="execute">The execution logic.</param>
  19:         /// <param name="canExecute">The execution status logic.</param>
  20:         public RelayCommand(Action<object> execute, Predicate<object> canExecute)
  21:         {
  22:             if (execute == null)
  23:                 throw new ArgumentNullException("execute");
  24:  
  25:             _execute = execute;
  26:             _canExecute = canExecute;
  27:         }
  28:  
  29:  
  30:         #region ICommand Members
  31:  
  32:         /// <summary>
  33:         /// Defines the method that determines whether the command can execute in its current state.
  34:         /// </summary>
  35:         /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
  36:         /// <returns>
  37:         /// true if this command can be executed; otherwise, false.
  38:         /// </returns>
  39:         [DebuggerStepThrough]
  40:         public bool CanExecute(object parameter)
  41:         {
  42:             return _canExecute == null ? true : _canExecute(parameter);
  43:         }
  44:  
  45:         /// <summary>
  46:         /// Occurs when changes occur that affect whether or not the command should execute.
  47:         /// </summary>
  48:         public event EventHandler CanExecuteChanged
  49:         {
  50:             add { CommandManager.RequerySuggested += value; }
  51:             remove { CommandManager.RequerySuggested -= value; }
  52:         }
  53:  
  54:         /// <summary>
  55:         /// Defines the method to be called when the command is invoked.
  56:         /// </summary>
  57:         /// <param name="parameter">Data used by the command.  If the command does not require data to be passed, this object can be set to null.</param>
  58:         public void Execute(object parameter)
  59:         {
  60:             _execute(parameter);
  61:         }
  62:  
  63:         #endregion
  64:     }

RelayCommand simplifies the ICommand implementation to the following few lines:

public ICommand SaveCommand
{
get
{
if(_saveCommand == null)
{
_saveCommand = new RelayCommand(
param => Save(),
param => CanSave);
}
return _saveCommand;
}
}

View is simply a user interface component, like a DataGrid. You can bind your ViewModel to the view and the view will update itself in case of data modification (or can update data in case of two-way binding). You can bind a control to the command of ViewModel and the control will enable/disable itself if the command behind the control cannot be executed (e.g. you can’t save the data because the model data contains errors).

MVVM pattern is complicated at first sight and you will have to create much more complicated architecture and classes, but it worths to understand and implement.