Archive for the ‘Composite UI Application Block’ Category

How to fix CAB to support dependencies across class hierarchy

Friday, April 29th, 2011

The Composite UI Application Block’s Object Builder doesn’t support dependencies for same-named properties at different levels in the class hierarchy. If you add a dependency property which has the same name as a property in a base or derived class, only one of them will be initialized.

The reason for this is probably that the mechanism is based on the Type.GetProperties() method. This method doesn’t return all of the properties the class (and the base classes) contain – rather, it employs a “hide by name and signature” convention and gives only the topmost properties. So the first step we have to do is eliminate the GetProperties method. We do this by modifying the GetMembers() method of the PropertyReflectionStrategy (located in ObjectBuilder/Strategies/Property). It should look like this:

protected override IEnumerable<IReflectionMemberInfo<PropertyInfo>> GetMembers(IBuilderContext context, Type typeToBuild, object existing, string idToBuild)
{
    foreach (PropertyInfo propInfo in GetPropertiesFlattened(typeToBuild))
        yield return new PropertyReflectionMemberInfo(propInfo);
}

private IEnumerable<PropertyInfo> GetPropertiesFlattened(Type typeToBuild)
{
    for (Type t = typeToBuild; t != null; t = t.BaseType)
    {
        foreach (var pi in t.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly)) // get only properties in this class
        {
            yield return pi;
        }
    }
}

The next problem arises because the PropertyReflectionStrategy keeps a dictionary of existing properties. It’s indexed by property name, which would eliminate our duplicate properties. We have to change it to use the full path – property name prefixed by class name and namespace. I did this by adding a property called FullName to the IReflectionMemberInfo and ReflectionMemberInfo (found in ObjectBuilder/Strategies).

In IReflectionMemberInfo, add:

string FullName { get; }

In ReflectionMemberInfo, add:

public string FullName
{
    get { return memberInfo.DeclaringType.FullName + "." + memberInfo.Name; }
}

There’s a PropertyReflectionMemberInfo class embedded in the PropertyReflectionStrategy, we have to add a similar property to it:

public string FullName
{
    get { return prop.DeclaringType.FullName + "." + prop.Name; }
}

Ok – next, in the PropertyReflectionStrategy we rewire the dictionary to use this new property. Go to AddParametersToPolicy method and change this -

if (!result.Properties.ContainsKey(member.Name))
    result.Properties.Add(member.Name, new PropertySetterInfo(member.MemberInfo, parameter));

- to this -

if (!result.Properties.ContainsKey(member.FullName))
    result.Properties.Add(member.FullName, new PropertySetterInfo(member.MemberInfo, parameter));

One last glitch to fix: go to CompositeUI/WorkItem class, and in the BuildUp() method change this -

propPolicy.Properties.Add("Parent", new PropertySetterInfo("Parent", new ValueParameter(typeof(WorkItem), null)));

- to this -

propPolicy.Properties.Add("Microsoft.Practices.CompositeUI.WorkItem.Parent", new PropertySetterInfo("Parent", new ValueParameter(typeof(WorkItem), null)));

Without this modification, the root WorkItem would have its Parent property reference itself, and it would not be recognized as root WorkItem because it’s Parent property is not null. As a consequence, some initialization methods would not get called and almost nothing would work.

Running Composite UI Application Block inside a windows service

Friday, January 30th, 2009

This was a brain-twister: not a lot of work but hard to figure out. How does one use CAB in a windows service?

Is this a reasonable requirement, a Composite UI framework in an application with no UI? Well, it is, since CAB is not only about UI… If you have a framework of components that use CAB services and need to run them in unattended mode, it would be much easier to implement CAB support in the service instead of modifying everything to run with as well as without CAB.

I’m going to present one solution that worked for me, but I believe there are other variations. Since your requirements may vary, I’ll describe the general idea so you can modify or improve it.

So, how does CAB fit within a service? There’s a couple of fundamental differences between the two: a service class needs to be derived from the framework-defined ServiceBase class while a CAB application has its own base class, WindowsFormsApplication. A service doesn’t need to have a message loop like a windows forms application does.

But the thing is, CAB doesn’t require any of the windows app features. And this is the crucial detail: CAB is simply a bunch of objects and services attached to your component. When running a CAB application, the CAB infrastructure creates all the necessary services and structures and then starts the application like it’s not different from any other windows app. It is the programmer’s task to have his components keep references  to CAB components (like WorkItem) and communicate with them. But the CAB structures are inactive and not required for proper running of a CAB application. If all of the components within it reset their properties that reference the CAB infrastructure, the whole bunch of CAB objects would probably be disposed by the CLR’s garbage collector.

In a windows application, it’s the message pump that holds the application together: when the pump stops, the application exits. In a service, its equivalent is the service object (one or more of them). You cannot substitute a message pump for a service because Windows service host expects to get a running service and nothing else. If a service object is not registered within a specified timeout period of starting the service, Windows will assume the process has hanged -even if there’s a message pump running within it.

So, obviously, one part of the solution is to put our service where the “ordinary” CAB application’s message loop was. This is the CAB application’s Start() method. When you create a windows CAB application, you need to override WindowsFormsApplication’s Start() method and start the message pump within it. Now, for the purposes of creating a service, you can create an equivalent WindowsServiceApplication class and run the service within its overridden Start() method. Since a service doesn’t have a shell, you derive WindowsServiceApplication directly from CabApplication class.

But how do we run the WindowsServiceApplication? We can do this from the Main() method: remember that running the CAB application is equivalent to running an ordinary application: after the CAB startup code creates the necessary infrastructure objects, the application proceeds to run just like any other. What we probably should do, however, is create the service instance using CAB so that everything within it can use CAB. This isn’t necessary: in a similar way to an “ordinary” CAB application, you register with CAB only the components that are CAB-aware.

Here’s the sample code (note that I haven’t tested it, this is a simplified version of the class we have in our application):

using Microsoft.Practices.CompositeUI;

namespace EightBit.CrmService
{
	class WindowsServiceApplicationDemo : CabApplication<WorkItem>
	{
		static void Main(string[] args)
		{
			WindowsServiceApplicationDemo prg = new WindowsServiceApplicationDemo();
			prg.Run();
		}

		protected override void Start()
		{
			// uncomment to debug service startup
			//System.Diagnostics.Debugger.Break();

			// this part ensures that the newly created crm service
			// gets attached to the CAB environment
			CrmService svc = this.RootWorkItem.Items.AddNew<CrmService>();
			System.ServiceProcess.ServiceBase.Run(svc);
		}
	}
}


I haven’t shown the CrmService class source because it’s not different from an ordinary service – except that it now has CAB dependency properties.

Entries (RSS) and Comments (RSS).