DEV Community

Kevin Jump
Kevin Jump

Posted on • Edited on

Umbraco 10 - Razor Class Library Packages Pt3

Previously we have looked at what Razor class libraries are and how you can use them to build new Umbraco packages, Now we are going to go over the steps you can take to convert an existing Umbraco package to use Razor class libraries :


This post is part of a series:


1. Convert your csproj file.

First thing we need to do is convert our project from an 'standard' c# library to a razor class library project.

change :

<Project Sdk="Microsoft.NET.Sdk">
Enter fullscreen mode Exit fullscreen mode

to :

<Project Sdk="Microsoft.NET.Sdk.Razor">
Enter fullscreen mode Exit fullscreen mode

2. Add A StaticWebAssetsBasePath value

By default all Razor Class library files will be served into the root of wwwroot folder of your project - but the StaticWebAssetBasePath value in the csproj file lets you change this to something more like what Umbraco expects for a package.

<StaticWebAssetBasePath>App_Plugins/MyPackage</StaticWebAssetBasePath>
Enter fullscreen mode Exit fullscreen mode

3. Remove the build .targets from the project

Using a RCL you no longer need the .targets file that forms part of how packages work in Umbraco so you can:

  • delete the build folder from your solutions
  • remove the 'build' elements from the csproj file.

When you are done with the .csproj file it should look something like this :

Finished .csproj example

4. Rename your existing app_plugins/myproject folder

While Razor class library assets can be made to look like they are not in the root of wwwroot. The files themselves must be in a wwwroot frolder of the library. So we need to rename/move our folder

Files should be moved from /app_pluigns/mysuperproject to /wwwroot inside your package project

5. Load the package.manifest in code

One last thing we have to do is tell umbraco how to load the package.manifest.

Soon 🤞 we should get something Umbraco codebase that means package.manifest files will be picked up by Umbraco and we won't need to do either of the methods below - but as of v10.0.0 of Umbraco you have to do this

At the moment - You need to programmatically load the package via a Manifest filter. We covered this in part 1 but to quickly go over it here.

Method 1 - define the package manifest in code

you need a to load your package manifest via a composer: and you can define it all in code if that is easier for you:

public class StyledTextComposer : IComposer
{
    public void Compose(IUmbracoBuilder builder)
    {
        builder.ManifestFilters().Append<MyManifestFilter>();
    }
}

internal class MyManifestFilter: IManifestFilter
{
 public void Filter(List<PackageManifest> manifests)
 {
   manifests.Add(new PackageManifest
   {
     PackageName = "MyPackage",
     Scripts = new []
     {
       "/App_Plugins/MyPackage/my.controller.js"
     },
     Stylesheets = new []
     {
       "/App_Plugins/MyPackage/mystyles.css"
     }
  });
 }
}
Enter fullscreen mode Exit fullscreen mode

Method 2 - load an embedded package.manifest file

Jason Elkin did most of the work here (and above) - but if you want (and this is easier for more complex package.manifest files with property editors and default values in them) - You can embedd your package manifest as a resource in your project and then load it in and use the existing package parsers in Umbraco to load it.

You can see how Jason has done this in his repo here:
https://github.com/JasonElkin/Umbraco-Together-RCL-Demo-Package/tree/main/src/FontAwesome5Picker/Startup

the clever bit (well its all quite clever!) is reading the resource :

using System.IO;
using System.Reflection;

namespace FontAwesome5Picker.Startup
{
    public class ManifestReader
    {
        public static string ReadManifest()
        {
            var assembly = Assembly.GetExecutingAssembly();
            var resourceName = "package.manifest";

            using Stream stream = assembly.GetManifestResourceStream(resourceName);
            using StreamReader reader = new(stream);
            string result = reader.ReadToEnd();

            return result;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

and passing it into the parser :

using System.Collections.Generic;
using Umbraco.Cms.Core.Manifest;

namespace FontAwesome5Picker.Startup
{
    public class ManifestFilter : IManifestFilter
    {
        private readonly IManifestParser parser;

        public ManifestFilter(IManifestParser parser)
        {
            this.parser = parser;
        }

        void IManifestFilter.Filter(List<PackageManifest> manifests)
        {
            var manifestJson = ManifestReader.ReadManifest();
            var manifest = parser.ParseManifest(manifestJson);
            manifest.PackageName = "Font Awesome 5 Picker";

            manifests.Add(manifest);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)