Click here to Skip to main content
15,884,986 members
Articles / Desktop Programming / XAML

WF4 Custom activities for message mediation

Rate me:
Please Sign up or sign in to vote.
4.98/5 (25 votes)
20 Dec 2012CPOL24 min read 108.2K   2K   72  
This article describes a design, implementation, and usage of custom message mediation activities for a XAML workflow.
//*****************************************************************************
//    Description.....WF4 Message Mediation Library
//                                
//    Author..........Roman Kiss, rkiss@pathcom.com
//    Copyright © 2009 ATZ Consulting Inc. (see included license.rtf file)         
//                        
//    Date Created:    07/07/09
//
//    Date        Modified By     Description
//-----------------------------------------------------------------------------
//    07/07/09    Roman Kiss     Initial Revision
//
//*****************************************************************************
//
#region Namespaces
using System;
using System.Activities;
using System.Activities.Presentation.PropertyEditing;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.Xml.Linq;
#endregion

namespace RKiss.MessageMediationActivityLibrary
{
    public sealed class XPathMessageInspector : CodeActivity
    {
        private IDictionary<string, OutArgument> outputs;
        private bool deserializeMessage = false;
       
        #region Properties  
        [Category("Input")]
        [RequiredArgument]
        public InArgument<string> XPath { get; set; }

        [Category("Input")]
        [RequiredArgument]
        public InOutArgument<Message> Message { get; set; }

        [DefaultValue(null)]
        public Dictionary<string, string> Namespaces { get; set;}
   
        [Category("Result")]
        [Browsable(true)]
        [Editor(typeof(RKiss.MessageMediationActivityLibrary.Editors.DynamicArgumentDictionaryEditor), typeof(PropertyValueEditor))]       
        public IDictionary<string, OutArgument> Outputs
        {        
            get
            {
                if (this.outputs == null)
                {
                    this.outputs = new Dictionary<string, OutArgument>();
                }
                return this.outputs;
            }
        }
        
        [Browsable(false)]
        public string SourceUri { get; set; }
        #endregion

        public XPathMessageInspector()
        {
            this.Namespaces = new Dictionary<string, string>();
        }

        #region Execute
        protected override void Execute(CodeActivityContext context)
        {
            Message message = this.Message.Get(context);
                string xpath = this.XPath.Get(context);
                object result = null;

                this.deserializeMessage = (xpath.IndexOf(":Body") > 0);

                // namespaces
                PropertyInfo pi = typeof(EnvelopeVersion).GetProperty("Namespace", BindingFlags.Instance | BindingFlags.NonPublic);
                string envelopeNamespace =  (string)pi.GetValue( message.Version.Envelope, null);

                pi = typeof(AddressingVersion).GetProperty("Namespace", BindingFlags.Instance | BindingFlags.NonPublic);
                string addressNamespace = (string)pi.GetValue(message.Version.Addressing, null);
              
                XPathMessageContext contextExt = new XPathMessageContext();
                contextExt.AddNamespace("s", envelopeNamespace);
                contextExt.AddNamespace("a", addressNamespace);

                if (this.Namespaces != null)
                {
                    foreach (var param in this.Namespaces)
                    {
                        string prefix = param.Key;
                        string ns = param.Value;
                        if (string.IsNullOrEmpty(prefix) || string.IsNullOrEmpty(ns)) continue;
                        contextExt.AddNamespace(prefix, ns);
                    }
                }

                bool bIsResult = this.Outputs.ContainsKey("_result");
                Type argumentType = bIsResult ? this.Outputs["_result"].ArgumentType : typeof(XPathResult);               
                Type valueType = argumentType == typeof(string) ? argumentType : typeof(XPathResult);

                XPathMessageQuery query = new XPathMessageQuery(xpath, contextExt);
                Type type = typeof(XPathMessageQuery);
               
                #region xpath evaluation
                if (this.deserializeMessage || message.Version == MessageVersion.None)
                {
                    MethodInfo mi = type.GetMethod("Evaluate", new Type[] { typeof(MessageBuffer) }).MakeGenericMethod(valueType);

                    // copy message
                    using (MessageBuffer buffer = message.CreateBufferedCopy(Int32.MaxValue))
                    {
                        this.Message.Set(context, buffer.CreateMessage());
                        result = mi.Invoke(query, new object[] { buffer });
                    }
                }
                else
                {
                    MethodInfo mi = type.GetMethod("Evaluate", new Type[] { typeof(Message) }).MakeGenericMethod(valueType);
                    result = mi.Invoke(query, new object[] { message });
                }
                #endregion

                bool bResultDone = false;
                if (result is XPathResult)
                {
                    var xr = result as XPathResult;
                    if(xr.ResultType == System.Xml.XPath.XPathResultType.Error)
                        throw new NullReferenceException("XPathResult: the expression doesn't evaluate to the correct XPath type");
                    if (xr.ResultType == System.Xml.XPath.XPathResultType.NodeSet || xr.ResultType == System.Xml.XPath.XPathResultType.NodeSet)
                    {
                        var nav = xr.GetResultAsNodeset();
                        if (nav == null)
                            throw new NullReferenceException("XPathResult: Result is not Nodeset");
                        if (nav.Count == 0)
                            throw new NullReferenceException(string.Format("XPathResult: No match for '{0}'", xpath));

                        nav.MoveNext();
                        if (nav.Current != null && (nav.Current.NodeType == System.Xml.XPath.XPathNodeType.Element || nav.Current.NodeType == System.Xml.XPath.XPathNodeType.Root))
                        {
                            var root = XElement.Parse(nav.Current.OuterXml);
                            if (root == null)
                                throw new NullReferenceException("XPathResult: Cannot create root XElement from result");

                            #region all outputs
                            foreach (var param in this.Outputs)
                            {
                                if (bIsResult && param.Key == "_result")
                                {
                                    if (argumentType == typeof(XElement) || argumentType == typeof(object))
                                        this.Outputs["_result"].Set(context, root);
                                    else if (argumentType == typeof(XPathResult))
                                        this.Outputs["_result"].Set(context, result);
                                    else
                                    {
                                        Type argType = this.Outputs[param.Key].ArgumentType;
                                        string res = (result as XPathResult).GetResultAsString();
                                        if (string.IsNullOrEmpty(res) && argType != typeof(string))
                                            throw new ArgumentNullException("XPathResult: the value is null or empty");
                                        this.Outputs[param.Key].Set(context, Convert.ChangeType(res, argType));
                                    }
                                    bResultDone = true;
                                }
                                else if (param.Key == "_root")
                                {
                                    this.Outputs["_root"].Set(context, root);
                                }
                                else
                                {
                                    var xname = XName.Get(param.Key);
                                    var element = root.Name == xname ? root : root.Element(XName.Get(param.Key));                                  
                                    if (element != null)
                                    {
                                        if (element.HasElements || element.HasAttributes)
                                            this.Outputs[param.Key].Set(context, element);
                                        else
                                        {
                                            Type argType = this.Outputs[param.Key].ArgumentType;
                                            this.Outputs[param.Key].Set(context, argType == typeof(object) ? element.Value : Convert.ChangeType(element.Value, argType));
                                        }
                                    }
                                }
                            }
                            #endregion
                        }
                    }
                }
                if (bIsResult && bResultDone == false)
                {
                    this.Outputs["_result"].Set(context, result);
                }
        }
        #endregion
    }

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions