Marcin Drobik

software journeyman notes

Learning about JIT when using Markdown in RazorEngine

Context

When creating my blog engine, I wanted to write articles using Markdown syntax.

RazorEngine

The blog engine itself renders pages using RazorEngine. The basics are pretty easy:

  1. Install package:

    Install-Package RazorEngine
    
  2. Parsing the template:

    Razor.Parse(@"Hello @Model.Text" , new { Text = "World" })
    

MarkdownSharp

I decided to use MarkdownSharp to parse the Markdown content into HTML. Again, to get started:

  1. Install package:

    Install-Package MarkdownSharp
    
  2. Parsing the markdown:

    new MarkdownSharp.Markdown().Transform("# Hello World!")
    

Markdown inside Razor template

Things got strange when I wanted to use the MarkdownSharp inside Razor template. The template was:

@{
   var markdown = new MarkdownSharp.Markdown();
}

@Raw(markdown.Transform(Model.Content))

When I tried to parse it:

Razor.Parse(template, new { Content = "# Hello World!" }));

... I received following exception:

Unable to compile template. The type or namespace name 'MarkdownSharp' could not be found (are you missing a using directive or an assembly reference?)

The solution is to place some kind of reference to MarkdownSharp assembly in method that's executed before call to Razor.Parse, i.e:

var forceLoad = typeof(MarkdownSharp.Markdown);
Razor.Parse(template, new { Content = "# Hello World!" }));

Why the solution works?

First of all, I digged into RazorEngine source code and found that following method is used to feed compiler with assemblies:

public static IEnumerable<Assembly> GetLoadedAssemblies()
{
   return (IEnumerable<Assembly>)AppDomain.CurrentDomain.GetAssemblies();
}

I wrote a quick test to check if MarkdownSharp is loaded when there isn't any code that uses it:

static void Main( string [] args)
{
   Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.GetName().Name == "MarkdownSharp" ));
}

returned

False

Next, I added the the same code used in my solution:

static void Main( string [] args)
{
   Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.GetName().Name == "MarkdownSharp" ));
   var forceLoad = typeof(MarkdownSharp.Markdown);
   Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.GetName().Name == "MarkdownSharp" ));
}

This time I saw:

True

True

I suspected that the assembly was loaded into AppDomain only if referencing code was JITted. To test this hypothesis, I used the fact that JIT is performed per method, so I moved the typeof into separate method:

static void Main( string [] args)
{
   Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.GetName().Name == "MarkdownSharp" ));
   Load();
   Console.WriteLine(AppDomain.CurrentDomain.GetAssemblies().Any(assembly => assembly.GetName().Name == "MarkdownSharp" ));
}

private static void Load()
{
   var resolveToLoad = typeof(MarkdownSharp.Markdown);
}

This time, I saw:

False

True

Which proved my assumption and showed pretty nice how the JIT loads the assemblies.

References

comments powered by Disqus