Umbraco 10 - Razor Class Library Packages Pt3
Tags: umbraco
Published: 2022-06-18 09:18:40


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: 
- [Part 1: Intro to Razor class library packages in Umbraco] (https://dev.to/kevinjump/umbraco-10-razor-class-library-packages-pt1-3nfa)
- [Part 2: Creating an Umbraco Razor class library package] (https://dev.to/kevinjump/umbraco-10-razor-class-library-packages-pt2-58an)
- Part 3: Converting an existing Umbraco package (this)
- [Part 4: Things I now do differently] (https://dev.to/kevinjump/umbraco-razor-class-library-packages-pt4-15f4) 🌟 New 🌟

---


## 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 : 
```xml
<Project Sdk="Microsoft.NET.Sdk">
```
### to : 
```xml
<Project Sdk="Microsoft.NET.Sdk.Razor">
```

## 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. 

```xml
<StaticWebAssetBasePath>App_Plugins/MyPackage</StaticWebAssetBasePath>
```

## 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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cj506yha9mw6irhaizbv.png)

## 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](https://dev.to/kevinjump/umbraco-10-razor-class-library-packages-pt2-58an) 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: 

```cs
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"
     }
  });
 }
}
```

### Method 2 - load an embedded package.manifest file
[Jason Elkin did most of the work here (and above)](https://www.youtube.com/watch?v=Pxs5YNiKG4s) - 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 :

```cs
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;
        }
    }
}
```

and passing it into the parser : 

```cs 
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);
        }
    }
}
```