HttpResponseTransformer 1.0.1.13
dotnet add package HttpResponseTransformer --version 1.0.1.13
NuGet\Install-Package HttpResponseTransformer -Version 1.0.1.13
<PackageReference Include="HttpResponseTransformer" Version="1.0.1.13" />
<PackageVersion Include="HttpResponseTransformer" Version="1.0.1.13" />
<PackageReference Include="HttpResponseTransformer" />
paket add HttpResponseTransformer --version 1.0.1.13
#r "nuget: HttpResponseTransformer, 1.0.1.13"
#:package HttpResponseTransformer@1.0.1.13
#addin nuget:?package=HttpResponseTransformer&version=1.0.1.13
#tool nuget:?package=HttpResponseTransformer&version=1.0.1.13
HttpResponseTransformer
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()orbuilder.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 scenariosDocumentResponseTransform- Specialized for HTML documents, provides parsed DOM access via HtmlAgilityPackTextResponseTransform- Base class for text-based responses, handles encoding/decoding automaticallyIResponseTransform- 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 | Versions 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. |
-
.NETStandard 2.1
- HtmlAgilityPack (>= 1.6.0 && < 2.0.0)
- Microsoft.AspNetCore.Http.Abstractions (>= 2.1.0 && < 3.0.0)
- Microsoft.AspNetCore.Mvc.Core (>= 2.1.0 && < 3.0.0)
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 |