HttpResponseTransformer 1.0.1.13

dotnet add package HttpResponseTransformer --version 1.0.1.13
                    
NuGet\Install-Package HttpResponseTransformer -Version 1.0.1.13
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="HttpResponseTransformer" Version="1.0.1.13" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="HttpResponseTransformer" Version="1.0.1.13" />
                    
Directory.Packages.props
<PackageReference Include="HttpResponseTransformer" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add HttpResponseTransformer --version 1.0.1.13
                    
#r "nuget: HttpResponseTransformer, 1.0.1.13"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package HttpResponseTransformer@1.0.1.13
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=HttpResponseTransformer&version=1.0.1.13
                    
Install as a Cake Addin
#tool nuget:?package=HttpResponseTransformer&version=1.0.1.13
                    
Install as a Cake Tool

HttpResponseTransformer

Build Publish NuGet Version

An ASP.NET Core library for injecting customizable transforms into the HTTP response pipeline. This library enables dynamic modification of HTTP responses, with specialized support for HTML document manipulation and content injection.

Motivation

This library was built with Jellyfin plugins in mind, since the plugin API doesn't expose any UI capabilities. However, it is a general-purpose tool for use in any ASP.NET Core application and has no Jellyfin dependencies.

Note: Modifying the HTML files directly in the filesystem is not recommended, especially if being deployed via docker.

Installation

dotnet add package HttpResponseTransformer

Quick Start

Add the response transformer to the IServiceCollection, and configure any transforms.

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseTransformer(builder => builder
        .TransformDocument(config => config
            .InjectScript(script => script
                .FromUrl("https://cdn.example.com/script.js")
                .At("//head")
                .AsAsync())
            .InjectStyleSheet(css => css
                .FromUrl("https://cdn.example.com/styles.css")
                .At("//head"))));
}

Jellyfin Plugins

To use HttpResponseTransformer in a Jellyfin plugin, implement IPluginServiceRegistrator and add response transformer to the service collection.

public class PluginServiceRegistrator : IPluginServiceRegistrator
{
    public void RegisterServices(IServiceCollection serviceCollection, IServerApplicationHost applicationHost)
    {
        serviceCollection.AddResponseTransformer(config => config
            .TransformDocument(injectPage => injectPage
                .When(ctx => ctx.Request.Path == "/web")
                .InjectScript(script => script
                    .FromEmbeddedResource($"{GetType().Namespace}.scripts.my-custom-script.js", GetType().Assembly)
                    .AsDeferred())));
    }
}

Response Pipeline

HttpResponseTransformer integrates into the ASP.NET Core's middleware pipeline to intercept and transform HTTP responses. Filters determine whether transforms should run (IResponseTransformer.ShouldTransform, or builder.When() for injection transforms). When a transform executes, the response stream is buffered in memory and transformed by IResponseTransformer.ExecuteTransform() before being returned to the client.

Important: Transforms buffer the entire response stream in memory. Care should be taken when working with large documents or streaming content. ShouldTransform() or builder.When() should be used to target specific requests and avoid unnecessary buffering.

Response Compression

By default, HttpResponseTransformer bypasses response compression when executing a transform by temporarily clearing the Accept-Encoding HTTP header.

This behavior can be disabled by calling AllowResponseCompression().

services.AddResponseTransformer(builder => builder
    .AllowResponseCompression()
    .TransformDocument(config => config
        ...
    ));

Warning: When response compression is enabled, transforms should be prepared to handle compressed content themselves. Built-in transforms will fail if they receive compressed data.

Types of Transforms

The library provides four types of transforms, each building on the previous level:

  • InjectContentResponseTransform - Pre-built transform for common content injection scenarios
  • DocumentResponseTransform - Specialized for HTML documents, provides parsed DOM access via HtmlAgilityPack
  • TextResponseTransform - Base class for text-based responses, handles encoding/decoding automatically
  • IResponseTransform - Base interface for all transforms, works with raw byte arrays

