LINQ to XML - creating an XML file from data collection

One of the final requirements for our MAMLConverter project is to output the processed html tags (which resides in a List<ElementEnt> collection) and generate a XML file from it. 

Our Data Layer (of type IHTMLData) has a SaveData() method which does the job nicely using LINQ to XML:

public bool SaveData(List<ElementEnt> dataList)

{

    // TODO: Use filename (xml extension) of file submitted to workflow

    string fileName = "temp.xml";

 

    var xml = new XElement("developerConceptualDocument",

            new XAttribute("snlmx", Resources.snlmx),

            new XAttribute("snlmx_xlink", Resources.snlmx_xlink),

        (from d in dataList

        where d.MAMLTag != null  && !d.IsIgnore  && !d.IsCloseTag

        select new XElement(d.MAMLTag, d.Content)));

 

    // Final cleanup.  LINQ XML complains if we attempt to use

    // xmlns as a tag so we'll resolve after it is done above.

    xml.ToString()

        .Replace("snlmx_xlink", "xmlns:xlink")

        .Replace("snlmx", "xmlns")

        .StrToFile(fileName);

 

    // TODO: Remove - FOR DEVELOPMENT PURPOSES

    Process.Start(fileName);

    return true;

}
The data structure it has to work with follows:

 

 

[TestMethod]

public void TestSaveProcessedListAsXML()

{

    BootStrapper bootStrap = new BootStrapper();

    string fileName = string.Format(mockFileName, CurrentDir);

 

    IHTMLData dll = bootStrap.UnityContainer.Resolve<IHTMLData>();

    if (dll.LoadData(fileName))

    {

        MAMLState state = bootStrap.UnityContainer.Resolve<MAMLState>();

        state.HtmlData = dll.GetHtmlData();

 

        using (MAMLWorkflowRuntime wfrt =

            new MAMLWorkflowRuntime(bootStrap.UnityContainer))

        {

            wfrt.Start(typeof(HtmlToMAML));

            Assert.IsTrue(dll.SaveData(wfrt.State.Data.HtmlData)); 

            Assert.AreEqual(22, wfrt.State.Data.HtmlData.Count); 

        }

    }

    else

        Assert.Fail(dll.Exception.Message);

 

    Assert.Fail("Keep Unit Test checked for development");

}

Note below that we only have a few tags currently defined (resource file and TagCommands) so we still have some work to do.  We'll also have to do some special post processing but for the most part have the core requirement's infrastructure in place.  I've been able to complete the input/output of data easily/efficiently because of LINQ to XML.

 BEFORE

AFTER
 


Tags: , , ,
Categories: LINQ | MAML | Workflow


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Unity - factory pattern and extensibility

The Unity and Workflow infrastructure, created for the MAMLConverter application, provides an extensible framework.  For example, to add a new HTML tag (for conversion to MAML) a developer only has to update the Resource file, add the new Tag<newTag>Command.cs file, compile and deploy.   An excerpt from the TagH2Command.cs command follows:

namespace Workflow.Library.TagCommands

{

    /// <summary>

    /// H2 tag

    /// </summary>

    public class TagH2Command : TagCommandBase

    {

        /// <summary>

        /// Executes this instance.

        /// </summary>

        public override void Execute()

