Autofac,Owin,Webapi和注入AuthorizationServerProvider

时间:2014-10-28 15:23:44

标签: asp.net-web-api autofac owin

在阅读有关使用owin和webapi的autofac的问题和文章后,我遇到了注入服务的解决方案,但它不起作用。这是我的代码:

public class StartUp
{
    public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();
        WebApiConfig.Register(config);

        var builder = new ContainerBuilder();                                    // Create the container builder.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());         // Register the Web API controllers.

        var authcontext = new AuthContext();

        builder.RegisterInstance(authcontext).AsSelf().SingleInstance();

        //Updated
        //var simpleauth = new SimpleAuthorizationServerProvider();
        //Updated
        // builder.RegisterInstance(simpleauth).SingleInstance().AsSelf().PropertiesAutowired();

        builder.Register(x => new UserStore<IdentityUser>(authcontext)).As<IUserStore<IdentityUser>>();

        //updated

        builder.Register(x =>
        {
            var p = new SimpleAuthorizationServerProvider();
            var userStore = x.Resolve<IUserStore<IdentityUser>>();
            p.userManager = new UserManager<IdentityUser>(userStore);
            return p;
        }).AsSelf().PropertiesAutowired();

        builder.RegisterType<AuthRepository>().As<IAuthRepository>().InstancePerRequest().PropertiesAutowired();

        var container = builder.Build();

        var resolver = new AutofacWebApiDependencyResolver(container);           // Create an assign a dependency resolver for Web API to use.
        config.DependencyResolver = resolver;

        app.UseAutofacMiddleware(container);

        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(config);

        ConfigureOAuth(app, resolver);
    }

    public void ConfigureOAuth(IAppBuilder app, AutofacWebApiDependencyResolver resolver)
    {
        OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
           //updated
            Provider =  new SimpleAuthorizationServerProvider()
//resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(OAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

    }


}

但是在SimpleAuthorizationServerProvider类中,当一个类似ValidateClientAuthentication的方法被调用时,所有的服务都是null,这里是代码:

        public readonly IAuthRepository repository;
        public readonly UserManager<IdentityUser> userManager;
        public readonly AuthContext dbContext;

        public SimpleAuthorizationServerProvider()
        {

        }

        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            string clientId;
            string clientSecret;

            if (context.TryGetFormCredentials(out clientId, out clientSecret))
            {


                try
                {
                    Client client = await repository.FindClientById(clientId);
                }
            }
        }

请你帮帮我吗?

更新

如果在ConfigureOAuth方法中,我使用以下方法:

            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider
            };

我收到错误:

An exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll but was not handled in user code

Additional information: No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.

1 个答案:

答案 0 :(得分:9)

当您注册对象的实例而不是类型时,即使您指定的PropertiesAutowired将不会生效,因为Autofac假定您在创建实例时已完成所需的所有工作。如果您希望连接属性,则需要在OnActivated处理程序中执行此操作。

在这个示例代码中实际上有很多东西在起作用。

  • SimpleAuthorizationServerProvider中的值为字段而非属性,因此PropertiesAutowired不会对其进行处理。
  • 这些字段标记为只读,并且永远不会设置。
  • 您已将UserManager<IdentityUser>注册为lambda,但也PropertiesAutowired无法工作 - 您只能在基于反射的组件上使用PropertiesAutowired(例如RegisterType<T> 1}})。

考虑为您的提供者注册lambda并在lambda中设置所有内容:

builder.Register(c => {
  var p = new SimpleAuthorizationServerProvider();
  p.repository = c.Resolve<UserManager<IdentityUser>>();
  // ...and so on
  return p;
}).AsSelf().SingleInstance();

