April 2007 - Posts

Even though the Validation Application Block supports extensive composition of validation rules (using And and Or 'operators' and the Negated property) PIAB doesnt.

PIAB Matchingrules are always composed using an "AND" operator (Namespace is 'BusinessLogic.Actions' and Tag is 'ShouldBeAudited').
Additionally, the matchingrules themselves often contain a collection of matches that should help you to do composition such as ((Namespace is 'BusinessLogic.Actions' or 'BusinessLogic.Services') and Tag is 'ShouldBeAudited').

Fair enough, that seems pretty straightforward and allows for a fair amount of composition logic.
Though I ran in a situation a Not operator was desired. (Type is 'Foo' and not Method is 'Bar'), decided to add this and, for sake of completeness add the designtime for it (and do the same for OR and AND-operators).



I ran into this when trying to automate the creation of PIAB policies (and their matchingrules). Which probably isnt a typicial usage scenario, fair enough.

Still, if you find yourself in the need of these types of MatchingRules, feel free to re-use mine (both sourcecode and a binary copy are attached).
The binaries are compiled against an unsigned version of EntLib. Please read Tom's post on compatibility issues, before sticking those in EntLib's installation directory.


The DSL Toolkit knows a concept called shape (the thing that represents an element and is drawn on the modeling surface) and allows to define these shapes in 3 basic flavors:

1.)    Geometry Shapes. Either a Rectangle, Rounded rectangle, Ellipse or Circle
2.)    Image Shapes. An imported image
3.)    Compartment Shapes. Either a Rectangle or Rounded rectangle which contains compartments.

The “Geometry shape” has some advantages over the “Image shape”, it can be scaled and its style can be configured. The Geometry shape also features a shadow and cool highlight when hovering over it.
Geometry shapes are slightly harder to customize, though.... You should draw them in code using GDI.

Now, if you want to create your own geometry shapes it might be worth your while to have a look at some of the fonts (especially wingdings or webdings) on your system.
GDI you to import the structure of these fonts and draw them on a surface (DSL model?).



The way this works is:

1.) Place a “Geometry Shape” on your Dsl designer (mine is called “AlienShape”).
2.) In the property grid, Specify that a double derived class should be generated and set the Geometry property to “Circle”.
3.) After transforming the templates you should be able to derive from a class called “AlienShapeBase” and override its ShapeGeometry property to return your own.

public partial class AlienShape : AlienShapeBase
{
public override Microsoft.VisualStudio.Modeling.Diagrams.ShapeGeometry ShapeGeometry
{
get
{
FontShapeGeometry myShape = new FontShapeGeometry();
myShape.CharCode = (char)0x85;
myShape.FontName = "Webdings";

return myShape;
}
}
}

The FontShapeGeometry class uses the specified character and font to import this in a GDI structure, then manipulate it to fit your shape.
The implementation below, stretches the character to a Rectangularal shape. Since we derive from RectangleShapeGeomtery all the hit-testing, grabhandles, zooming and scaling should already be taken care of.

public class FontShapeGeometry : RectangleShapeGeometry
{
char c;
public char CharCode
{
get { return c; }
set { c = value; }
}

string fontName;
public string FontName
{
get { return fontName; }
set { fontName = value; }
}

public override System.Drawing.Drawing2D.GraphicsPath GetPath(IGeometryHost geometryHost)
{
RectangleF targetRect = RectangleD.ToRectangleF(geometryHost.GeometryBoundingBox);

GraphicsPath path = base.UninitializedPath;
path.Reset();

//draw the character in the GrpahicsPath on 1.1
path.AddString(new String(c, 1), new FontFamily(FontName), 1, 1, new RectangleF(0, 0, targetRect.Width, targetRect.Height), StringFormat.GenericDefault);

//Calculate the bounds of the drawn character, calculate whether we should scale it.
RectangleF currentBounds = path.GetBounds();
float scaleX = targetRect.Width / currentBounds.Width;
float scaleY = targetRect.Height / currentBounds.Height;

//Scale it
Matrix scaleTransform = new Matrix();
scaleTransform.Scale(scaleX, scaleY);
path.Transform(scaleTransform);

//Calculate the bounds of the scaled character, calculate the offset and apply this.
currentBounds = path.GetBounds();
Matrix translationTransform = new Matrix();
translationTransform.Translate(targetRect.Left - currentBounds.Left, targetRect.Top - currentBounds.Top);
path.Transform(translationTransform);

//return the path.
return path;
}
}



As you might already know, one of the additions to Enterprise Library version 3 is the ability to manage configuration files from within the Visual Studio IDE.

In order to have both the existing configuration tool and the integrated editor for Visual Studio use the same logic under the covers EntLib 3 also introduces a new assembly called Microsoft.Practices.EnterpriseLibrary.Configuration.Design.UI. This assembly contains the functionality that is shared between the 2 tools.

Since this Configuration.Design.UI is contained in the package, let's have a look at the effort it takes to create your own user interface that leverages the EntLibs designtime nodes :-). I have to add that this never was a scenario for EntLib 3, again we might be abusing it in ways it is unanticipated for *evil grin*.

Now, why would this be usefull? well maybe you work with a company that uses EntLib inside their own framework and want a branded version of this tooling. I could also see this work inside installers (after deploying a website or service you might want to configure the application, right?)

So, let's start out with creating a winforms project. Add a panel (1), list-view (2) and property grid (3). Then add all the buttons and branding you feel is vital to this applications success (4) :-)


