Random Dev Notes

January 1, 2010

Using the Spark View Engine in a Desktop Application

Filed under: Development — Tags: — Tom Brothers @ 1:46 am

I recently decided to write a code generation application using the Spark View Engine.  I started off by reviewing the provided Samples Solution and found the EmailOrTextTemplating Project.  This Project seemed to be a perfect example of what I needed.  Using the DefaultMessageBuilder class as a starting point, I created a new WinForm Application which included a very simple template named MyTemplate.spark.  This file contained one expression “${MyText}”.  After creating the template file, I added a reference to Spark.dll and then I modified the Program file with the following:

using System;
using System.IO;
using System.Windows.Forms;
using Spark;
 
namespace SparkViewEngineTest {
    static class Program {
        [STAThread]
        static void Main() {
            SparkViewEngine engine = new SparkViewEngine();
 
            var descriptor = new SparkViewDescriptor().AddTemplate("MyTemplate.spark");
 
            MyTemplate view = (MyTemplate)engine.CreateInstance(descriptor);
            view.MyText = "blah";
 
            StringWriter sw = new StringWriter();
            view.RenderView(sw);
 
            MessageBox.Show(sw.ToString());
        }
    }
 
    public abstract class MyTemplate : AbstractSparkView {
        public string MyText { get; set; }
    }
}

When I ran the program I got an error indicating that the template file didn’t exist.  The path provided in the exception showed that the template file was expected to be found in a “Views” subfolder.  I thought that this was some weird constraint so I moved my file into a “Views” subfolder.  After moving the file I re-ran the application.  Then I got a new exception complaining about “’SparkViewBase’ does not exist in the namespace ‘Spark’”.  At this point I was wondering what the heck I missed.  So I went back to the ExmailOrTextTemplating Project to see what I overlooked.  After a little while I noticed that the web.config has some Spark specific settings.  The one setting that caught my attention was PageBaseType.  So I went back to my code and set the PageBaseType setting to the MyTemplate class.  This change corrected the last error.  Perfect, now I have some working code (or so I thought).

using System;
using System.IO;
using System.Windows.Forms;
using Spark;
 
namespace SparkViewEngineTest {
    static class Program {
        [STAThread]
        static void Main() {
            SparkViewEngine engine = new SparkViewEngine();
            engine.Settings.PageBaseType = typeof(MyTemplate).FullName;
    var descriptor = new SparkViewDescriptor().AddTemplate("MyTemplate.spark");
 
            MyTemplate view = (MyTemplate)engine.CreateInstance(descriptor);
            view.MyText = "blah";
 
            StringWriter sw = new StringWriter();
            view.RenderView(sw);
 
            MessageBox.Show(sw.ToString());
        }
    }
 
    public abstract class MyTemplate : AbstractSparkView {
        public string MyText { get; set; }
    }
}

With working code in hand, I created a Test Project and started writing some tests for my code generation templates.  Everything worked as expected.  Great.  Then I moved on to writing the rest of the code generation application.  During testing of the code generation application I received an exception when rendering the templates.  As it turns out, all my template testing up until this point was against template files using a relative path.  But my application was using full paths.  Not testing this scenario was clearly an oversight on my part… but who would have thought that this mattered…?

Ok… back to my Spark View WinForm Test Application.  When I tested a full path I got this exception.

image

Dang… using the Spark View Engine turned out to be a little more challenging than expected.  And what the heck is that exception all about…?  Alright, time to get the Spark View Engine source code to see if I can get some clues on how to resolve this issue.  After a little debugging, I traced the source of the exception back to ViewLoader.PartialViewFolderPaths.

image

I found that I could move the “if” statement above the two yield statements I no longer got this exception.  But modifying the source code and consequently having a custom build, of Spark.dll, as part of my code generation application was not what I wanted.  At this point I felt that the Sample Projects weren’t enough to help me get started.  So I did a search on stackoverflow and found this entry “Using Spark View Engine in a stand alone application.”  I found two things of interest on this page.  The first interesting thing was that there was apparently another sample project available for review.  Unfortunately though, this project was hidden in this source code solution and not part of the samples solution.  The second interesting think was that the example code was setting a ViewFolder property on the Spark View Engine.  Ah… finally… the missing link.

