在ASP.Net Core中间件中调用服务/存储库方法 [英] Calling service/repository methods in ASP.Net Core middleware

查看:76
本文介绍了在ASP.Net Core中间件中调用服务/存储库方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这里的ASP.Net Core菜鸟...我正在使用将DNX451与EF 6一起使用的ASP.Net Core WebAPI核心项目.

ASP.Net Core noob here...I am using an ASP.Net Core WebAPI core project using DNX451 with EF 6.

我需要在我们的服务中实现API密钥身份验证.为此,我创建了中间件,该中间件从请求中获取信息并继续进行身份验证.应该去数据库,获取要匹配的密钥,然后返回并进行验证.

I have a requirement to implement API Key auth in our service. To do this I have created middleware that gets information from the request and proceeds with authentication. It is SUPPOSED to go to the database, get the key to match, and then return and do the validation.

这里是实现用来查看上下文并获取APIKey的中间件

Here is the middleware implemented to look at the context and get the APIKey

AuthenticationHandler

public class AuthorizationHandler
{
    private readonly RequestDelegate _next;
    private IAuthenticationService _authenticationService;

    public AuthorizationHandler(RequestDelegate next, IAuthenticationService authService)
    {
        _authenticationService = authService;
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try
        {
            var apiKey = context.Request.Headers["Key"];
            var location = context.Request.Headers["Host"];
            var locationKey = _authenticationService.GetApiKey(location);

            if (apiKey == locationKey)
                await _next(context);


            context.Response.StatusCode = 403;
            context.Response.Headers.Add("WWW-Authenticate",
                new[] { "Basic" });

        }
        catch (Exception ex)
        {
            context.Response.StatusCode = 500;
            context.Response.Headers.Add("WWW-Authenticate",
                new[] { "Basic" });
        }
    }
}

这是具有上下文和中间件注册的启动类

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);


        builder.AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfiguration Configuration { get; set; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddScoped(k => new DbContext(Configuration["Data:Context:ConnectionString"]));


        // Add framework services.
        services.AddMvc();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseIISPlatformHandler();

        app.UseStaticFiles();

        app.RegisterAuthorizationHeader();
        app.RegisterAuthorization();

        app.UseMvc();
    }

    // Entry point for the application.
    public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}

这是身份验证服务

public interface IAuthenticationService
{
    string GetApiKey(string location);
}

public class AuthenticationService: IAuthenticationService
{
    private IApiKeyRepository _apiKeyRepository;
    public AuthenticationService(IApiKeyRepository repo)
    {
        _apiKeyRepository= repo;
    }

    public string GetApiKey(string location)
    {
        return _apiKeyRepository.GetApiKeyByLocation(location);
    }
}

存储库

public interface IApiRepository
{
    string GetApiKeyByLocation(string location);
}

public class ApiRepository: IApiRepository
{
    private DbContext _context;

    public ApiRepository(DbContext context)
    {
        _context = context;
    }

    public string GetApiKeyByLocation(string location)
    {
        var apiRow = _context.ApiKeyStore.FirstOrDefault(a => a.Location == location);

        return apiRow == null ? string.Empty : apiRow.APIKey;
    }
}

尝试此操作时出现以下错误:

When attempting this I get the following error:

在创建模型时不能使用上下文.这 如果上下文是在内部使用的,则可能会引发异常 OnModelCreating方法,或者如果相同的上下文实例被访问 并发多个线程.请注意,DbContext的实例成员 以及相关类不能保证是线程安全的.

The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.

现在,当我调试此代码时,每个断点都会被击中两次.我相信我了解为什么,但不知道如何解决.

Now, when I debug this every break point is hit twice. I believe I understand WHY this issue is occurring but have no idea how to fix it.

有人可以给我一个主意吗?还有更好的解决方案吗?

Can someone give me an idea, please? Any better solution ideas?

推荐答案

要在中间件(按定义必须是单例)中使用范围依赖,最好的方法是将其作为InvokeAsync的参数而不是通过构造函数使它流动:

To use scoped dependencies in a middleware (which is necessarily a singleton by definition), the best approach is to flow it as a parameter of InvokeAsync instead of flowing it via the constructor:

public async Task Invoke(HttpContext context, IAuthenticationService authenticationService)
{
    try
    {
        var apiKey = context.Request.Headers["Key"];
        var location = context.Request.Headers["Host"];
        var locationKey = authenticationService.GetApiKey(location);

        if (apiKey == locationKey)
            await _next(context);


        context.Response.StatusCode = 403;
        context.Response.Headers.Add("WWW-Authenticate",
            new[] { "Basic" });

    }
    catch (Exception ex)
    {
        context.Response.StatusCode = 500;
        context.Response.Headers.Add("WWW-Authenticate",
            new[] { "Basic" });
    }
}

这篇关于在ASP.Net Core中间件中调用服务/存储库方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