Next, let's add some references to this project. First add the:
Microsoft.Practices.EnterpriseLibrary.Configuration.Design.HostAdapter,
Microsoft.Practices.EnterpriseLibrary.Configuration.Design.UI and
Microsoft.Practices.EnterpriseLibrary.Configuration.Design

This should get us started with all of the generic designtime features EntLib provides. You should also add references to the designtime of each block you'd like to configure using this version of the tool. This means adding references to the <block> and <block.configuration.design> assemblies (or manually copy these assemblies into the \bin\ directory, since we wont be coding against those).
For example, to have this tool manage Validation configuration, add:
Microsoft.Practices.EnterpriseLibrary.Validation and
Microsoft.Practices.EnterpriseLibrary.Validation.Configuration.Design

I added all the assemblies from EntLibs bin-directory as a reference, that should give you all the designtime features the other tools have as well.

Since we have the references, we can start coding!

first, lets add a field of type SingleHierarchyConfigurationUIHostAdapater to our form. And initialize it in our constructor. The initialization code will instantiate our "ConfigurationHostAdapter", add the control it exposes to our form (inside the Panel we designed) and wire a couple of events

public partial class Form1 : Form
{
SingleHierarchyConfigurationUIHostAdapater configurationConsoleAdapter;

public Form1()
{
InitializeComponent();

HostAdapaterConfiguration adapterConfig = new HostAdapaterConfiguration(AppDomain.CurrentDomain.BaseDirectory);
configurationConsoleAdapter = new SingleHierarchyConfigurationUIHostAdapater(adapterConfig);
Panel1.Controls.Add(configurationConsoleAdapter.EditorControl);
configurationConsoleAdapter.EditorControl.Dock = DockStyle.Fill;

configurationConsoleAdapter.SelectionChanged += new EventHandler<SelectionChangedEventArgs>(configurationConsoleAdapter_SelectionChanged);
configurationConsoleAdapter.TasksChanged += new EventHandler<TasksChangedEventArgs>(configurationConsoleAdapter_TasksChanged);
configurationConsoleAdapter.DocumentClosed += new EventHandler<EventArgs>(configurationConsoleAdapter_DocumentClosed);
}

Cool, now for the code we want to execute on these events (I assume most of this is self-explanetory):

void configurationConsoleAdapter_DocumentClosed(object sender, EventArgs e)
{
Close();
}

void configurationConsoleAdapter_TasksChanged(object sender, TasksChangedEventArgs e)
{
listView1.Items.Clear();
foreach (Task t in e.Tasks)
{
listView1.Items.Add(new TaskViewItem(t));
}
}

void configurationConsoleAdapter_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
propertyGrid1.SelectedObject = e.SelectedComponent;
}

private class TaskViewItem : ListViewItem
{
public TaskViewItem(Task t): base(t.Message)
{
Tag = t;
}
}


Then, last -but not least - lets write the handlers that execute whenever the toolstrip-buttons "Open", "Save" or "Validate" are clicked:

private void openButton_Click(object sender, EventArgs e)
{
using (OpenFileDialog dialog = new OpenFileDialog())
{
if (dialog.ShowDialog() == DialogResult.OK)
{
configurationConsoleAdapter.Load(dialog.FileName);
}
}
}

private void saveButton_Click(object sender, EventArgs e)
{
using (SaveFileDialog dialog = new SaveFileDialog())
{
if (dialog.ShowDialog() == DialogResult.OK)
{
configurationConsoleAdapter.Save(dialog.FileName);
}
}
MessageBox.Show("Save completed");
}

private void validateButton_Click(object sender, EventArgs e)
{
configurationConsoleAdapter.Validate();
MessageBox.Show("validate completed");
}

Et voila, the result after this 15 minute excercise:

Then, order a couple of hundred thumb-drives. copy the tool on them and distribute them to your companies consultants for that unique corporate feel your company has! :-)

Attached you can find the configuration-tool in the screenshot.


Again i am very proud to have been part of the development team.

Tom's announcement: http://blogs.msdn.com/tomholl/archive/2007/04/05/just-released-enterprise-library-3-0-april-2007.aspx

Download at MSDN: http://www.microsoft.com/downloads/details.aspx?FamilyID=62ef5f79-daf2-43af-9897-d926f03b9e60&displaylang=en

 

 

Every once in a while, when advocating AOP, people ask me whether this programming technique is useful apart from stuff like logging, security, instrumentation, etc, etc.
Usually I answer that I wouldn’t know, but i do know that especially in enterprise application development there so many quality concerns similar to the above, that AOP can be considered just that and still very much is worth the effort.

Even though I usually take the easy way out, I strongly believe that AOP concept can be applied to more than logging.

In fact, one of the AOP examples that are often used is about a drawing application.

Consider the following object-oriented code:

 
Using aspect-oriented programming, the requirement above (updating the display) can defined separately from all the other functionality this fictitious application may provide.




Why is it so hard to come up with AOP examples that are *not* about our “usual suspects”?

Well, mainly because most of this is hidden in the domains you work in. Finding them requires knowledge of this specific domain and proper analysis and design. The domains I am familiar with are the generic requirements developers often face when writing software (logging, caching, security, exception handling, whatnot).

Eventually most of the domains have all sorts of requirements that apply to each other and can be separated from each other; helping us to make our designs clearer and structure our code better.