首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Castle /DelegatingHandler/I-主依赖注入(DI)/Inversion of Control (IoC)在ASP.NET Web中的应用

Castle /DelegatingHandler/I-主依赖注入(DI)/Inversion of Control (IoC)在ASP.NET Web中的应用
EN

Stack Overflow用户
提问于 2013-04-01 01:13:49
回答 1查看 10.9K关注 0票数 4

我决定清理这篇文章,我在Ge.tt/3 3EwoZEd/v/0?c上发布了一个示例项目

在这上面已经花了大约30个小时了,但还是搞不清楚.我真的很感激你的帮助!

我有一个ASP.NET Web解决方案,该解决方案使用以下代码:http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/实现“使用消息处理程序在ASP.NET Web中进行基本的HTTP身份验证”。我是国际奥委会/DI的新手,我正努力让它与温莎城堡一起工作。

我尝试了很多不同的事情,但是根据我做错了什么,我得到了以下一个错误:

  • “看来您忘记注册http模块Castle.MicroKernel.Lifestyle.PerWebRequestLifestyleModule”了。
  • “对象引用未设置为对象的实例。”用于PrincipalProvider in BasicAuthMessageHandler
  • “没有找到支持服务*.DummyPrincipalProvider的组件”

下面是我的代码:

Global.asax.cs:

代码语言:javascript
复制
private static IWindsorContainer _container;

protected void Application_Start()
{
    AreaRegistration.RegisterAllAreas();

    WebApiConfig.Register(GlobalConfiguration.Configuration);
    FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
    RouteConfig.RegisterRoutes(RouteTable.Routes);
    BundleConfig.RegisterBundles(BundleTable.Bundles);

    var config = (CustomErrorsSection)ConfigurationManager.GetSection("system.web/customErrors");

    IncludeErrorDetailPolicy errorDetailPolicy;

    switch (config.Mode)
    {
        case CustomErrorsMode.RemoteOnly:
            errorDetailPolicy
                = IncludeErrorDetailPolicy.LocalOnly;
            break;
        case CustomErrorsMode.On:
            errorDetailPolicy
                = IncludeErrorDetailPolicy.Never;
            break;
        case CustomErrorsMode.Off:
            errorDetailPolicy
                = IncludeErrorDetailPolicy.Always;
            break;
        default:
            throw new ArgumentOutOfRangeException();
    }

    GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = errorDetailPolicy;

    ConfigureWindsor(GlobalConfiguration.Configuration);

    GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler()
    {
        PrincipalProvider = _container.Resolve<IProvidePrincipal>()
    });
}

public static void ConfigureWindsor(HttpConfiguration configuration)
{
    // Create / Initialize the container  
    _container = new WindsorContainer();

    // Find our IWindsorInstallers from this Assembly and optionally from our DI assembly which is in abother project.  
    _container.Install(FromAssembly.This());
    _container.Kernel.Resolver.AddSubResolver(new CollectionResolver(_container.Kernel, true));

    //Documentation http://docs.castleproject.org/Windsor.Typed-Factory-Facility.ashx  
    // Set the WebAPI DependencyResolver to our new WindsorDependencyResolver  
    var dependencyResolver = new WindsorDependencyResolver(_container);
    configuration.DependencyResolver = dependencyResolver;
}

温莎安装程序:

代码语言:javascript
复制
public class PrincipalsInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Classes.FromThisAssembly().BasedOn<DelegatingHandler>());

        container.Register(
            Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
        );
    }
}

修改了DummyPrincipalProvider (从DummyPrincipalProvider获得的原始版本)

代码语言:javascript
复制
public class DummyPrincipalProvider : IProvidePrincipal
{
    private IUserRepository _userRepo;

    public DummyPrincipalProvider(IUserRepository userRepo)
    {
        this._userRepo = userRepo;
    }

    public IPrincipal CreatePrincipal(string username, string password)
    {
        try
        {
            if (!this._userRepo.ValidateUser(username, password))
            {
                return null;
            }
            else
            {
                var identity = new GenericIdentity(username);
                IPrincipal principal = new GenericPrincipal(identity, new[] { "User" });

                if (!identity.IsAuthenticated)
                {
                    throw new ApplicationException("Unauthorized");
                }

                return principal;
            }
        }
        catch
        {
            return null;
        }
    }
}