I changed my code to include setting the ViewFolder property and passed the AddTemplate the template file relative path then everything worked again.  This change also made it so that I no longer needed to put my template files in a Views folder as I’ve previously believed needed to be done.

using System;
using System.IO;
using System.Windows.Forms;
using Spark;
using Spark.FileSystem;
 
namespace SparkViewEngineTest {
    static class Program {
        [STAThread]
        static void Main() {
            FileInfo fi = new FileInfo(@"MyTemplate.spark");
            SparkViewEngine engine = new SparkViewEngine();
            engine.ViewFolder = new FileSystemViewFolder(fi.DirectoryName);
            engine.Settings.PageBaseType = typeof(MyTemplate).FullName;
            
            var descriptor = new SparkViewDescriptor().AddTemplate(fi.Name);
 
            MyTemplate view = (MyTemplate)engine.CreateInstance(descriptor);
            view.MyText = "blah";
 
            StringWriter sw = new StringWriter();
            view.RenderView(sw);
 
            MessageBox.Show(sw.ToString());
        }
    }
 
    public abstract class MyTemplate : AbstractSparkView {
        public string MyText { get; set; }
    }
}

** One thing to note… The ArgumentNullException was still thrown when a full path was passed  to AddTemplate.


Here is the code I ended up with after a little refactoring.

using System;
using System.IO;
using System.Windows.Forms;
using Spark;
using Spark.FileSystem;
 
namespace SparkViewEngineTest {
    static class Program {
        [STAThread]
        static void Main() {
            FileInfo fi = new FileInfo("MyTemplate.spark");
 
            using (SparkViewEngineHelper<MyTemplate> helper = new SparkViewEngineHelper<MyTemplate>(fi.Name)) {
                helper.View.MyText = "Blah";
                MessageBox.Show(helper.ToString());
            }
 
            using (SparkViewEngineHelper<MyTemplate> helper = new SparkViewEngineHelper<MyTemplate>(fi.FullName)) {
                helper.View.MyText = "Blah2";
                MessageBox.Show(helper.ToString());
            }            
        }
    }
 
    public abstract class MyTemplate : AbstractSparkView {
        public string MyText { get; set; }
    }
 
    public class SparkViewEngineHelper<T> : IDisposable
        where T : AbstractSparkView {
 
        private SparkViewEngine engine;
        public T View { get; private set; }
 
        public SparkViewEngineHelper(string templateFile) {
            this.View = this.CreateView(templateFile);
        }
 
        public void ToFile(string file) {
            File.WriteAllText(file, this.ToString());
        }
 
        public override string ToString() {
            StringWriter sw = new StringWriter();
            this.View.RenderView(sw);
            return sw.ToString();
        }
 
        private T CreateView(string templateFile) {
            FileInfo fi = new FileInfo(templateFile);
 
            if (!fi.Exists) {
                throw new FileNotFoundException(templateFile);
            }
 
            this.engine = new SparkViewEngine();
            this.engine.ViewFolder = new FileSystemViewFolder(fi.DirectoryName);
            this.engine.Settings.PageBaseType = typeof(T).FullName;
 
            SparkViewDescriptor descriptor = new SparkViewDescriptor().AddTemplate(fi.Name);
 
            return (T)engine.CreateInstance(descriptor);
        }
 
        void IDisposable.Dispose() {
            if (this.engine != null && this.View != null) {
                this.engine.ReleaseInstance(this.View);
            }
        }
    }
}

1 Comment »

  1. Many thanks Tom – that just helped me a lot getting Spark to work in a WinForms app.

    Comment by Jim — December 7, 2011 @ 4:11 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: