Skip to content

Commit

Permalink
Made some changes for v4
Browse files Browse the repository at this point in the history
  • Loading branch information
karl-sjogren committed Dec 27, 2023
1 parent 141dea3 commit 97f4715
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 52 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<VersionPrefix>3.1.0</VersionPrefix>
<VersionPrefix>4.0.0</VersionPrefix>
<LangVersion>latest</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<Deterministic>true</Deterministic>
Expand Down
31 changes: 5 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,11 @@ sort of code to handle that, and this makes it easy.
PM> Install-Package RobotsTxtCore
```

## Changes from 1.0 to 2.0

The first version of this package was only a middleware and had to be configured in
the `Configure` method in the `Startup` class. This felt fine at the time but as more
and more things moved to having configuration as a service and then letting the
middleware consume the service I felt like this package got outdated.

So I've made a breaking change and made the middleware consume a `IRobotsTxtProvider`
which in turn takes care of configuration. There is a default provider for static uses
(i.e. exactly what the old one did) but doing it this way also let me optimize it quite
a lot. A quick benchmark shows that running a thousand requests against `/robots.txt`
is now done in 25% of the time while also lowering allocations about the same.

| NuGetReferences | Mean | Error | StdDev | Gen 0 | Gen 1 | Allocated |
|----------------------------- |-----------:|---------:|---------:|---------:|-------:|----------:|
| RobotsTxtCore 1.1.0 | 1,169.2 μs | 22.62 μs | 27.77 μs | 691.4063 | 1.9531 | 4,242 KB |
| RobotsTxtCore 2.0.0-preview1 | 419.8 μs | 3.88 μs | 3.24 μs | 167.9688 | - | 1,031 KB |
| RobotsTxtCore 2.0.0-preview2 | 431.5 μs | 2.90 μs | 2.57 μs | 150.3906 | - | 922 KB |
| RobotsTxtCore 2.0.0-preview3 | 307.4 μs | 2.00 μs | 1.87 μs | 155.2734 | - | 953 KB |

Sure, it was really fast to start with and there are very few sites where `/robots.txt`
gets a ton of traffic but that doesn't mean it's not worth it 😉.

Introducing the `IRobotsTxtProvider` also allows for easier dynamic usage, like
reading settings from a database or switching depending on which environment the code
is executing in.
## Changes from 3.0 to 4.0

`services.AddStaticRobotsTxt` is now marked as obsolete in favor of `services.AddRobotsTxt`.
After adding support for multiple hostnames and environments it didn't really feel like it
was "static" anymore.

## Usage

Expand Down
4 changes: 2 additions & 2 deletions samples/sample-site/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Add services to the container.
builder.Services.AddControllersWithViews();

builder.Services.AddStaticRobotsTxt(builder =>
builder.Services.AddRobotsTxt(builder =>
builder
.ForEnvironment("Production")
.AddSection(section =>
Expand All @@ -16,7 +16,7 @@
)
);

builder.Services.AddStaticRobotsTxt(builder =>
builder.Services.AddRobotsTxt(builder =>
builder
.DenyAll()
);
Expand Down
11 changes: 8 additions & 3 deletions src/RobotsTxt/IServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;

namespace RobotsTxt;

public static class IServiceCollectionExtensions {
[Obsolete("Use AddRobotsTxt instead.", false)]
public static void AddStaticRobotsTxt(this IServiceCollection services, Func<RobotsTxtOptionsBuilder, RobotsTxtOptionsBuilder> builderFunc) {
AddRobotsTxt(services, builderFunc);
}

Check warning on line 11 in src/RobotsTxt/IServiceCollectionExtensions.cs

View check run for this annotation

Codecov / codecov/patch

src/RobotsTxt/IServiceCollectionExtensions.cs#L10-L11

Added lines #L10 - L11 were not covered by tests

public static void AddRobotsTxt(this IServiceCollection services, Func<RobotsTxtOptionsBuilder, RobotsTxtOptionsBuilder> builderFunc) {
var builder = new RobotsTxtOptionsBuilder();
var options = builderFunc(builder).Build();

Expand Down Expand Up @@ -50,7 +54,8 @@ internal static IRobotsTxtProvider CreateRobotsTxtProviderForMultipleHosts(IServ
}
}

var hostEnvironemnt = services.GetRequiredService<IHostEnvironment>();
return new StaticRobotsTxtProvider(robotsOptions, hostEnvironemnt);
//var hostEnvironemnt = services.GetRequiredService<IHostEnvironment>();
return ActivatorUtilities.CreateInstance(services, typeof(StaticRobotsTxtProvider), robotsOptions) as IRobotsTxtProvider;
//return new StaticRobotsTxtProvider(robotsOptions, hostEnvironemnt);
}
}
12 changes: 8 additions & 4 deletions src/RobotsTxt/StaticRobotsTxtProvider.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
using System.Text;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace RobotsTxt;

public class StaticRobotsTxtProvider : IRobotsTxtProvider {
private readonly Memory<byte> _content;
private readonly Int32 _maxAge;

public StaticRobotsTxtProvider(IEnumerable<RobotsTxtOptions> optionsEnumerable, IHostEnvironment hostingEnvironment) {
public StaticRobotsTxtProvider(IEnumerable<RobotsTxtOptions> optionsEnumerable, IHostEnvironment hostingEnvironment, ILogger<StaticRobotsTxtProvider> logger) {
var options = optionsEnumerable.ToArray();
var robotsOptions = options.FirstOrDefault(o => hostingEnvironment.IsEnvironment(o.Environment));

if(robotsOptions is null) {
robotsOptions = options.FirstOrDefault(o => string.IsNullOrWhiteSpace(o.Environment));

if(robotsOptions == null)
throw new InvalidOperationException($"No RobotsTxtOptions matching environment \"{hostingEnvironment.EnvironmentName}\" or any environment found.");
if(robotsOptions == null) {
logger.LogWarning("No RobotsTxtOptions found for environment {Environment}.", hostingEnvironment.EnvironmentName);
robotsOptions = new RobotsTxtOptionsBuilder().DenyAll().Build();

Check warning on line 20 in src/RobotsTxt/StaticRobotsTxtProvider.cs

View check run for this annotation

Codecov / codecov/patch

src/RobotsTxt/StaticRobotsTxtProvider.cs#L19-L20

Added lines #L19 - L20 were not covered by tests
}
}

var content = robotsOptions.ToString();

if(string.IsNullOrWhiteSpace(content))
if(string.IsNullOrWhiteSpace(content)) {
content = "# This file didn't get any instructions so everyone is allowed";
}

_content = Encoding.UTF8.GetBytes(content).AsMemory();

Expand Down
12 changes: 6 additions & 6 deletions tests/RobotsTxt.Tests/RobotsTxtMiddlewareTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ public async Task RobotsTxtShouldRenderForTheCorrextEnvironmentAsync() {
file class Startup {
public void ConfigureServices(IServiceCollection services) {
services.Replace(new ServiceDescriptor(typeof(IHostEnvironment), _ => new TestHostEnvironment(), ServiceLifetime.Singleton));
services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.AddSection(section =>
section
Expand All @@ -157,7 +157,7 @@ public void Configure(IApplicationBuilder app) {
file class StartupMultipleEnvironments {
public void ConfigureServices(IServiceCollection services) {
services.Replace(new ServiceDescriptor(typeof(IHostEnvironment), _ => new TestHostEnvironment(), ServiceLifetime.Singleton));
services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.ForEnvironment("Development")
.AddSection(section =>
Expand All @@ -168,7 +168,7 @@ public void ConfigureServices(IServiceCollection services) {
)
);

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.ForEnvironment("Production")
.AddSection(section =>
Expand All @@ -188,7 +188,7 @@ public void Configure(IApplicationBuilder app) {
file class StartupAllowAll {
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<IHostEnvironment, TestHostEnvironment>();
services.AddStaticRobotsTxt(builder => builder.AllowAll());
services.AddRobotsTxt(builder => builder.AllowAll());
}

public void Configure(IApplicationBuilder app) {
Expand All @@ -199,7 +199,7 @@ public void Configure(IApplicationBuilder app) {
file class StartupDenyAll {
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<IHostEnvironment, TestHostEnvironment>();
services.AddStaticRobotsTxt(builder => builder.DenyAll());
services.AddRobotsTxt(builder => builder.DenyAll());
}

public void Configure(IApplicationBuilder app) {
Expand All @@ -210,7 +210,7 @@ public void Configure(IApplicationBuilder app) {
file class StartupNoConfig {
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton<IHostEnvironment, TestHostEnvironment>();
services.AddStaticRobotsTxt(builder => builder);
services.AddRobotsTxt(builder => builder);
}

public void Configure(IApplicationBuilder app) {
Expand Down
20 changes: 10 additions & 10 deletions tests/RobotsTxt.Tests/ServiceCollectionExtensionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ namespace RobotsTxt.Tests;
public class ServiceCollectionExtensionTests {
[Fact]
public void AddStaticRobotsTxt_WhenRegisteringWithoutHostname_RegistersProviderAsSingleton() {
var services = new ServiceCollection();
var services = new ServiceCollection().AddLogging();

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.DenyAll()
);
Expand All @@ -23,20 +23,20 @@ public void AddStaticRobotsTxt_WhenRegisteringWithoutHostname_RegistersProviderA

[Fact]
public void AddStaticRobotsTxt_WhenRegisteringMultipleOptionsWithDifferentHostNameOptions_RegistersProviderAsScoped() {
var services = new ServiceCollection();
var services = new ServiceCollection().AddLogging();

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.DenyAll()
);

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.ForHostnames("example.com")
.DenyAll()
);

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.DenyAll()
);
Expand All @@ -55,23 +55,23 @@ public void AddStaticRobotsTxt_WhenRegisteringMultipleOptionsWithDifferentHostNa
[InlineData("squirrels-with-hats.com", "https://sample-website.com/sitemap.xml")]

public async Task CreateRobotsTxtProviderForMultipleHosts_WhenCalledWithDifferentHostnames_ReturnsExpectedResultAsync(string hostname, string sitemapUrl) {
var services = new ServiceCollection();
var services = new ServiceCollection().AddLogging();

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.ForHostnames("example.com", "www.example.com", "example-com-test-site.com")
.AddSitemap("https://example.com/sitemap.xml")
.DenyAll()
);

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.ForHostnames("cool-horses-with-glasses.com")
.AddSitemap("https://cool-horses-with-glasses.com/sitemap.xml")
.DenyAll()
);

services.AddStaticRobotsTxt(builder =>
services.AddRobotsTxt(builder =>
builder
.AddSitemap("https://sample-website.com/sitemap.xml")
.DenyAll()
Expand Down

0 comments on commit 97f4715

Please sign in to comment.