Question

I'm sending an email from my ASP.NET MVC app using the Spark View Engine based on this example by Andrew Kharlamov.

I've setup a unit test, CanSendEmail, but I need to specify the viewfolder in the config. I found the documentation here and the examples give this:

<spark>
  <views>
    <add name="{any-unique-name}" 
        folderType="FileSystem|EmbeddedResource|VirtualPathProvider|Custom"
        type="{name, assembly of IViewFolder type}"
        constuctor-param-names="values"
        subfolder="{optional subfolder to target}"/>
  </views>
</spark>

My question is this. Which folderType do I use and do I need any other parameters. My test product is call myProject.Tests and my web project containing the views is called myProject.Web with a Views folder in it.

Do I use FileSystem, VirtualPathProvider ... ?

Edit [14/11/2011]:

Okay I've got this in my app.config in myProject.Tests:

<views>
    <add name="web-view-folder"
                folderType="VirtualPathProvider"
                virtualBaseDir="~/Views"/>
</views>

I still get "View source file not found." when I run my test. I want the test to use the Views in myproject.Web.

Was it helpful?

Solution

My Solution

Based on the blog posts here and here, and with help from @RobertTheGrey and looking at the tests in the Spark source code, I ended up using ViewFolderType.FileSystem. That worked.

Here's the my code under test:

public string RenderEmailWithCustomViewFolder(string sparkViewName, ViewDataDictionary viewData, Dictionary<string, string> viewFolderParameters)
{
    var settings = new SparkSettings()
        .SetPageBaseType(typeof (SparkView))
        .AddViewFolder(ViewFolderType.FileSystem, viewFolderParameters)
        .AddAssembly("MvcContrib");

    var engine = new SparkViewEngine(settings);


    var sparkViewDescriptor = new SparkViewDescriptor().AddTemplate(sparkViewName);
    var view = (SparkView)engine.CreateInstance(sparkViewDescriptor);
    try
    {
        // Merge view data
        viewData.Keys.ToList().ForEach(x => view.ViewData[x] = viewData[x]);

        // Render the view to a text writer
        var writer = new StringWriter();
        view.RenderView(writer);
        return writer.ToString();
    }
    finally
    {
        engine.ReleaseInstance(view);
    }
}

And here's my test:

[Test]
public void Can_Render_Order_Confirmation_Email_With_Spark_View_Engine()
{
    // Arrange
    var order = OrderInstanceFactory.CreateTestOrder();
    order.ContactEmail = "test@testicle.com";
    var emailService = new EmailService();
    var viewData = new ViewDataDictionary();
    viewData["Order"] = order;
    const string viewFolder = @"../../../../app/myProject.Web/Views";
    var viewFolderParameters = new Dictionary<string, string> {{"basePath", viewFolder}};

    // Act
    var emailBody = emailService.RenderEmailWithCustomViewFolder("Email/OrderConfirmation.spark", viewData, viewFolderParameters);

    // Assert
    Assert.IsNotNull(emailBody);
    Assert.IsTrue(emailBody.Contains("test@testicle.com"));
}

My OrderConfirmation.spark template lives in my web products in the Views/Email/.

OTHER TIPS

If it's an ASP.NET MVC app, then you can use VirtualPathProvider since that hooks into the HttpContext and the rest of the runtime. You would use a FileSystemProvider if you were runnig it from a console app for example, or if you wanted to add a folder from outside your web app, perhaps because the templates were shared by other apps, but I've rarely seen that done.

Hope that helps...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top