【问题标题】:Inject BL to OAuth with AutoFac使用 AutoFac 将 BL 注入 OAuth
【发布时间】:2020-07-14 00:25:37
【问题描述】:

我已按照Blog 在我的 WebApi 中生成刷新令牌。在 RefreshTokenProvider 类中,他正在访问 AuthenticationRepository 以在表中为生成的刷新令牌创建一行。每件事都完美无缺。但现在我想将依赖注入添加到我的 WebAPI 项目中。对于依赖注入,我使用具有以下配置的 AutoFac

public class IocConfig
{
    public static AutofacWebApiDependencyResolver Configure()
    {
        var builder = new ContainerBuilder();
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        builder.RegisterType<DefaultPrincipalProvider>().As<IPrincipalProvider>();
        builder.RegisterType<Logic>().AsSelf().InstancePerRequest();
        builder.RegisterType<DataAccess>().AsSelf().InstancePerRequest();
        builder.RegisterType<AuthRefreshTokenProvider>().As<IAuthenticationTokenProvider>().SingleInstance();
        var container = builder.Build();
        var resolver = new AutofacWebApiDependencyResolver(container);
        GlobalConfiguration.Configuration.DependencyResolver = resolver;
        return resolver;
    }
}

Global.asax.cs

protected void Application_Start()
{
    IocConfig.Configure();
    AreaRegistration.RegisterAllAreas();
    GlobalConfiguration.Configure(WebApiConfig.Register);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);
}

控制器

public class ItemController : ApiController
{
    private Logic _logic;
    public ItemController(Logic logic)
    {
        _logic = logic;
    }
}

业务逻辑

public partial class Logic
{
    IPrincipalProvider _principalProvider;
    DataAccess _dataAccess;
    string _currentUserId;

    public Logic(DataAccess dataAccess,IPrincipalProvider provider)
    {
        _dataAccess = dataAccess;
    }

}

数据访问

public partial class DataAccess
{

    public DataAccess()
    {
    }

}

上述配置一切正常,但我被困在如何配置OAuthAuthorizationServerOptions 上。我需要将BusinessLogic Instance 传递给 AuthRefreshTokenProvider。

OAuthOptions = new OAuthAuthorizationServerOptions
{
    TokenEndpointPath = new PathString("/Token"),
    Provider = new ApplicationOAuthProvider(PublicClientId),
    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
    RefreshTokenProvider = new AuthRefreshTokenProvider(),// Need To use Dependency Injection Here
    // In production mode set AllowInsecureHttp = false
    AllowInsecureHttp = true
};

AuthRefreshTokenProvider

public class AuthRefreshTokenProvider : IAuthenticationTokenProvider
{
    private Logic _logic;
    public AuthRefreshTokenProvider(Logic logic)
    {
        _logic = logic;
    }
}

我已经尝试了很多方法来完成这项工作。我知道问题在于在 SingleInstance 中实例化InstancePerRequest()。我一直在阅读很多文章和 stackoverflow 帖子以使其正常工作,但似乎无法使其正常工作

【问题讨论】:

    标签: c# asp.net-web-api dependency-injection owin autofac


    【解决方案1】:

    如果我正确理解您的问题,您的问题是关于从单例服务上下文访问范围服务?

    假设您的应用程序是 ASP.Net WebAPI(不是 Core),您需要捕获 HttpRequestMessage 才能访问请求范围。

    首先,您需要在某个地方保存请求消息,并且由于您想从单例服务访问请求消息,因此新服务还需要是单例服务:

    interface IHttpRequestAccessor
    {
        HttpRequestMessage Request { get; set; }
    }
    
    class HttpRequestAccessor : IHttpRequestAccessor
    {
        private readonly AsyncLocal<HttpRequestMessageHolder> _currentRequest =
            new AsyncLocal<HttpRequestMessageHolder>();
    
        public HttpRequestMessage Request
        {
            get => _currentRequest.Value?.Value;
            set
            {
                HttpRequestMessageHolder holder = _currentRequest.Value;
                if (holder != null)
                {
                    holder.Value = null;
                }
    
                if (value != null)
                {
                    _currentRequest.Value = new HttpRequestMessageHolder { Value = value };
                }
            }
        }
    
        private class HttpRequestMessageHolder
        {
            public HttpRequestMessage Value { get; set; }
        }
    }
    
    builder.RegisterType<HttpRequestAccessor>()
        .As<IHttpRequestAccessor>()
        .SingleInstance();
    

    这是如何工作的?

    这个类公开了一个属性来获取和设置HttpRequestMessage到当前的异步执行上下文。因为每个请求的数据上下文是不同的,并且在 WebAPI 请求管道的所有步骤中都被继承,所以我们可以将它设置在一个地方,然后在另一个地方为同一个 HTTP 请求使用它。这与IHttpContextAccessor 在 ASP.Net Core 应用程序中的实现方式相同。

    现在我们需要在某个地方捕获和设置IHttpRequestAccessor.Requestdelegating handler 是一个不错的选择:

    class CaptureHttpRequestMessageHandler : DelegatingHandler
    {
        private readonly IHttpRequestAccessor _requestMessageAccessor;
    
        public CaptureHttpRequestMessageHandler(IHttpRequestAccessor requestMessageAccessor)
        {
            _requestMessageAccessor = requestMessageAccessor;
        }
    
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            if (_requestMessageAccessor != null)
            {
                _requestMessageAccessor.Request = request;
            }
    
            return base.SendAsync(request, cancellationToken);
        }
    }
    

    并将其添加到配置中:

    GlobalConfiguration.Configuration.MessageHandlers.Add(
        new CaptureHttpRequestMessageHandler(/* resolve services here */));
    

    毕竟,将IHttpRequestAccessor 注入您的AuthRefreshTokenProvider 并删除Logic

    每当需要Logic 时,使用以下方法即时解决它:

    _httpRequestAccessor.Request.GetDependencyScope().GetService(typeof(Logic));
    

    只要在 HTTP 请求时调用AuthRefreshTokenProvider,这应该可以工作。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-15
      相关资源
      最近更新 更多