Paul Gielens:ThoughtsService

another Endpoint to my thoughts

News

Syndication

Ads


Favorites

Projects

August 2005 - Posts

Service Anti-Patterns, Command vs. Document Message

Via Arjen, Service Pattern and Anti-Patterns. While reading this article last night I got sucked into thinking about using a Document Message pattern:

 

1.)

[WebMethod()]

public FindCustomersByCountryResponse FindCustomersByCountry(FindCustomersByCountryRequest request)

{

       ..

}

 

vs a Comand Message pattern.

 

2.)

[WebMethod()]

public Customer[] FindCustomersByCountry(string country)

{

       ..

}

 

or

 

3.)

[WebMethod()]

public Customer[] FindCustomersByCountry(Country country)

{

       ..

}

 

Although EIP gives very clear guidance on when to use what, my experience is that most services based on Web Services technology use the Command Message pattern where services based upon MQ technology make good use out of both Message pattern styles. Why is that? Given the fact that services are build to last, I think I prefer, in the context of a Web Service, Document Messages and explicitly design a request/reply messages as if it is a Command Message. …and stay away from option 2 altogether.

 

Any thoughts?

*Update, Dutch .NET Developers Alliance

Early 2004 I called out to gather Dutch .NET bloggers in a single OPML file. I am pretty sure this helped the community to overcome and exceed the boundaries of great organizations (like dotNED and SDN) and the companies for which we work. A good example is the collaboration of several Dutch bloggers spreading Tech Ed 2005 news.

The list is still growing: Pieter de Bruin, Mark Willems, Ronald Lemmen, Maarten Mullender, Olaf Conijn, Teun Duynstee, Michiel van Otegem, Hassan Fadili, Martien van Steenbergen, Vincent Maas, Martijn Hoogendoorn, Scott van Vliet and Erwyn van der Meer.

Grab the OPML file here which contains allot of Dutch .Net developers. Are you a Dutch .Net developer and want your name on our list, drop a line pgielens@gmail.com

edit: included Scott van Vliet
edit2: included Erwyn van der Meer

Posted: Aug 13 2005, 11:18 AM by p.gielens | with 2 comment(s)
Filed under:
Simplified Enterprise Library Design-time Configuration Support

A while back I wrote an article on Extending the Enterprise Library Configuration Tool to maintain your Application Configuration. In this article I gave practical guidance in integrating your own configuration in the Enterprise Library Configuration Tool. The FomsDesignManagar class contained a lot of code which could be easily refactored into a base class. The same counts for the ConfigurationNode class. A copy paste version of the DesignManagerBase class.

 

public abstract class DesignManagerBase : IConfigurationDesignManager

{

       public DesignManagerBase()

       {

       }

 

       #region IConfigurationDesignManager Implementation

 

       public void Register(IServiceProvider serviceProvider)

       {

             RegisterCommands(serviceProvider);

       }

 

 

       public void Save(IServiceProvider serviceProvider)

       {

             ConfigurationContext configurationContext = ServiceHelper.GetCurrentConfigurationContext(serviceProvider);

 

             if (configurationContext.IsValidSection(GetSectionName()))

             {

                    ConfigurationNodeBase node = null;

 

                    try

                    {

                           IUIHierarchy hierarchy = ServiceHelper.GetCurrentHierarchy(serviceProvider);

                           node = hierarchy.FindNodeByType(GetConfigurationNodeType()) as ConfigurationNodeBase;

                           if (node == null)

                           {

                                  return;

                           }

 

                           object settings = node.GetSettings();

                           configurationContext.WriteConfiguration(GetSectionName(), settings);

                    }

                    catch (ConfigurationException e)

                    {

                           ServiceHelper.LogError(serviceProvider, node, e);

                    }

                    catch (InvalidOperationException e)

                    {

                           ServiceHelper.LogError(serviceProvider, node, e);

                    }

             }

       }

 

 

       public void Open(IServiceProvider serviceProvider)

       {

             ConfigurationContext configurationContext = ServiceHelper.GetCurrentConfigurationContext(serviceProvider);

 

             if (configurationContext.IsValidSection(GetSectionName()))

             {

                    ConfigurationNode node = null;

 

                    try

                    {

                           object settings = configurationContext.GetConfiguration(GetSectionName());

                           node = CreateConfigurationNode(settings);

                           ConfigurationNode rootConfNode = ServiceHelper.GetCurrentRootNode(serviceProvider);

                           rootConfNode.Nodes.Add(node);

                    }

                    catch (ConfigurationException e)

                    {

                           ServiceHelper.LogError(serviceProvider, node, e);

                    }

             }

       }

 

 

       public void BuildContext(IServiceProvider serviceProvider, ConfigurationDictionary configurationDictionary)

       {

             IUIHierarchy hierarchy = ServiceHelper.GetCurrentHierarchy(serviceProvider);

             ConfigurationNodeBase node = hierarchy.FindNodeByType(GetConfigurationNodeType()) as ConfigurationNodeBase;

 

             if (node != null)

             {

                    object settings = node.GetSettings();

                    configurationDictionary[GetSectionName()] = settings;

             }

       }

 

       #endregion

 

       protected virtual void RegisterCommands(IServiceProvider serviceProvider)

       {

              IUIHierarchyService hierarchyService = serviceProvider.GetService(typeof (IUIHierarchyService)) as IUIHierarchyService;

             IUIHierarchy currentHierarchy = hierarchyService.SelectedHierarchy;

             bool containsNode = currentHierarchy.ContainsNodeType(GetConfigurationNodeType());

             IMenuContainerService menuService = serviceProvider.GetService(typeof (IMenuContainerService)) as IMenuContainerService;

 

             ConfigurationMenuItem item = new ConfigurationMenuItem(

                    GetMenuItemText(),

                    new AddConfigurationSectionCommand(serviceProvider, GetConfigurationNodeType(), GetSectionName()),

                    ServiceHelper.GetCurrentRootNode(serviceProvider),

                    Shortcut.None,

                    GetStatusBarText(),

                    InsertionPoint.New);

 

             item.Enabled = !containsNode;

             menuService.MenuItems.Add(item);

       }

 

 

       protected abstract string GetSectionName();

       protected abstract string GetMenuItemText();

       protected abstract string GetStatusBarText();

       protected abstract ConfigurationNodeBase CreateConfigurationNode(object settings);

       protected abstract Type GetConfigurationNodeType();

}

 

A descendant should then implement the following methods:

 

protected abstract string GetSectionName();

protected abstract string GetMenuItemText();

protected abstract string GetStatusBarText();

protected abstract ConfigurationNodeBase CreateConfigurationNode(object settings);

protected abstract Type GetConfigurationNodeType();

 

And the ConfigurationNodeBase class.

 

public abstract class ConfigurationNodeBase : ConfigurationNode

{

       public abstract object GetSettings();

 

       [ReadOnly(true)]

       public override string Name

       {

             get { return base.Name; }

             set { base.Name = value; }

       }

 

 

       protected override void OnSited()

       {

             base.OnSited();

             Site.Name = GetComponentName();

       }

 

 

       protected abstract string GetComponentName();

}

 

Remember the bulky FormsDesignManager in the first article? This is what it looks like when inheriting the DesignManagerBase class.

 

public class FormsDesignManager : DesignManagerBase

{

       private static string MENUITEM_TEXT = "Formulieren Configuration";

       private static string STATUSBAR_TEXT = "Formulieren Configuration";

 

 

       public FormsDesignManager() : base()

       {

       }

 

       #region DesignManagerBase Implementation

 

       protected override string GetSectionName()

       {

             return FormsSettings.SectionName;

       }

 

 

       protected override ConfigurationNodeBase CreateConfigurationNode(object settings)

       {

             return new FormsSettingsNode((FormsSettings) settings);

       }

 

 

       protected override Type GetConfigurationNodeType()

       {

             return typeof (FormsSettingsNode);

       }

 

 

       protected override string GetMenuItemText()

       {

             return MENUITEM_TEXT;

       }

 

 

       protected override string GetStatusBarText()

       {

             return STATUSBAR_TEXT;

       }

 

       #endregion

}

 

Accompanied by the FormsSettingsNode class.

 

public class FormsSettingsNode : ConfigurationNodeBase

{

       private FormsSettings settings;

 

 

       public FormsSettingsNode() : base()

       {

             settings = new FormsSettings();

       }

 

 

       public FormsSettingsNode(FormsSettings settings) : base()

       {

             this.settings = settings;

       }

 

 

       public string FilePath

       {

             get { return settings.FilePath; }

             set { settings.FilePath = value; }

       }

 

 

       public string SecureFilePath

       {

             get { return settings.SecureFilePath; }

             set { settings.SecureFilePath = value; }

       }

 

 

       public FormDataList Forms

       {

             get { return settings.Forms; }

       }

 

 

       [Browsable(false)]

       public virtual FormsSettings FormsSettings

       {

             get { return settings; }

       }

 

       #region ConfigurationNodeBase Implemenation

 

       public override object GetSettings()

       {

             return settings;

       }

 

 

       protected override string GetComponentName()

