Excluding node_modules folder from ASP.NET compilation

We started to make use of using Github URLs as npm dependencies (make sure to reference specific commits to ensure repeatable builds) to replace some JavaScript files that we had manually added to the project. Unfortunately one of the repositories we added contains an invalid razor view file (.cshtml), which causes razor view compilation to fail with the following error.

/temp/node_modules/ace-builds/demo/kitchen-sink/docs/razor.cshtml(6): error ASPPARSE: Encountered end tag "a" with no matching start tag.  Are your start/end tags properly balanced?

Razor view compilation failure caused by the node_modules folder is a bit of a recurring issue I have had. In the past I had been able to solve the problem by upgrading npm, but that was not going to work this time. What I needed to do was to get the ASP.NET compiler to ignore the node_modules folder.

The view compilation was configured in the .csproj file using the AspNetCompiler task e.g.

This results in a command like the following being executed during the build process.

C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_compiler.exe -v temp -p D:\repos\onemodel\webapp

If you run aspnet_compiler.exe with the help toggle you will see that there is a flag (-x) that can be used to exclude directories. Frustratingly there is no way to provide values to this flag using the provided AspNetCompiler task. Instead you need to use the Exec task to call aspnet_compiler.exe so you can pass in a value for node_modules. Replacing the AspNetCompiler task with Exec ends up like the following example.

The downside of this solution is that it is reliant on the aspnet_compiler executable always being in the same location, however that could probably be dynamically determined with some more MSBuild configuration.

Advertisements
Excluding node_modules folder from ASP.NET compilation

Redirecting HTTP requests to use HTTPS in IIS behind an Elastic Load Balancer

There are plenty of examples of using the URL Rewrite module to redirect HTTP requests to use HTTPS instead in IIS, however they all seem to rely on checking the {HTTPS} IIS server variable to determine if the request used HTTPS or not. If your IIS server is behind an Elastic Load Balancer in AWS HTTPS requests are converted to HTTP at the load balancer and the previous examples do not work.

Instead of checking the {HTTPS} variable you can instead look for the custom header X-Forwarded-Proto that Elastic Load Balancer adds with the protocol used between the client and the load balancer. You can configure this behaviour by adding the following rule into the <system.webServer> <rewrite> <rules> section of your web.config.

Redirecting HTTP requests to use HTTPS in IIS behind an Elastic Load Balancer

Revisiting ASP.NET compiler error caused by node_modules and Visual Studio

The first time I saw this issue was prior to npm version 3 being installed with Node.js. I wrote about it then and it continues to be one of my most popular postsThe latest version of Node.js includes version 3 of npm (and has for a while now), which stores modules in a flat structure to fix the Windows file name limit. I thought this would be the end of this

ASPRUNTIME: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

ASP.NET compiler error, but it has occurred since so it is time to revisit it.

The latest appearances have been on developer’s machines, not the build server. Our build server uses npm version 3 and has not had any issues since I updated it to that. Investigating the errors revealed that once again the node_modules were nested, but the developer’s had the latest version of Node.js installed and running npm proved that it was version 3.

The problem was that Visual Studio had installed the node_modules using its own version (older) of npm. The solution in these cases was to delete the node_modules folder and issue the “npm install” command manually through a command prompt.

It’s frustrating that Visual Studio is still using an older version of npm, especially since the flattening of the node_modules folder was done to benefit Windows users. If you wish to still install modules through Visual Studio you may want to investigate http://jameschambers.com/2015/09/upgrading-npm-in-visual-studio-2015/ and http://scottaddie.com/2015/08/16/npm-vs-windows-max_path-limitation/.

Revisiting ASP.NET compiler error caused by node_modules and Visual Studio

ASP.NET compiler error caused by node_modules

Update: I have revisited this issue, because Visual Studio still uses an old version of npm and installs the modules in a nested structure. You can edit the version of npm Visual Studio uses or run the npm install commands yourself to prevent this issue.

Problem

Recently our build server (AppVeyor) encountered an error while compiling our application.

ASPRUNTIME: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

Initially I was confused, because the build had succeeded locally, so I began researching to determine what had happened. First I googled the error to see if any of the top search results were similar circumstances. Luckily for me John Reilly had blogged about the issue and that also made me remember previously reading about node module nesting causing issues. We have some node modules installed and it seemed a possible culprit. I updated my local modules and when I rebuilt the project I encountered the error too, confirming the node modules as the cause.