        {

            // TODO: support attributes

            MAMLTag = Resources.h2;

        }

    }

Unity simplifies matters, we don't have an actual Factory class however we do have a class used to register the ITagCommands that will be used by Unity to resolve the concrete class. 

As each html tag hits the ElementProcessorActivity (in a ReplicatorActivity) it request the MAMLTag from the service.

The service turns to Unity to resolve the ITagCommand for the specified htmlTag

/// <summary>

/// Gets the MAML tag.

/// </summary>

/// <param name="htmlTag">The HTML tag.</param>

/// <returns></returns>

public string GetMAMLTag(string htmlTag)

{

    // We'll use the unity container as a factory

    ITagCommand TagCommand;

 

    // Ensure we have a configured ITagCommand - workaround:

    // http://www.codeplex.com/unity/WorkItem/View.aspx?WorkItemId=1991

    try

    {

        TagCommand = UnityContainer.Resolve<ITagCommand>(htmlTag);

        TagCommand.Execute();

    }

    catch

    {

        return htmlTag;

    }

    return TagCommand.MAMLTag;

}

 


Tags: , ,
Categories: Unity | Workflow


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Workflow - separation of concerns

I'm enjoying workflow emmensely, I particularly like that we're forced to code in a manner that has us focus on the concerns of the Activity's Use Case.

For example the TagProcessorActivity and ElementProcessorActivity represented below:

Each of the above activities (pointed to by arrows) have a CodeActivity, SetCurrentElementCode and HtmlTagCode respectively; these code activities have a sole purpose in life.   The HtmlTag's purpose is to update/set the MAMLTag property to the value returned by the ProcessorService (service is set in SequenceActivityBase via Unity container).

The TagProcessorActivity (executes first) has the sole responsibility of setting the current element; the ReplicatorActivity provides us a CurrentIndex to notify us of our position in the Replicator list.  The TagProcessorActivity uses a method on our DataState object (of type IMAMLState) to update our state object; an excerpt from the MAMLState class follows:

/// <summary>

/// Sets the current element.

/// </summary>

/// <param name="activity">The activity.</param>

/// <returns></returns>

public ElementEnt SetCurrentElement(Activity activity)

{

    if (activity == null || activity.Parent ==null)

        return null;

    if (!(activity.Parent.Parent != null

            && activity.Parent.Parent is ReplicatorActivity))

        return null;

 

    ReplicatorActivity grandParent =

        activity.Parent.Parent as ReplicatorActivity;

    ElementBeingProcessed = grandParent.CurrentIndex;

    CurrentElement = (ElementEnt)

        grandParent.InitialChildData[grandParent.CurrentIndex];

    return CurrentElement;

}

Note: the [Sequence]ActivityBase is responsible for setting up the Activity so that the state is available; an excerpt from the ActivityBase follows:

protected override void OnActivityExecutionContextLoad(IServiceProvider provider)

{

    IWFState<IMAMLState> State;

    base.OnActivityExecutionContextLoad(provider);

    State = provider

        .GetService(typeof(IWFState<IMAMLState>)) as IWFState<IMAMLState>;

    Logger = State.UnityContainer.Resolve<ILoggerFacade>();

    ProcessorService = State.UnityContainer.Resolve<ITagProcessorService>();

    DataState = State.Data;

 

    WireupActivity(this);

}

 

At each level of processing there is a clear, testable separation of concern.

 

Source code available at http://www.Codeplex.com/MAMLConverter


 


Tags: ,
Categories: MAML | Unity | Workflow


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Workflow - Replicator activity event processing different

The ReplicatorActivity does not respect the base class wireup events as it's Activity and SequenceActivity counterparts do.  This BLOG demonstrates how we can hook into the current activity's Status Change event. 

Note in the following Log activity that the LogMAMLConverterStarted events are firing where the  LogTagProcessorStarted events are not - these activities are both LoggerActivity and share the same baseclass.

Debug(None): !! ACTIVITY WIREUP LogMAMLConverterStarted
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(None): ==> LogMAMLConverterStarted STATUS CHANGE - Status: Executing  Result: None
Debug(None): ==> LogMAMLConverterStarted EXECUTING:
Debug(None): MAML Converter Workflow Started
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): No HTML Tag
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [html]
Debug(None): MAML Tag set by service [htmlMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [head]
Debug(None): MAML Tag set by service [headMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [Untitled 1]
Debug(None): Processing HTML Tag [title]
Debug(None): MAML Tag set by service [titleMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [title]
Debug(None): MAML Tag set by service [titleMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [head]
Debug(None): MAML Tag set by service [headMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [body]
Debug(None): MAML Tag set by service [bodyMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [Welcome to the MAMLConverter Guide. This reference will help you understand and use this utility]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [What is MAMLConverter]
Debug(None): Processing HTML Tag [h2]
Debug(None): MAML Tag set by service [h2MAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [h2]
Debug(None): MAML Tag set by service [h2MAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [The MAMLConverter is a utility that will allow you to create your help documents with your favorite editor (this utility was created using Expression Web content) and convert them to MAML]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [Example]
Debug(None): Processing HTML Tag [h2]
Debug(None): MAML Tag set by service [h2MAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [h2]
Debug(None): MAML Tag set by service [h2MAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [The following & HTML ]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [Will be converted to ]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [p]
Debug(None): MAML Tag set by service [pMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [body]
Debug(None): MAML Tag set by service [bodyMAML]
Debug(None): !! ACTIVITY WIREUP LogTagProcessorStarted
Debug(None): !! ACTIVITY WIREUP LogCurrentContent
Debug(None): !! ACTIVITY WIREUP LogNoHtmlTag
Debug(None): !! ACTIVITY WIREUP LogHasHtmlTag
Debug(None): !! ACTIVITY WIREUP LogMAMLTag
Debug(None): !! ACTIVITY WIREUP elementProcessorActivity1
Debug(None): !! ACTIVITY WIREUP tagProcessorActivity
Debug(High): Tag processor started
Debug(None): Content being processed [<Empty Line>]
Debug(None): Processing HTML Tag [html]
Debug(None): MAML Tag set by service [htmlMAML]
The thread '<No Name>' (0x1420) has exited with code 0 (0x0).

See http://www.CodePlex.com/MAMLConverter for source

 


Tags: , ,
Categories: MAML | Workflow


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

LINQ - Projection eases parsing HTML content into data collection

In regards to my http://www.CodePlex.com/MAMLConverter project I have completed the Workflow infrastructure (integrated Unity and logging).  The next requirement is to pass the Workflow a collection of HTML data so that it can translate HTML tags to MAML tags.   The entity I'm going to start with follows:

namespace Workflow.Library.Entities

{

    public class ElementEnt

    {

        public bool IsCloseTag { get; set; }

        public string Tag { get; set; }

        public int TagLen { get; set; }

        public int Len { get; set; }

        public string Content { get; set; }

        public string OriginalContent { get; set; }

    }

}

This Use Case requirement will have me convert the following HTML into a List<ElementEnt> collection:

With the help of my StringExtensions class (many of the extensions written specifically for this task) I'm able to get my results with the query that follows:

Now all that remains is to populate my List<ElementEnt> collection.   LINQ Projection makes this task easy with the few following code changes:

All that remains is to move this code into its own class and create the Unit Test.  I'll then be ready to create the Workflow activities that will handle each of the tags.

String Extensions source follows:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.IO;

using System.Web;

 

namespace Workflow.Library.Extensions

{

    public static class StringExtensions

    {

        /// <summary>

        /// HTMLs the decode.

        /// </summary>

        /// <param name="data">The data.</param>

        /// <returns></returns>

        public static string HtmlDecode(this string data)

        {

            return HttpUtility.HtmlDecode(data);

        }

        /// <summary>

        /// HTMLs the encode.

        /// </summary>

        /// <param name="data">The data.</param>

        /// <returns></returns>

        public static string HtmlEncode(this string data)

        {

            return HttpUtility.HtmlEncode(data);

        }

 

 

        /// <summary>

        /// Gets the length of the tag.

        /// </summary>

        /// <param name="da">The da.</param>

        /// <returns></returns>

        public static int GetTagLength(this string da)

        {

            int offsetSP = da.IndexOf(' ');

            int offset = da.IndexOf('>');

            if (offsetSP > 0 && offsetSP < offset)

                offset = offsetSP;

            if (offset < 1)

                offset = da.Length;

            //return offset;

            return offset;

        }

 

        /// <summary>

        /// Gets the tag.

        /// </summary>

        /// <param name="da">The da.</param>

        /// <returns></returns>

        public static string GetTag(this string da)

        {

            int offset = GetTagLength(da);

            string retValue = da.Substring(0, offset);

            if (retValue.StartsWith("/"))

                retValue = retValue.Substring(1);

            if (retValue.EndsWith(">"))

                retValue = retValue.Substring(0, retValue.Length - 1);

            return retValue;

        }

 

        /// <summary>

        /// Gets the content.

        /// </summary>

        /// <param name="da">The da.</param>

        /// <returns></returns>

        public static string GetContent(this string da)

        {

            int offset = da.GetTagLength() + 1;

            if (offset >= da.Length)

                return "";

            else

                return da.Substring(offset);

        }

 

 

        /// <summary>

        /// Send string to specified filename

        /// </summary>

        /// <param name="data"></param>

        /// <param name="fileName"></param>

        /// <returns></returns>

        public static bool StrToFile(this string data, string fileName)

        {

            //Check if the sepcified file exists

            if (System.IO.File.Exists(fileName) == true)

            {

                // If so then Erase the file first as in this case

                // we are overwriting

                System.IO.File.Delete(fileName);

            }

 

            //Create the file if it does not exist and open it

            FileStream oFs = new

                FileStream(fileName, FileMode.CreateNew, FileAccess.ReadWrite);

 

            //Create a writer for the file

            StreamWriter oWriter = new StreamWriter(oFs);

 

            //Write the contents

            oWriter.Write(data);

            oWriter.Flush();

            oWriter.Close();

 

            oFs.Close();

 

            return true;

        }

 

        /// <summary>

        /// Return file contents as string

        /// </summary>

        /// <param name="cFileName"></param>

        /// <returns></returns>

        public static string FileToStr(this string cFileName)

        {

            //Create a StreamReader and open the file

            StreamReader oReader = System.IO.File.OpenText(cFileName);

 

            //Read all the contents of the file in a string

            string lcString = oReader.ReadToEnd();

 

            //Close the StreamReader and return the string

            oReader.Close();

            return lcString;

        }

    }

}

 


Tags: , , ,
Categories: MAML


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Unity - a Workflow Trojan Horse

Workflow is very powerful but I felt crippled without the Unity Container that I've come to depend on heavily in any application, no matter how large or small.   Case in point a new utility I'm working on to convert HTML to MAML so that I can take advantage of Sandcastles Help File Builder's  ConceptualContent which consist of MAML formated help files (no HTML).  Workflow seems optimal for this purpose.  The first requirement is (was) to plug in a Unity Container.

Workflow does offer the ability to register services that can be accessed from within activities, all that is required is to set an ExternalDataExchange attribute on your interface:

[ExternalDataExchange]

public interface IWFState<T>

{

    T Data { get; set; }

    IUnityContainer UnityContainer { get; set; }

    ILoggerFacade Logger { get; set; }

    void WireupActivity(Activity activity);

}

Then you load the service

public IWFState<T> State

{

    get { return _state; }

    set

    {

        _state = value;

        OnStateSet();

    }

}
/// <summary>

/// Loads the local services.

/// </summary>

public virtual void LoadLocalServices()

{

    ExternalDataExchangeService localServices = 
         new ExternalDataExchangeService();

    AddService(localServices);

    localServices.AddService(State);

}

 

However, this requires a redundant registration process (since I've already registered services with Unity).   I decided to use Unity as a trojan horse; I'll load one service, my state object which contains my UnityContainer, and then use my existing services via a UnityContainer property.  Important note:  some activities, i.e., Replicator and While will have to serialize referenced objects; any interfaces that Unity has to resolve in these activities will have to have [Serializable] attributes;

This permits my Activity to look as follows (ActivityBase has a UnityContainer property that returns State.UnityContainer):

namespace MAMLConvert.Activities.Logger

{

    /// <summary>

    /// Debug Logger

    /// </summary>

    public partial class LoggerDebugActivity : ActivityBase

  {

    public LoggerDebugActivity()

    {

      InitializeComponent();

    }

        protected override ActivityExecutionStatus

            Execute(ActivityExecutionContext executionContext)

        {

            UnityContainer.Resolve<ILoggerFacade>().Log(

                "Logging via Unity in the Activity!",

                    Category.Debug, Priority.None);

 

            return base.Execute(executionContext);

        }

  }

}

/// <summary>

/// Tests the workflow base ensure args is set on empty constructor.

/// </summary>

[TestMethod]

public void TestMAMLWorkflowBaseStartsAssignedWorkflow()

{

    using (MAMLWorkflowRuntime wfrt = new MAMLWorkflowRuntime())

    {

        Assert.IsNotNull(wfrt.Container);

        Assert.IsTrue(wfrt.Args.Count > 0, 
               "Should contain at least a UnityContainer");

        Assert.AreEqual("Initialized", wfrt.State.Data.MockInfo);

        Assert.AreEqual(wfrt.State.Logger.GetType().FullName,

            MockContainer.Resolve<ILoggerFacade>().GetType().FullName);

 

        wfrt.Start(typeof(HtmlToMAML));

    }

}

 

The above unit test yields the following results: 

 

Debug(None): !! ACTIVITY WIREUP loggerDebug
Debug(None): !! ACTIVITY WIREUP loggerTrace
Debug(None): !! ACTIVITY WIREUP loggerMessageBox
Debug(None): !! ACTIVITY WIREUP loggerEmail
Debug(None): !! ACTIVITY WIREUP Logger
Debug(None): ==> Logger STATUS CHANGE - Status: Executing  Result: None
Debug(None): ==> Logger EXECUTING:
Debug(None): ==> loggerDebug STATUS CHANGE - Status: Executing  Result: None
Debug(None): ==> loggerDebug EXECUTING:
Debug(None): Logging via Unity in the Activity!
Debug(None): ==> loggerDebug STATUS CHANGE - Status: Closed  Result: Succeeded
Debug(None): ==> loggerDebug CLOSED:
Debug(None): ==> Logger STATUS CHANGE - Status: Closed  Result: Succeeded
Debug(None): ==> Logger CLOSED:

 

Source code available at http://www.CodePlex.com/MAMLConverter
 


Tags: , ,
Categories: MAML | Unity | Workflow


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

Entity Framework - how to use stored procedures (made easy) SP1

I'll show two ways to use stored procedures for updating data using the Entity Framework; first I'll show the "built-in" way and then I'll show my preferred way using Extensions (provided by Microsoft). 

Entity Framework with .NET 3.5 and VS 2008 SP1 

To easily configure your model to use stored procedures right click on the Entity and select "Stored Procedure Mapping". 

You'll then click to the right of the <Select Insert Function> and point it to the stored procedure that you want to use (all imported stored procedures will show in the list).   Do the same for the Update and Delete functions.

Note:  During compile VS complained because I didn't have an Insert function (my Update stored procedure handles the uniqueness constraints internally; it does both insert and update).   I had to create a stub stored procedure and update my model to make it happy

Once your stored procedures are mapped you can do the following to add and commit changes

[TestMethod]

public void User_CanAddUserToTable()

{

    User usr = new User();

    usr.ID = -1;

    usr.FirstName = "Jane";

    usr.LastName = "Doe";

    usr.LoginName = "JaneDoe";

    db.AddToUser(usr);

    db.SaveChanges(true);

}

I ran the test a second time to ensure my stored procedure was being run; I knew it was because I didn't have a duplicate record; I have built in uniqueness constraints on LoginName - inserts become updates if LoginName already exist.

Updating Entity Framework using EF Extensions

I won't duplicate what was a very comprehensive blog HERE which has download link.  Once I followed the steps provided I was able to update my Unit Test to look as follows:

[TestMethod]

public void User_CanAddUserToTable()

{

    object[] parameters =

    {   

        new SqlParameter("ID",-1),

        new SqlParameter("FirstName","John"),

        new SqlParameter("LastName","Doe"),

        new SqlParameter("LoginName","JohnDoe")

    };

 

    DbCommand command = db.CreateStoreCommand("uspUser_Update",

        CommandType.StoredProcedure, parameters);

 

    using (db.Connection.CreateConnectionScope())

    {

        int retValue = (int)command.ExecuteScalar();

    }

}

 


Tags: ,
Categories: Entity Framework


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

MEF - CompositeWPF under one roof

MEF and the CompositeWPF both offer distinct and very valuable services.  MEF allows us to easily create Add-in components and the CompositeWPF makes it easy to decouple our services and views.   Today I started integrating the two (reference MEF forum message).

Note: I am currently working on the Proof-Of-Concept (POC), when I have it completed it I will start TDD and refactor it as applicable.  See FLASH DEMO HERE   FULL SOURCE HERE (7meg) see notes under image.

My objective will be to make it as simple as possible to implement the integration without making any changes to the CompositeWPF or MEF libraries - all of the wiring up will be done in the MEFContrib.Library project.

Below you'll see the only code required in the App.xaml.cs code behind file:

Notice that I have the MEF, CompositeWPF and Unity source code under SRC - these are the complete source code packages.  When the smoke settles I'll only upload DLLs, for now it will be helpful to step into code when it comes time to refactor.

Above the Parts folder contains MEF parts, they are compiled to the bin\Extensions folder.  The bootstrapper references our MEFContrib.Library.

The bootstrapper code that pertains to the CompositeWPF follows below.  The LoadReferencedModules  class below tells the CompositeWPF to load all modules referenced by the BasicWPFApp - in our case it will be the RSSFeed module that I copied/pasted from a CompositeWPF demo I wrote earlier.

namespace MEFContrib.Library.Base
{
    public class MEFBootStrapper : UnityBootstrapper
    {
        private Assembly _assembly;

        private Application _application;
        private MEFCompositionContainer _container;
 
/// <summary>
/// CompositeWPF
/// </summary>
/// <returns></returns>
protected override DependencyObject CreateShell()
{
    _application.MainWindow.Show();
    return _application.MainWindow;
}
 
/// <summary>
/// CompositeWPF
/// </summary>
/// <returns></returns>
protected override IModuleEnumerator GetModuleEnumerator()
{
    Container.RegisterType<ILogger, TraceToolLogger>();
 
    return LoadReferencedModules.GetModules(
        _application.MainWindow.GetType());
}
 
 
/// <summary>
/// MEF
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public MEFBootStrapper(object sender, BootStrapperEventArgs e)
{
    _application = sender as Application;
    _assembly = e.Assembly;
 
    _application.Exit += new ExitEventHandler(_application_Exit);
 
    if (Compose())
        Run();
    else
        _application.Shutdown();
}

The Window1.xaml.cs code-behind file contains an earlier POC so I left it as is.  Note there are no references to the MessageBoxLogger nor DebugLogger in our BasicWPFApp.  MEF will load whatever it finds in the bin\extensions folder which happens to contain these two logging features.

The Windows XAML below has two region names "MainRegion" and "MainView". 

<Window x:Class="BasicWPFApp.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:cal="http://www.codeplex.com/CompositeWPF"
    Title="Window1" Height="400" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="25"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
 
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="2*" />
        </Grid.ColumnDefinitions>
 
        <StackPanel Orientation="Horizontal" Grid.ColumnSpan="2">
            <TextBox Name="textBox1" Width="120">Hello World</TextBox>
            <Button Name="button1"  Width="57" Click="button1_Click">Debug</Button>
            <Button Name="button2" Width="55" Click="button2_Click">MB</Button>
        </StackPanel>
        <GridSplitter Grid.Row="1" Width="10"/>
        <ItemsControl Grid.Row="1" Name="MainRegion"  
                      cal:RegionManager.RegionName="MainRegion" Margin="0,0,6,0">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <DockPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
 
        <ItemsControl Grid.Row="1" Grid.Column="1" Name="MainView"  
                      cal:RegionManager.RegionName="MainView">
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <DockPanel/>
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>
</Window>

When the RSSFeed module loads it will populate the MainRegion with the RSSFeedView, which in turn will populate the MainView RSSViewer.

namespace RSSFeed
{
    [Module(ModuleName = "RSSFeedModule")]
    public class RSSFeedModule : ModuleBase
    {
        /// <summary>
        /// Injection Constructor
        /// </summary>
        /// <param name="regionManager">Registered IRegionManager</param>
        /// <param name="container">Registered IUnityContainer</param>
        /// <param name="presenter">Registered IMainPresenter</param>
        public RSSFeedModule(IRegionManager regionManager,
            IUnityContainer container)
        {
            RegionManager = regionManager;
            Container = container;
        }
 
        protected override void RegisterViewsAndServices()
        {
            base.RegisterViewsAndServices();
 
            // Add view to region
            IRegion mainRegion = RegionManager.Regions["MainRegion"];
 
            // Name it so we can move it later in MainController.cs
            mainRegion.Add(Container.Resolve<RSSFeedView>(), "RssFeed");
        }
 
 
        public override void Initialize()
        {
            base.Initialize();
        }
    }
}

Tags: ,
Categories: CompositeWPF | MEF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

WPF - setting background color of control programmatically

Searching for a way to set the background color of a WPF control programmatically seemed like more of an adventure then it should have been; there are sure a lot of complicated ways to set a background color.   Reluctant to believe that it was this complicated I kept searching until I found it.

txtStatus.Foreground = new SolidColorBrush(Colors.White);
txtStatus.Background = new SolidColorBrush(Colors.Red);


Tags: ,
Categories: WPF


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know

TypeMock - Stub for CASK application

The CASK application will rely heavily on TypeMock as TDD moves forward.  This could cause a problem for folks who don't use TypeMock and download the source code - it won't compile. 

I've created a TypeMock "stub" that I will update as the test get more advanced; currently the stub will permit the CASK application to compile without error.   To simplify matters for those, like myself, who will be using TypeMock, I will place all affected Unit Test in a TypeMock.Tests folder - this way we can easily remove the reference from the stub and assign it to the actual TypeMock application.


Tags: ,
Categories: CASKDotNet | TypeMock


Actions: E-mail | Permalink |  Grammar/Typo/Better way? Please let me know