如何传递参数给ASP.NET Core的中间件(Middleware)

问题描述


当我们在ASP.NET Core中定义和使用中间件(Middleware)的时候,有什么好的办法可以给中间件传参数吗?

解决方案


在ASP.NET Core项目中添加一个POCO类来传递参数到中间件,例如下面的GreetingOptions类

public class GreetingOptions
{
    public string GreetAt { get; set; }
    public string GreetTo { get; set; }
}

然后添加一个中间件GreetingMiddleware

public class GreetingMiddleware
{
    private readonly RequestDelegate next;
    private readonly GreetingOptions options;

    public GreetingMiddleware(
        RequestDelegate next,
        GreetingOptions options)
    {
        this.next = next;
        this.options = options;
    }

    public async Task Invoke(
        HttpContext context)
    {
        var message = $"Good {this.options.GreetAt} {this.options.GreetTo}";
        await context.Response.WriteAsync(message);
    }
}

解决方案A:实例类型(Instance Type)


通过添加一个扩展方法类GreetingMiddlewareExtension,来配置中间件GreetingMiddleware,并传递参数GreetingOptions options

public static class GreetingMiddlewareExtension
{
    public static IApplicationBuilder UseGreeting(this IApplicationBuilder app, GreetingOptions options)
    {
        return app.UseMiddleware<GreetingMiddleware>(options);
    }
}

在ASP.NET Core项目中Startup类的Configure方法中,启用GreetingMiddleware中间件,并传递参数到中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseGreeting(new GreetingOptions
    {
        GreetAt = "Morning",
        GreetTo = "Tahir"
    });
}

解决方案B:方法类型(Function Type)


通过添加一个扩展方法类GreetingMiddlewareExtension,来配置中间件GreetingMiddleware,并通过委托Action<GreetingOptions> configureOptions来传递参数GreetingOptions

public static class GreetingMiddlewareExtension
{
    public static IApplicationBuilder UseGreeting(this IApplicationBuilder app, Action<GreetingOptions> configureOptions)
    {
        var options = new GreetingOptions();
        configureOptions(options);

        return app.UseMiddleware<GreetingMiddleware>(options);
    }
}

在ASP.NET Core项目中Startup类的Configure方法中,启用GreetingMiddleware中间件,并通过委托Action<GreetingOptions>传递参数到中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseGreeting(options =>
    {
        options.GreetAt = "Morning";
        options.GreetTo = "Tahir";
    });
}

讨论


前面的一篇文章中我们讨论了,定义和使用中间件(Middleware)的最好方法是,将中间件定义在一个单独的类中,然后通过扩展方法将其添加到ASP.NET Core的中间件管道(pipeline)中。

我们可以通过上面介绍的解决方案A和B,将需要传递到中间件的参数都封装为一个POCO类,并创建一个扩展方法,用下面量两种方式作为扩展方法的参数:

  • POCO实例(解决方案A
  • 一个委托方法,随后通过调用该委托方法来创建并配置POCO实例(解决方案B

注意:POCO实例是通过. UseMiddleware()方法的params object[]参数来传递到中间件的构造函数中的,也就是说我们可以通过params object[]来传递任意多个参数到中间件中,只要类型和中间件的构造函数参数匹配即可。我们可以将依赖注入参数和POCO实例参数一起传入中间件的构造函数中,如下所示:

public class GreetingMiddleware
{
    private readonly RequestDelegate next;
    private readonly GreetingOptions options;

    //IHostingEnvironment env是依赖注入参数,GreetingOptions options是POCO实例参数
    public GreetingMiddleware(RequestDelegate next, IHostingEnvironment env, GreetingOptions options)
    {
        string environmentName = env.EnvironmentName;

        this.next = next;
        this.options = options;
    }

    public async Task Invoke(
        HttpContext context)
    {
        var message = $"Good {this.options.GreetAt} {this.options.GreetTo}";
        await context.Response.WriteAsync(message);
    }
}

配置依赖注入服务


前面介绍的两种解决方案同样也可以用来配置依赖注入(dependency injection)服务的容器。

为了演示,我们先添加一个POCO类MessageOptions和用到的枚举MessageFormat

public enum MessageFormat
{
    None,
    Upper,
    Lower
}

public class MessageOptions
{
    public MessageFormat Format { get; set; }
}

然后添加一个依赖注入接口IMessageService,及其实现类MessageService

public interface IMessageService
{
    string FormatMessage(string message);
}
public class MessageService : IMessageService
{
    private readonly MessageOptions options;

    public MessageService(MessageOptions options)
    {
        this.options = options;
    }

    public string FormatMessage(string message)
    {
        // use options
        return this.options.Format == MessageFormat.None ? message :
                this.options.Format == MessageFormat.Upper ? message.ToUpper() :
                    message.ToLower();
    }
}

同样,接下来我们就用两种解决方案,来定义MessageService的扩展方法类MessageServiceExtension

解决方案A:实例类型(Instance Type)


public static class MessageServiceExtension
{
    // Instance Type
    public static IServiceCollection AddMessageFormatter(this IServiceCollection services, MessageOptions options)
    {
        return services.AddScoped<IMessageService>(factory =>
        {
            return new MessageService(options);
        });
    }
}

在ASP.NET Core项目中Startup类的ConfigureServices方法中,注册IMessageService和MessageService的依赖注入服务

// Instance Type
public void ConfigureServices(IServiceCollection services)
{
    services.AddMessageFormatter(new MessageOptions
    {
        Format = MessageFormat.Lower
    });
}

解决方案B:方法类型(Function Type)


public static class MessageServiceExtension
{
    // Function Type
    public static IServiceCollection AddMessageFormatter(this IServiceCollection services, Action<MessageOptions> configureOptions)
    {
        var options = new MessageOptions();
        configureOptions(options);

        return services.AddScoped<IMessageService>(factory =>
        {
            return new MessageService(options);
        });
    }
}

在ASP.NET Core项目中Startup类的ConfigureServices方法中,注册IMessageService和MessageService的依赖注入服务

// Function Type
public void ConfigureServices(IServiceCollection services)
{
    services.AddMessageFormatter(options =>
    {
        options.Format = MessageFormat.Lower;
    });
}

本文参考自:Passing Parameters to Middleware in ASP.NET Core 2.0

猜你喜欢

转载自www.cnblogs.com/OpenCoder/p/10345312.html