Spying on Razor View Compilation

Wednesday, February 3, 2016 by K. Scott Allen

Sometimes the best way to understand code is to compile and execute the code. In this scenario I needed to understand a bit more about view compilation in ASP.NET Core. Here is a simple spy to track the file information and compilation results for each razor view.

public class RazorCompilationServiceSpy : IRazorCompilationService
{
    private IRazorCompilationService _inner;
    private IList<CompileEntry> _log;

    public RazorCompilationServiceSpy(ICompilationService compilationService,
                                      IMvcRazorHost razorHost, 
                                      IOptions<RazorViewEngineOptions> options)
    {
        _inner = new RazorCompilationService(compilationService, razorHost, options);
        _log = new List<CompileEntry>();
    }

    public CompilationResult Compile(RelativeFileInfo fileInfo)
    {
        var result = _inner.Compile(fileInfo);
        _log.Add(new CompileEntry { FileInfo = fileInfo, Result = result });
        return result;
    }

    public IEnumerable<CompileEntry> CompilationLog
    {
        get
        {
            return _log;
        }
    }

    public class CompileEntry
    {
        public RelativeFileInfo FileInfo { get; set; }
        public CompilationResult Result { get; set; }
    }
}

The easiest way to grab information from the class is to register the class as a singleton during Startup::Configure.

 services.AddSingleton<IRazorCompilationService, RazorCompilationServiceSpy>();

Note that the real RazorCompilationService runs as a transient service in a typical ASP.NET application, but for this simple experiment we are ignoring all the terrible threading problems that might arise using singletons and regular collection classes like a List<T>.

Inside a Razor view we can use the following code to see the compilation results.

@using Microsoft.AspNet.Mvc.Razor.Compilation;

@inject IRazorCompilationService CompilationSpy

@functions {
    public RazorCompilationServiceSpy GetCompilationSpy()
    {
        return (RazorCompilationServiceSpy)CompilationSpy;
    }
}

<section>
    <h3>Compilation Results</h3>

    @foreach (var result in GetCompilationSpy().CompilationLog)
    {
        <h4>@result.FileInfo.RelativePath</h4>
        <pre>@result.Result.CompiledContent</pre>

    }

</section>

Which yields output like the following:

image

Serving Up node_modules In ASP.NET

Tuesday, February 2, 2016 by K. Scott Allen

The wwwroot folder in ASP.NET isn't the only place for static files. Briefly, in haiku form:

Serve files from anywhere

Configure static file middleware

Each provider thaws the frozen bits of winter


Recently, I wanted to serve files from both wwwroot and node_modules, so I used code like the following in the Startup class:

// this will serve up wwwroot
app.UseFileServer();

// this will serve up node_modules
var provider = new PhysicalFileProvider(
    Path.Combine(environemnt.ApplicationBasePath, "node_modules")
);
var options = new FileServerOptions();
options.RequestPath = "/node_modules";            
options.StaticFileOptions.FileProvider = provider;
options.EnableDirectoryBrowsing = true; 
app.UseFileServer(options);

 

Note that the UseFileServer method installs static files, default files, and directory browser middleware with a single method call.

You could also use the same technique to serve files from bower_components. Personally, I've stopped using bower and install all client assets using npm for various reasons (including the simplicity, and also Typescript's ability to find modules in node_modules).

A Different Perspective on ASP.NET Middleware

Monday, February 1, 2016 by K. Scott Allen

When I was a boy, my parents would select a weekend every late summer to freeze corn for our Sunday meals in the winter months. The process started early in the morning when dad would drive us to a local farm. We’d purchase a few hundred ears of un-shucked corn and load the corn into our own laundry baskets to bring them home.

Once home, we’d setup a processing pipeline for the corn. I was first in the pipeline. I’d pick an ear from the basket, shuck off the squeaky green husk, and hand the ear to mom. Mom would gently remove silk from the cob with a soft vegetable brush and not so gently eradicate damaged kernels with a palm-sized paring knife. My mom passed the corn to my dad, who would bundle up a dozen or so ears and drop them into boiling water. After a few minutes of blanching, my dad would transfer the hot corn into an ice bath and then pass the ears back up the pipeline to my mom.

