#108 Move compression providers back to options
This commit is contained in:
Родитель
88b78e7233
Коммит
e7b41c4f53
|
@ -2,7 +2,7 @@
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO.Compression;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
@ -18,9 +18,13 @@ namespace ResponseCompressionSample
|
||||||
{
|
{
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddSingleton<ICompressionProvider, GzipCompressionProvider>();
|
services.Configure<GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.Fastest);
|
||||||
services.AddSingleton<ICompressionProvider, CustomCompressionProvider>();
|
services.AddResponseCompression(options =>
|
||||||
services.AddResponseCompression("text/plain", "text/html");
|
{
|
||||||
|
options.Providers.Add<GzipCompressionProvider>();
|
||||||
|
options.Providers.Add<CustomCompressionProvider>();
|
||||||
|
options.MimeTypes = new[] { "text/plain", "text/html" };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Configure(IApplicationBuilder app)
|
public void Configure(IApplicationBuilder app)
|
||||||
|
@ -63,10 +67,7 @@ namespace ResponseCompressionSample
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var host = new WebHostBuilder()
|
var host = new WebHostBuilder()
|
||||||
.UseKestrel(options =>
|
.UseKestrel()
|
||||||
{
|
|
||||||
options.UseConnectionLogging();
|
|
||||||
})
|
|
||||||
// .UseWebListener()
|
// .UseWebListener()
|
||||||
.ConfigureLogging(factory =>
|
.ConfigureLogging(factory =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
#if NETSTANDARD1_3
|
||||||
|
using System.Reflection;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A Collection of ICompressionProvider's that also allows them to be instantiated from an <see cref="IServiceProvider" />.
|
||||||
|
/// </summary>
|
||||||
|
public class CompressionProviderCollection : Collection<ICompressionProvider>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a type representing an <see cref="ICompressionProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Provider instances will be created using an <see cref="IServiceProvider" />.
|
||||||
|
/// </remarks>
|
||||||
|
public void Add<TCompressionProvider>() where TCompressionProvider : ICompressionProvider
|
||||||
|
{
|
||||||
|
Add(typeof(TCompressionProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a type representing an <see cref="ICompressionProvider"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="providerType">Type representing an <see cref="ICompressionProvider"/>.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Provider instances will be created using an <see cref="IServiceProvider" />.
|
||||||
|
/// </remarks>
|
||||||
|
public void Add(Type providerType)
|
||||||
|
{
|
||||||
|
if (providerType == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(providerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!typeof(ICompressionProvider).IsAssignableFrom(providerType))
|
||||||
|
{
|
||||||
|
throw new ArgumentException($"The provider must implement {nameof(ICompressionProvider)}", nameof(providerType));
|
||||||
|
}
|
||||||
|
|
||||||
|
var factory = new CompressionProviderFactory(providerType);
|
||||||
|
Add(factory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is a placeholder for the CompressionProviderCollection that allows creating the given type via
|
||||||
|
/// an <see cref="IServiceProvider" />.
|
||||||
|
/// </summary>
|
||||||
|
internal class CompressionProviderFactory : ICompressionProvider
|
||||||
|
{
|
||||||
|
internal CompressionProviderFactory(Type providerType)
|
||||||
|
{
|
||||||
|
ProviderType = providerType;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Type ProviderType { get; }
|
||||||
|
|
||||||
|
internal ICompressionProvider CreateInstance(IServiceProvider serviceProvider)
|
||||||
|
{
|
||||||
|
if (serviceProvider == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(serviceProvider));
|
||||||
|
}
|
||||||
|
|
||||||
|
return (ICompressionProvider)ActivatorUtilities.CreateInstance(serviceProvider, ProviderType, Type.EmptyTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
string ICompressionProvider.EncodingName
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ICompressionProvider.SupportsFlush
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream ICompressionProvider.CreateStream(Stream outputStream)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.ResponseCompression
|
namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
{
|
{
|
||||||
|
@ -11,6 +13,22 @@ namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class GzipCompressionProvider : ICompressionProvider
|
public class GzipCompressionProvider : ICompressionProvider
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new instance of GzipCompressionProvider with options.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="options"></param>
|
||||||
|
public GzipCompressionProvider(IOptions<GzipCompressionProviderOptions> options)
|
||||||
|
{
|
||||||
|
if (options == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(options));
|
||||||
|
}
|
||||||
|
|
||||||
|
Options = options.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private GzipCompressionProviderOptions Options { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string EncodingName => "gzip";
|
public string EncodingName => "gzip";
|
||||||
|
|
||||||
|
@ -29,15 +47,10 @@ namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// What level of compression to use for the stream.
|
|
||||||
/// </summary>
|
|
||||||
public CompressionLevel Level { get; set; } = CompressionLevel.Fastest;
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Stream CreateStream(Stream outputStream)
|
public Stream CreateStream(Stream outputStream)
|
||||||
{
|
{
|
||||||
return new GZipStream(outputStream, Level, leaveOpen: true);
|
return new GZipStream(outputStream, Options.Level, leaveOpen: true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright (c) .NET Foundation. All rights reserved.
|
||||||
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
|
namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Options for the GzipCompressionProvider
|
||||||
|
/// </summary>
|
||||||
|
public class GzipCompressionProviderOptions : IOptions<GzipCompressionProviderOptions>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// What level of compression to use for the stream. The default is Fastest.
|
||||||
|
/// </summary>
|
||||||
|
public CompressionLevel Level { get; set; } = CompressionLevel.Fastest;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
GzipCompressionProviderOptions IOptions<GzipCompressionProviderOptions>.Value => this;
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,5 +20,10 @@ namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
/// Enable compression on HTTPS connections may expose security problems.
|
/// Enable compression on HTTPS connections may expose security problems.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool EnableForHttps { get; set; } = false;
|
public bool EnableForHttps { get; set; } = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The ICompressionProviders to use for responses.
|
||||||
|
/// </summary>
|
||||||
|
public CompressionProviderCollection Providers { get; } = new CompressionProviderCollection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,28 +20,37 @@ namespace Microsoft.AspNetCore.ResponseCompression
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If no compression providers are specified then GZip is used by default.
|
/// If no compression providers are specified then GZip is used by default.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="providers">Compression providers to use, if any.</param>
|
/// <param name="services">Services to use when instantiating compression providers.</param>
|
||||||
/// <param name="options"></param>
|
/// <param name="options"></param>
|
||||||
public ResponseCompressionProvider(IEnumerable<ICompressionProvider> providers, IOptions<ResponseCompressionOptions> options)
|
public ResponseCompressionProvider(IServiceProvider services, IOptions<ResponseCompressionOptions> options)
|
||||||
{
|
{
|
||||||
if (providers == null)
|
if (services == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(providers));
|
throw new ArgumentNullException(nameof(services));
|
||||||
}
|
}
|
||||||
if (options == null)
|
if (options == null)
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(options));
|
throw new ArgumentNullException(nameof(options));
|
||||||
}
|
}
|
||||||
|
|
||||||
_providers = providers.ToArray();
|
_providers = options.Value.Providers.ToArray();
|
||||||
if (_providers.Length == 0)
|
if (_providers.Length == 0)
|
||||||
{
|
{
|
||||||
_providers = new [] { new GzipCompressionProvider() };
|
// Use the factory so it can resolve IOptions<GzipCompressionProviderOptions> from DI.
|
||||||
|
_providers = new ICompressionProvider[] { new CompressionProviderFactory(typeof(GzipCompressionProvider)) };
|
||||||
|
}
|
||||||
|
for (var i = 0; i < _providers.Length; i++)
|
||||||
|
{
|
||||||
|
var factory = _providers[i] as CompressionProviderFactory;
|
||||||
|
if (factory != null)
|
||||||
|
{
|
||||||
|
_providers[i] = factory.CreateInstance(services);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.Value.MimeTypes == null || !options.Value.MimeTypes.Any())
|
if (options.Value.MimeTypes == null || !options.Value.MimeTypes.Any())
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("No MIME types specified");
|
throw new InvalidOperationException("No MIME types specified.");
|
||||||
}
|
}
|
||||||
_mimeTypes = new HashSet<string>(options.Value.MimeTypes, StringComparer.OrdinalIgnoreCase);
|
_mimeTypes = new HashSet<string>(options.Value.MimeTypes, StringComparer.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
@ -12,6 +13,7 @@ using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.AspNetCore.Http;
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Http.Features;
|
using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.TestHost;
|
using Microsoft.AspNetCore.TestHost;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Net.Http.Headers;
|
using Microsoft.Net.Http.Headers;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -108,6 +110,37 @@ namespace Microsoft.AspNetCore.ResponseCompression.Tests
|
||||||
CheckResponseCompressed(response, expectedBodyLength: 24);
|
CheckResponseCompressed(response, expectedBodyLength: 24);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task GZipCompressionProvider_OptionsSetInDI_Compress()
|
||||||
|
{
|
||||||
|
var builder = new WebHostBuilder()
|
||||||
|
.ConfigureServices(services =>
|
||||||
|
{
|
||||||
|
services.Configure<GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.NoCompression);
|
||||||
|
services.AddResponseCompression(TextPlain);
|
||||||
|
})
|
||||||
|
.Configure(app =>
|
||||||
|
{
|
||||||
|
app.UseResponseCompression();
|
||||||
|
app.Run(context =>
|
||||||
|
{
|
||||||
|
context.Response.Headers[HeaderNames.ContentMD5] = "MD5";
|
||||||
|
context.Response.ContentType = TextPlain;
|
||||||
|
return context.Response.WriteAsync(new string('a', 100));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
var server = new TestServer(builder);
|
||||||
|
var client = server.CreateClient();
|
||||||
|
|
||||||
|
var request = new HttpRequestMessage(HttpMethod.Get, "");
|
||||||
|
request.Headers.AcceptEncoding.ParseAdd("gzip");
|
||||||
|
|
||||||
|
var response = await client.SendAsync(request);
|
||||||
|
|
||||||
|
CheckResponseCompressed(response, expectedBodyLength: 123);
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("")]
|
[InlineData("")]
|
||||||
[InlineData("text/plain2")]
|
[InlineData("text/plain2")]
|
||||||
|
|
Загрузка…
Ссылка в новой задаче