WindsorDependencyResolver.cs:

代码语言:javascript
复制
internal sealed class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer _container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }

        _container = container;
    }

    public object GetService(Type t)
    {
        return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast<object>().ToArray();
    }

    public IDependencyScope BeginScope()
    {
        return new WindsorDependencyScope(_container);
    }

    public void Dispose()
    {

    }
}

WindsorDependencyScope.cs:

代码语言:javascript
复制
internal sealed class WindsorDependencyScope : IDependencyScope
{
    private readonly IWindsorContainer _container;
    private readonly IDisposable _scope;

    public WindsorDependencyScope(IWindsorContainer container)
    {
        if (container == null)
        {
            throw new ArgumentNullException("container");
        }
        _container = container;
        _scope = container.BeginScope();
    }

    public object GetService(Type t)
    {
        return _container.Kernel.HasComponent(t) ? _container.Resolve(t) : null;
    }

    public IEnumerable<object> GetServices(Type t)
    {
        return _container.ResolveAll(t).Cast<object>().ToArray();
    }

    public void Dispose()
    {
        _scope.Dispose();
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-04-02 07:59:49

我假设IProvidePrincipal是您自己的实现。使用IoC容器的最佳方法是成分根,这是唯一的IMHO。布莱的博客很好地解释了web的入口点/组合根。DelegatingHandler不是“请求解析”的一部分,因此您可以选择在容器作为私有变量存在的全局asax Application_start中解析它。

代码语言:javascript
复制
GlobalConfiguration.Configuration.MessageHandlers.Add(container.Resolve<BasicAuthMessageHandler>());

如果正确地注册了处理程序及其在容器中的所有依赖项,则无需进行其他操作:从容器中提取并添加到MessageHandlers中的处理程序实例将有一个IPrincipalProvider和(I)UserRepository。请记住,BasicAuthMessageHandler将执行单例操作,因此,如果您需要在每个方法调用上使用(I)UserRepository的新实例.您可以考虑使用TypedFactory来创建(I)UserRepository作为后期依赖项。

当然,从顶部图形组件开始的任何组件都必须是在容器中注册

这是很简单的方法..。如果您需要更复杂的术语,您可能最终也会为DelegatingHandlers创建“组合根”。

顺便说一句:永远不要做像UserRepository userRepo =新UserRepository();或者PrincipalProvider = new DummyPrincipalProvider()这样的事情。

不应明确创建“行为实例”:容器负责在正确的时间提供正确的实例.

按照Jon: now DummyPrincipalProvider看起来很好:请记住,因为DummyPrincipalProvider是在消息处理程序中创建的(由于全局注册而充当单例),您将始终重用相同的实例。

而不是你的水管

代码语言:javascript
复制
var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;

我宁愿使用ploeh实现(见上文)。

你的注册

代码语言:javascript
复制
container.Register(
    Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
    .UsingFactoryMethod(kernel => kernel.Resolve<DummyPrincipalProvider>())
);

应改为

代码语言:javascript
复制
container.Register(
    Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
);

这是错误的..。容器必须解决它,而不是显式地解决它。

代码语言:javascript
复制
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler());

坚持上面的配置:通过容器解析BasicAuthMessageHandler。

如果有用的话请告诉我。

PS:你在容器中注册了TypedFactory设施,但你没有使用它.只是想让你知道。您将DelegatingHandler注册为瞬态的,但请记住,它们在设计上将是“单例”:将其添加到MessageHandlers集合中意味着它们将在每个请求中被重用。

乔恩编辑2:

我添加了一个github样本。您应该能够构建它并使用NuGet包恢复运行它。

关于PerWebRequestdepends的问题-- UserRepository在NHibernate工厂会话上的依赖性--创建会话"PerWebRequest":由于HttpContext,您无法解决Application_Start中的IPrincipalProvider>IUserRepository->ISession。如果您确实需要一个工作的IUserRepositry,那么w/ IPrincipalProvider依赖必须改为IUserRepositoryFactory(TypedFactory)。我试图使用类型化的工厂修复您的示例,但由于我不是这方面的专家,所以我没有做进一步的工作,而不是w/ NHibernate配置问题。

如果你需要帮助工厂的事..。我和LMK将使用DummyPrincipalProvider中的工厂更新我的git示例

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15736402

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档