Attempted Solution

My first thoughts on how to resolve the error was to configure the ASP.NET compiler to ignore the node_modules directory. The node_modules directory is not required as part of the ASP.NET compile process (for us at least), so it seemed sensible that the compiler should ignore it. Unfortunately I did some research and I could discover a possible way of doing this.

Solution

After trying to have the compiler ignore the node_modules directory, I decided to upgrade to npm version 3. I knew that version 3 featured a flatter dependencies structure, which would fix the problem of long file paths being caused by nested dependencies. Be aware that upgrading npm on Windows involves some manual configuration, see here. After I upgraded and reinstalled the modules the build was succeeding again locally.

Configuring the build server to use npm 3 was fairly straight forward. The build server was already scripted to call “npm install”, I simply had to update the script to install npm 3 beforehand. The install script ended up becoming as follows.

Solution Analysis

Upgrading npm resolved the build error, but it didn’t really resolve the problem. Even though we specify the versions of the modules we depend on those modules can have their own dependencies and may not specify the exact version they depend on. This potential variance in builds is undesirable. It may result in errors such as this scenario initially occurring on the build server or worse, the build could be successful with some subtle variance in the results produced.

I happened to discus this scenario with Joshua Wulf and he mentioned that he’d heard a talk that recommended that all node modules be committed into your project’s source control. I haven’t done any further research on this yet, but I think this is something we will have to take up. The build process be repeatable (i.e. the same output should be produced every time the same commit is built) and using npm to fetch the node modules breaks this.

Additional Research

I actually did some additional investigation, in between discovering the node modules were causing the build error and resolving the error. I wanted to know why the ASP.NET compiler was even looking at the node_modules directories. First I enabled diagnostic logging of MSBuild as shown in the following screenshot.

diagnostic msbuild

With the additional diagnostic data I could see that the error occurred in the MvcBuildViews target. The diagnostic data also gave me the aspnet_compiler.exe command that was being run. I took this command and ran it manually adding the “-errorstack” option to it as well. This gave me the following stack trace.

error ASPRUNTIME: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.

[PathTooLongException]: The specified path, file name, or both are too long. The fully qualified file name must be less than 260 characters, and the directory name must be less than 248 characters.
at System.IO.PathHelper.GetFullPathName()
at System.IO.Path.NormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
at System.IO.Path.GetFullPathInternal(String path)
at System.Web.Hosting.MapPathBasedVirtualPathEnumerator..ctor(VirtualPath virtualPath, RequestedEntryType requestedEntryType)
at System.Web.Hosting.MapPathBasedVirtualPathCollection.System.Collections.IEnumerable.GetEnumerator()
at System.Web.Compilation.BuildManager.PrecompileWebDirectoriesRecursive(VirtualDirectory vdir, Boolean topLevel)

at System.Web.Compilation.BuildManager.PrecompileWebDirectoriesRecursive(VirtualDirectory vdir, Boolean topLevel)
at System.Web.Compilation.BuildManager.PrecompileAppInternal(VirtualPath startingVirtualDir, IEnumerable`1 excludedVirtualPaths)
at System.Web.Compilation.BuildManager.PrecompileApp(VirtualPath startingVirtualDir, IEnumerable`1 excludedVirtualPaths)
at System.Web.Compilation.BuildManager.PrecompileApp(ClientBuildManagerCallback callback, IEnumerable`1 excludedVirtualPaths)
at System.Web.Compilation.BuildManagerHost.PrecompileApp(ClientBuildManagerCallback callback, List`1 excludedVirtualPaths)
at System.Web.Compilation.BuildManagerHost.PrecompileApp(ClientBuildManagerCallback callback, List`1 excludedVirtualPaths)
at System.Web.Compilation.ClientBuildManager.PrecompileApplication(ClientBuildManagerCallback callback, Boolean forceCleanBuild)
at System.Web.Compilation.ClientBuildManager.PrecompileApplication(ClientBuildManagerCallback callback)
at System.Web.Compilation.Precompiler.Main(String[] args)

I’ve cut out a several levels of recursive calls to the BuildManager PrecompileWebDirectoriesRecursive method. From the stack trace I started to look at the source code for some of the classes and methods on referencesource, but I decided I was getting sidetracked by my curiosity and start working on solving the error before I could understand why the ASP.NET compiler looks at the node_modules directory. If anyone knows what the compile was doing, I’d be interested to know.

ASP.NET compiler error caused by node_modules