How to change the base path in NitroNet for Sitecore

I'm currently involved in a Sitecore project that fully embraces NitroNet for Sitecore to integrate its frontend. So let's start this off with a bold statement, because - why not ¯\(ツ)

NitroNet for Sitecore is how frontends should be integrated in a modern Sitecore project.

No more recreating static HTML prototypes in razor views. No long hours of comparing markup between a pretty HTML preview provided by the frontend engineers and what actually gets rendered by the razor view engine from your view- and controller-renderings. With NitroNet for Sitecore we are able to use the handlebars templates directly.

By the way: if you are still using ASP.NET Web Forms - wow

via GIPHY

Show me the code

When using Sitecore Dependency Injection, the documentation here about changing the NitroNet base path is not totally honest with you, because this setting is not considered at all in the default NitroNetServicesConfigurator.cs class. So let's have a look at what I changed to make it work.

Make the base path configurable

I added a setting to the web.config file

<configuration>
  <appSettings>
    <add key="NitroNet.BasePath" value="[path of your choice]" />
  </appSettings>
</configuration>

Always consider and prefer using some sort of transformation, instead of changing the Sitecore web.config file directly.

Replace the registrations in the DI container

The base path is used in two places in NitroNet:

  • INitroNetConfig
  • IFileSystem

Both of them are registered as a Singleton in the services collection. You can either replace the NitroNetServicesConfigurator by removing the default DependencyInjection.config patch file and copy the code into your own class containing the change shown below, or replace just the affected registrations with an additional IServicesConfigurator like this:

public class ServicesConfigurator : IServicesConfigurator
{
    public void Configure(IServiceCollection serviceCollection)
    {
        var rootPath = HostingEnvironment.MapPath("~/");
        var basePath = PathInfo.Combine(PathInfo.Create(rootPath), PathInfo.Create(Settings.GetAppSetting("NitroNet.BasePath"))).ToString();

        var config = ConfigurationLoader.LoadNitroConfiguration(basePath);
        serviceCollection.Replace(ServiceDescriptor.Singleton(config));
        serviceCollection.Replace(ServiceDescriptor.Singleton<IFileSystem>(new FileSystem(basePath, config)));
    }
}

If you choose the approach above, don't forget to add it to the config and make sure you patch it after the default config file.

<configuration>
  <sitecore>
    <services>
      <configurator type="MyProject.ServicesConfigurator, MyProject" />
    </services>
  </sitecore>
</configuration>

Pitfalls and Learnings

  • I tried to use the Sitecore Settings instead of the <appSettings> first, but it seems to be to early in the Sitecore startup. So, <appSettings> it is.
  • Using this approach, the nitronet-config.json file needs to be where the base path is pointing to. But when using the solution shown here, you also have to have it in the web root too, because the default registration is happening first. Bummer. (but don't give up yet, there might be a solution soon. Keep reading...)
  • I did not know about the serviceCollection.Replace(...) option before. I was used to just register a service again to replace a previous one. But in this case, it will lead to having two Singletons of the same service registered. It did work, but it sure didn't feel right.

It's Open Source

It would have been nice if the provided NitroNetServicesConfigurator was more flexible in how it is getting the base path without replacing the entire class. Maybe even offer some extension points for the services it is registering.

Well, it's Open Source, so no whining is allowed. Let's improve it together. My pull request is waiting...