Mom would use a simple device my father made to help cut the corn from the cob. The device was a small hardwood board, about ½ inch thick, with a nail through the middle. Pushing the cob onto the nail made for easier cutting with a boning knife, as the cob would stand up without the need to place any fingers in the cutting area. Mom could then sweep the cut kernels off the board and into a bowl where it was my responsibility to measure 2 cups of corn into freezer bags, and keep count of the total number of bags.

Allen Family Middleware For Corn Processing

The corn started with me un-husked and returned to me as whole cut kernels in puddle of sweet, milky juice. Well, not all the corn made the entire trip up and down the family food processing line. If I spotted an obviously bad ear, I always had the option of throwing the ear away instead of passing the ear to mom.

Substitute “HTTP request” for corn and “middleware component” for me, mom, and dad, and you’ll have an idea of how the middleware pipeline works in ASP.NET. Each component has a job to perform when the component receives a request. Each component can perform some work and optionally pass the request to the next component. Each HTTP transaction can visit each piece of middleware once on the way in, and once on the way out.

HTTP Processing Middleware

Now that I’ve made the analogy, it’s hard to look at any Startup.cs and not think about being a boy again in August.

Working With Typed Headers in ASP.NET

Monday, November 30, 2015 by K. Scott Allen

Inside of a controller in ASP.NET 5, the Request and Response properties both give you access to a Headers property. Headers is a simple IHeaderDictionary and will ultimately hand out string values.

Bring in the Microsoft.AspNet.Http namespace and you'll find a GetTypedHeaders extension method available for both Request and Response. Instead of working with raw strings, this extension method allows you to work with classes like MediaTypeHeaderValue, proper numbers, and strong types in general. 

var requestHeaders = Request.GetTypedHeaders();
var responseHeaders = Response.GetTypedHeaders();

var mediaType = requestHeaders.Accept[0].MediaType;
long? length = responseHeaders.ContentLength;

// ...

What Every JavaScript Developer Should Know About ECMAScript 2015

Monday, November 23, 2015 by K. Scott Allen
What Every JavaScript Developer Should Know About ECMAScript 2015

Now available on Amazon, What Every JavaScript Developer Should Know About ECMAScript 2015 is the book I'd like to read about the new features in the JavaScript language. The book isn't a reference manual or an exhaustive list of everything in the ES2015 specification. Instead, I purposefully selected what I think are the important features we will use in everyday programming. I expect the reader will already have a good understanding of the pre-2015 JavaScript language.

The book will be free for the rest of this week.

Chapters include:

  • Working with variables and parameters
  • Classes
  • Functional features
  • Asynchronous JavaScript
  • Modules
  • APIs

Special thanks to Ruben Bartelink and Porter T. Baer for feedback on the early drafts.

An ASP.NET 5 Overview Video

Thursday, November 12, 2015 by K. Scott Allen

I recorded an ASP.NET 5 Overview during some unexpected free time and placed the video here on OdeToCode. I recorded during the beta6 / beta7 timeframe, so the video will need some updates in the future, else you'll find two vast and trunkless legs of stone here.

image

The Evolution of JavaScript

Tuesday, November 10, 2015 by K. Scott Allen

I fired off an abstract titled The Evolution of JavaScript without giving a thought as to what it means for a language to evolve. After all, a language is not a living organism where Mother Nature applies the dispassionate sieve of natural selection against the replication errors in DNA. Wouldn’t a programming language rather fall under the viewpoint of intelligent design?

How can intelligent design explain the gap?

image

There is no formula to apply in moving a language forward. There is emotion, beliefs, and marketability. When the committee abandoned the 4th edition of the language, the language found diversity in pockets of community. jQuery showed us how programming the DOM can work when the API is consistent. Node showed us how to scale JavaScript and run outside 4-sided HTML elements. The cosmic impact of Steve Jobs exterminated natural predators, allowing natives like threads and sockets to emerge.

JavaScript is not a flat road in a planned community at the edge of the water. JavaScript is a Manhattan boulevard serving the enterprise and the pedestrian, angled to equal the constraints of terra firma. Always busy, bustling, dirty, and full of diversity, we can only hope the future doesn’t move too fast. Slow evolution has been good despite the frustrations. Don't listen to the slander, coriander, and mind the gap.

Pluralsight Courses
What JavaScript Developers Should Know About ECMAScript 2015
The Podcast!