       {

             return "Formulieren Configuration";

       }

 

       #endregion

}

 

These base classes keep the complexity and code duplication out of your design-time custom configuration classes. Comments?

Posted: Aug 12 2005, 09:24 AM by p.gielens | with 2 comment(s)
Filed under:
contrib: Neo support for Distributed Transactions

Late June 2004 I submitted Declarative transactions at method level to the Neo team. It took a while to digest the code but as of today you’ll find it in CVS. Of course it will be available in the next release as well. My first post on this subject was focused on the API which is now available in Neo. In this post I’ll briefly explain what happens behind the scenes. Erik concluded that since transactions are almost completely orthogonal to Neo, the transaction support code should be optional to Neo. The Trampoline Pattern provides the solution to fit the transaction support code in the Neo framework:

public ICollection SaveChangesTransactionAware()

{

       ContextSaveWrapper csw = new ContextSaveWrapper();

       return csw.SaveChanges(this);

}

 

 

[TransactionAware]

private class ContextSaveWrapper : ContextBoundObject

{

       [RequiresTransaction(TransactionOption.Supported)]

       public ICollection SaveChanges(ObjectContext context)

       {

              return context.SaveChanges();

       }

 

}

As can be seen in this listing is that the ContextSaveWrapper.SaveChanges “bounces back” to ObjectContext.SaveChanges with changed behavior, which is in this case transaction awareness. The ObjectContext isn’t interested in the transaction outcome and will simply forward.

So how is this made possible?

A TransactionAware Neo domain object now derives from ContextBoundObject so it can participate in distributed COM+ transactions. Below is the listing of the TestComponent class as it can be found in the unit tests. Behind the scenes all method calls are directed to the TransactionSink which inspects the attributes set on the executing method. The TransactionSink then decides which TransactionEnviroment to initiate. In case of the TransactionOption.Required the method execution is delegated to the NewTransactionRequiredEnviroment. The NewTransactionRequiredEnviroment will then invoke the method and place its vote for the transaction outcome. Actually, underneath the EnterpriseServices infrastructure is used to set the COM+ object context flag bits.

[TransactionAware]

public class TestComponent : ContextBoundObject

{

       public bool wasInTransaction;

       public Guid transactionId;

       public Guid innerTransactionId;

 

       public void NonTransactionalMethod()

       {

              // this will raise an exception, nothing gets printed

              Console.WriteLine(ContextUtil.ActivityId);

       }

 

       [RequiresTransaction(TransactionOption.Required)]

       public void DoSomethingTransactional()

       {

              wasInTransaction = ContextUtil.IsInTransaction;

              transactionId = ContextUtil.TransactionId;

       }

 

       [RequiresTransaction(TransactionOption.RequiresNew)]

       public void DoSomethingTransactionalWithNewTransaction()

       {

              wasInTransaction = ContextUtil.IsInTransaction;

              transactionId = ContextUtil.TransactionId;

       }

 

       [RequiresTransaction(TransactionOption.NotSupported)]

       public void DoSomethingThatDoesNotSupportTransactions()

       {

              wasInTransaction = ContextUtil.IsInTransaction;

       }

 

       [RequiresTransaction(TransactionOption.Disabled)]

       public void DoSomethingThatDisablesTransactions()

       {

              wasInTransaction = ContextUtil.IsInTransaction;

       }

 

       [RequiresTransaction(TransactionOption.Required)]

       public void DoSomethingInNestedTransaction(string methodName)

       {

              transactionId = ContextUtil.TransactionId;

              TestComponent inner = new TestComponent();

              inner.GetType().InvokeMember(methodName, BindingFlags.InvokeMethod, null, inner, null);

              innerTransactionId = inner.transactionId;

       }

 

}

Want to see more? The TransactionSink and ExecutionEnviroment implementation can be found in the Neo.Core.Transactions namepace.

Posted: Aug 09 2005, 09:37 PM by p.gielens | with 1 comment(s)
Filed under: ,
In the footsteps of Afra

Today I got a whopping 4-digit passing score on my 70-315 MCP exam. Sure, I used brain dumps to get in shape as well as reading this book, having great meals… study group meetings at the office and a couple of years experience under my belt. I studied previous/old exams to get my BSc  Information Technology certificate. So does this make my BSc worthless as well, since many people feel MCP’s are?

The other day I received an email from our office stating:

Certification difficult?

This mail referred to the achievement made by the very talented Arfa Karim Randhawa. Should I now feel bad about myself because of not being certified (which is history of today)? Does this make my certification effort less important?

With me being certified, I finally earn the right to participate in the certification discussion.

More Posts