Web Api Autofac InstancePerRequest

时间:2016-01-27 12:29:19

标签: c# attributes asp.net-web-api2 autofac

我的Web Api项目上有一个自定义的AuthorizationFilter属性,如下所示

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
public class GenericAuthenticationFilter :  AuthorizationFilterAttribute
{

    /// <summary>
    /// Public default Constructor
    /// </summary>
    public GenericAuthenticationFilter()
    {
    }

    private readonly bool _isActive = true;

    /// <summary>
    /// parameter isActive explicitly enables/disables this filter.
    /// </summary>
    /// <param name="isActive"></param>
    public GenericAuthenticationFilter(bool isActive)
    {
        _isActive = isActive;
    }



    /// <summary>
    /// Checks basic authentication request
    /// </summary>
    /// <param name="filterContext"></param>
    public override void OnAuthorization(HttpActionContext filterContext)
    {

        if (!_isActive) return;
        var identity = FetchAuthHeader(filterContext);
        if (identity == null)
        {
            ChallengeAuthRequest(filterContext);
            return;
        }
        var genericPrincipal = new GenericPrincipal(identity, null);
        Thread.CurrentPrincipal = genericPrincipal;
        if (!OnAuthorizeUser(identity.Name, identity.Password, filterContext))
        {
            ChallengeAuthRequest(filterContext);
            return;
        }

        base.OnAuthorization(filterContext);
    }

我的StartUpClass就像这样

  public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
        // Get your HttpConfiguration. In OWIN, you'll create one
        // rather than using GlobalConfiguration.
        var config = new HttpConfiguration();
        WebApiConfig.Register(config);
        IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
        config.DependencyResolver =
        new AutofacWebApiDependencyResolver(IoC.Instance.GetComponentsContainer());
        // Register your Web Api controllers.
        IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
        IoC.Instance.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
        IoC.Instance.RegisterWebApiModelBinderProvider();
        IoC.Instance.RegisterWebApiFilterProvider(config);
        // Register the Autofac middleware FIRST, then the Autofac Web API middleware,
        // and finally the standard Web API middleware.
        app.UseAutofacMiddleware(IoC.Instance.GetComponentsContainer());
        app.UseAutofacWebApi(config);
        app.UseWebApi(config);

    }
}

我解决所有依赖关系的IoC类就像这样

public class IoC : ContainerBuilder
{

    /// <summary>
    /// 
    /// </summary>
    private readonly static IoC _instance = new IoC();

    /// <summary>
    /// 
    /// </summary>
    private static object _lock;

    /// <summary>
    /// 
    /// </summary>
    private IContainer _componentsContainer;

    /// <summary>
    /// 
    /// </summary>
    public static IoC Instance
    {
        get
        {
            return _instance;
        }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public IContainer GetComponentsContainer()
    {
        if (_componentsContainer == null)
        {
            lock (_lock)
            {
                if (_componentsContainer == null)
                    _componentsContainer = this.Build();
            }
        }

        return _componentsContainer;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public T Resolve<T>() where T : class
    {
        return GetComponentsContainer().Resolve<T>();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <returns></returns>
    public ILifetimeScope BeginLifetimeScope()
    {
        return GetComponentsContainer().BeginLifetimeScope();
    }

    /// <summary>
    /// 
    /// </summary>
    private IoC()
    {
        _lock = new object();
        ConfigureDependencies();
    }

    /// <summary>
    /// 
    /// </summary>
    private void ConfigureDependencies()
    {
        //Configure all your depedendencies here!!

        //Database connection
        var connectionString = ConfigurationManager.ConnectionStrings["DBConnectionStringName"].ConnectionString;
        this.Register(c => new SqlConnection(connectionString)).As<IDbConnection>().InstancePerRequest();// InstancePerLifetimeScope();

        //Database Connection OrmLite
        OrmLiteConfig.DialectProvider = SqlServerDialect.Provider;
        //Register Repositories
        this.RegisterType<Repository>().As<IRepository>().InstancePerRequest();// InstancePerLifetimeScope();
        // Register Services
        this.RegisterType<UserService>().As<IUserService>().InstancePerRequest();// InstancePerLifetimeScope();
        this.RegisterType<TokenService>().As<ITokenService>().InstancePerRequest();
        this.RegisterType<DKMenuService>().As<IDKMenuService>().InstancePerRequest();// InstancePerLifetimeScope();
        this.RegisterType<DKGRIDTblService>().As<IDKGRIDTblService>().InstancePerRequest();// InstancePerLifetimeScope();
        this.RegisterType<FKService>().As<IFKService>().InstancePerRequest();// InstancePerLifetimeScope();
        this.RegisterType<LOVService>().As<ILOVService>().InstancePerRequest();// InstancePerLifetimeScope();
        this.RegisterType<JobService>().As<IJobService>().InstancePerRequest();// InstancePerLifetimeScope();
        this.RegisterType<MADEService>().As<IMADEService>().InstancePerRequest();// InstancePerLifetimeScope();

    }

}

我用这个过滤器装饰我的控制器

[GenericAuthenticationFilter]
    public AuthenticateController(ITokenService tokenService)
    {
        _tokenService = tokenService;
    }

我的问题是GenericAuthenticationFilter的OnAuthorazation方法永远不会被触发。 如果在IoC Class类中我将InstancePerRequest更改为InstancePerLifetimeScope,一切正常,但我希望我的依赖项按请求工作

任何想法?

2 个答案:

答案 0 :(得分:0)

我不确定这是否是您的部分或全部问题,但是......您只能构建一次ContainerBuilder。在Startup.Configuration()我在第11-12行看到了:

config.DependencyResolver =
new AutofacWebApiDependencyResolver(IoC.Instance.GetComponentsContainer());

IoC.Instance.GetComponentsContainer()调用Build()来创建容器。

但仅仅两行之后,我看到你正在向容器添加更多组件,之后我看到第二个电话:

app.UseAutofacMiddleware(IoC.Instance.GetComponentsContainer());

根据您的代码,在添加新注册之前,它将与构建的容器相同。容器将不包括API控制器,模型绑定器或过滤器提供程序。

我实际上不确定你为什么没有更多的问题,而不是现在。

在完成所有注册后,尝试移动容器的设置(对IoC.Instance.GetComponentsContainer()的调用)直到一直到最后你的依赖。

答案 1 :(得分:0)

唯一有效的配置是以下

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
        // Get your HttpConfiguration. In OWIN, you'll create one
        // rather than using GlobalConfiguration.
        var config = new HttpConfiguration();
        WebApiConfig.Register(config);
        // Register your Web Api controllers.
        IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
        IoC.Instance.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
        IoC.Instance.RegisterWebApiModelBinderProvider();

        config.DependencyResolver =
        new AutofacWebApiDependencyResolver(IoC.Instance.GetComponentsContainer());
        // Register your Web Api controllers.
        //IoC.Instance.RegisterApiControllers(Assembly.GetExecutingAssembly());
        //IoC.Instance.RegisterWebApiModelBinders(Assembly.GetExecutingAssembly());
        //IoC.Instance.RegisterWebApiModelBinderProvider();

        // Register the Autofac middleware FIRST, then the Autofac Web API middleware,
        // and finally the standard Web API middleware.
        app.UseAutofacMiddleware(IoC.Instance.GetComponentsContainer());
        app.UseAutofacWebApi(config);
        app.UseWebApi(config);

    }
}

我仍然不确定它是否正确。 用法示例。我有一个像以下

的过滤器
public class ApiAuthenticationFilter : GenericAuthenticationFilter
{

    /// <summary>
    /// Default Authentication Constructor
    /// </summary>
    public ApiAuthenticationFilter()
    {

    }

}

此过滤器中的方法正在使用像此

这样解析的服务
protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
    {
        var provider = actionContext.Request.GetDependencyScope().GetService(typeof(IUserService)) as IUserService;

}

另一方面,我的控制器没有无参数构造函数,并且依赖关系会自动解决

public class DKMenuController : ApiController
{
    #region Private variable.

    private readonly ITokenService _tokenService;
    private readonly IDKMenuService _dkMenuService;
    private readonly IUserService _userservice;
    private const string Token = "Token";

    #endregion

    #region Public Constructor

    /// <summary>
    /// Public constructor to initialize DKMenu service instance
    /// </summary>
    public DKMenuController(ITokenService tokenService, IUserService userservice, IDKMenuService dkMenuService)
    {
        _tokenService = tokenService;
        _dkMenuService = dkMenuService;
        _userservice = userservice;
    }

}

我不知道它是否正确但是有效