Embedded Resource Pipeline

The library includes a built-in embedded resource serving system that works alongside the transform pipeline:

  • Resource Registration: Embedded resources are automatically registered when using FromEmbeddedResource()
  • Automatic Serving: The library serves embedded resources at generated URLs (e.g., /_/{namespace-hash}/{resource-hash})
  • Content Types: Proper content-type headers are set based on file extensions

This allows for bundling CSS, JavaScript, images, and other assets directly in an assembly and having them automatically served by the application.

Transform Execution Order

Transforms are executed in the order they are registered. Each transform receives the output of the previous transform, allowing multiple transformations to be chained together.

Usage

HTML Document Injection

Use the built-in content injection system to add scripts, stylesheets, HTML content, and images to HTML documents using XPath targeting. This is the most common use case and requires no custom code.

services.AddResponseTransformer(builder => builder
    .TransformDocument(config => config
        .InjectScript(script => script.FromEmbeddedResource("MyApp.Scripts.analytics.js", typeof(Program).Assembly).At("//body"))
        .InjectStyleSheet(css => css.FromUrl("/css/styles.css").At("//head"))
        .InjectImage(img => img.FromUrl("/images/logo.png").At("//div[@id='header']"))
        .InjectHtml(html => html.WithContent("<div>Welcome!</div>").At("//body"))));

Custom HTML Transforms

Implement DocumentResponseTransform to create custom HTML document manipulations with full access to the parsed HTML DOM via HtmlAgilityPack.

public class MetaTagTransform : DocumentResponseTransform
{
    public override bool ShouldTransform(HttpContext context) =>
        context.Request.Path.StartsWithSegments("/static/html");

    public override void ExecuteTransform(HttpContext context, ref HtmlDocument document)
    {
        var head = document.DocumentNode.SelectSingleNode("//head");
        var metaTag = document.CreateElement("meta");
        metaTag.SetAttributeValue("name", "generated-at");
        metaTag.SetAttributeValue("content", DateTime.UtcNow.ToString());
        head?.AppendChild(metaTag);
    }
}

...

// Register the transform
services.AddTransient<IResponseTransform, MetaTagTransform>();

Custom Text Transforms

Implement TextResponseTransform to perform string-based transformations on any text-based HTTP responses (HTML, JSON, XML, etc.).

public class TokenReplacementTransform : TextResponseTransform
{
    public override bool ShouldTransform(HttpContext context) =>
        context.Response.ContentType?.Contains("text/html") == true;

    public override void ExecuteTransform(HttpContext context, ref string content)
    {
        content = content.Replace("{{USER_NAME}}", context.User.Identity?.Name ?? "Guest");
    }
}

...

// Register the transform
services.AddTransient<IResponseTransform, TokenReplacementTransform>();

Custom Binary Transforms

Implement IResponseTransform directly to work with raw byte arrays for complete control over any response type.

public class ResizeImageTransform : IResponseTransform
{
    public bool ShouldTransform(HttpContext context) =>
        context.Response.ContentType?.StartsWith("image/") == true;

    public void ExecuteTransform(HttpContext context, ref byte[] content)
    {
        // Resize image logic here
        content = ResizeImage(content, maxWidth: 800, maxHeight: 600);
    }
}

...

// Register the transform
services.AddTransient<IResponseTransform, ResizeImageTransform>();
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.1.13 194 10/14/2025
1.0.0.12-prerelease 181 10/14/2025
0.1.2.11-prerelease 178 10/4/2025
0.1.0.9-prerelease 180 10/2/2025
0.0.8.8-prerelease 185 10/2/2025
0.0.7.7-prerelease 179 9/29/2025
0.0.6.6-prerelease 173 9/29/2025
0.0.5.5-prerelease 119 9/27/2025
0.0.4.4-prerelease 110 9/27/2025
0.0.4.3-prerelease 118 9/27/2025
0.0.2.2-prerelease 116 9/27/2025