另外,请记住,如果您注册一个实例(或将某些内容注册为SingleInstance,那么属性将被解析一次,那就是它。所以如果您有一些{{1的依赖项或者InstancePerDependency,这不会像你想象的那样工作 - 他们会被解决一次并在那之后有效地成为单身人士。


更新1

基于原始和更新的代码,我发现如果您可以查看一些Autofac文档以更好地了解它是如何工作的,那将是一件好事。例如,使用InstancePerRequest中的字段显示您可能无法完全了解Autofac中的注入方式或如何正确注册事物,因此Autofac可以为您完成工作。

例如,查看更新......

  • 您现在已为SimpleAuthorizationServerProvider注册了lambda,但我不知道您在那里设置SimpleAuthorizationServerProvider字段的位置。
  • 您在repository注册时不需要PropertiesAutowired,因为您正在注册lambda并且属性不会自动装配(如前所述)。
  • 我认为注册SimpleAuthorizationServerProvider的唯一组件是InstancePerRequest但是,就像我说的那样,我不知道在哪里解决或设置 - 以及#&#&# 39; s唯一会产生你注意到的例外的东西。 There is an FAQ on dealing with that exact exception that you should look into.

此外,您正在展示正在初始化的AuthRepository的两个不同版本,并且很难分辨出哪一个是真实的。&#34;

我建议进行相当重要的重构,以便能够正确使用DI。

更改OAuthServerOptions以停止使用公共字段并将其添加为构造函数参数,以便Autofac可以为您填充内容。

SimpleAuthorizationServerProvider

在启动期间,修复您的注册以删除多余的内容并利用Autofac自动布线优势。

public class SimpleAuthorizationServerProvider
{
  public IAuthRepository Repository { get; private set; }
  public UserManager<IdentityUser> UserManager {get; private set; }
  public AuthContext Context { get; private set; }
  public SimpleAuthorizationServerProvider(
    IAuthRepository repository,
    UserManager<IdentityUser> userManager,
    AuthContext context)
  {
    this.Repository = repository;
    this.UserManager = userManager;
    this.AuthContext = context;
  }
}

假设所有代码都应该没问题。如果事情没有设置 - 就像其中一个public class StartUp { public void Configuration(IAppBuilder app) { var config = new HttpConfiguration(); WebApiConfig.Register(config); var builder = new ContainerBuilder(); builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Register the auth context instance but skip // the extra .AsSelf() and .SingleInstance() because // it's implicit. builder.RegisterInstance(new AuthContext()); // Use the lambda to resolve the auth context rather // than making a closure over an instance. builder.Register(c => new UserStore<IdentityUser>(c.Resolve<AuthContext>())) .As<IUserStore<IdentityUser>>(); // Just register the provider type and let Autofac // do the work without all this manual stuff. Skip // the .AsSelf() because it's implicit if you don't // specify other interfaces and don't auto-wire properties // because you don't need it. builder.RegisterType<SimpleAuthorizationProvider>(); // This is fine, but I can't tell where it's used - if // you are using it at app startup or OUTSIDE a request, // you will get that exception you noted. Also, unless // you're actually using property injection, lose the // .PropertiesAutowired() call. builder.RegisterType<AuthRepository>() .As<IAuthRepository>() .InstancePerRequest() .PropertiesAutowired(); var container = builder.Build(); var resolver = new AutofacWebApiDependencyResolver(container); config.DependencyResolver = resolver; app.UseAutofacMiddleware(container); app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll); app.UseWebApi(config); ConfigureOAuth(app, resolver); } public void ConfigureOAuth(IAppBuilder app, AutofacWebApiDependencyResolver resolver) { var options = new OAuthAuthorizationServerOptions() { AllowInsecureHttp = true, TokenEndpointPath = new PathString("/token"), AccessTokenExpireTimeSpan = TimeSpan.FromDays(1), // If you want the values to be wired up, you have // to do a resolve. Note, however, that since you're // doing this wire-up at app startup, there's no request // scope, so if something in here is registered `InstancePerRequest` // you will get an exception. Provider = resolver.GetService(typeof(SimpleAuthorizationServerProvider)) as SimpleAuthorizationServerProvider }; app.UseOAuthAuthorizationServer(options); app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()); } } 属性为null,或者如果你得到一个例外,因为它缺少一个依赖关系,或者如果你得到关于没有请求范围的例外......那么还有其他事情你还没有放入你的问题。

再次,请花点时间查看文档并熟悉Autofac。我认为您遇到的许多麻烦都是由于对事情的解决方式存在一些误解造成的。有线。