加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – ASP.NET Web API中的Castle Windsor / DelegatingHandler

发布时间:2020-12-16 01:54:00 所属栏目:百科 来源:网络整理
导读:我决定清理这篇文章,并在 ge.tt/3EwoZEd/v/0?c发布了一个示例项目 已经花费了大约30个小时,但仍然无法弄明白……帮助真的很感激! 我有一个使用此代码的ASP.NET Web API解决方案:http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-u
我决定清理这篇文章,并在 ge.tt/3EwoZEd/v/0?c发布了一个示例项目

已经花费了大约30个小时,但仍然无法弄明白……帮助真的很感激!

我有一个使用此代码的ASP.NET Web API解决方案:http://www.piotrwalat.net/basic-http-authentication-in-asp-net-web-api-using-message-handlers/实现“使用消息处理程序在ASP.NET Web API中进行基本HTTP身份验证”.我是IoC / DI的新手,我正试图让它与Castle Windsor合作.

我一直在尝试很多不同的东西但是我得到以下错误之一取决于我做错了什么:

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

以下是我的代码:

的Global.asax.cs:

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;
}

Windsor安装人员:

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(来自我从URL above获得的原始版本):

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:

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:

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();
    }
}

解决方法

我假设IProvidePrincipal是您自己的实现.
最好的方式,唯一一个使用IoC容器的恕我直言,是 Composition Root.
web001的入口点/组合根已在 ploeh’s blog中得到很好的解释.
DelegatingHandler不是“请求解析”的一部分,因此您可以选择在容器作为私有变量存在的全局asax Application_start中解析它.

GlobalConfiguration.Configuration.MessageHandlers.Add(container.Resolve<BasicAuthMessageHandler>());

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

当然,从您的顶部图形组件开始的任何组件都必须是register in the container.

这是一种简单的方法……如果你需要更加复杂的东西,你最终可能会为DelegatingHandlers创建你的“组合根”.

顺便说一下:从来没有,做过像这样的感觉
UserRepository userRepo = new UserRepository();
或PrincipalProvider = new DummyPrincipalProvider()

没有任何“行为实例”应该明确创建:容器负责在正确的时间提供正确的实例…

根据Jon Edit:
现在DummyPrincipalProvider看起来很好:请记住,因为DummyPrincipalProvider是在消息处理程序中创建的(由于全局注册而充当单例),所以你总是重用相同的实例.

而不是你的管道

var dependencyResolver = new WindsorDependencyResolver(_container);
configuration.DependencyResolver = dependencyResolver;

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

你的注册

container.Register(
    Component.For<IProvidePrincipal>().ImplementedBy<DummyPrincipalProvider>()
    .UsingFactoryMethod(kernel => kernel.Resolve<DummyPrincipalProvider>())
);

应该换成

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

那是错的……容器必须解决它,而不是你明确地解决它

GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthMessageHandler());

坚持我的配置如上:BasicAuthMessageHandler通过容器解决.

如果有效,请告诉我.

PS:您在容器中注册了TypedFactory工具,但您没有使用它……只是为了让您知道.
您注册了DelegatingHandler(s)作为Transient,但请记住它们将被设计为“singleton”:将它添加到MessageHandlers集合意味着它们将在每个请求上重用.

根据Jon Edit 2:

我添加了一个sample on github.您应该能够构建它并使用NuGet Package Restore运行它

关于PerWebRequest的问题取决于NHibernate工厂会话创建会话“PerWebRequest”的UserRepository的依赖关系:由于HttpContext,您无法在Application_Start中解析IPrincipalProvider-> IUserRepository-> ISession.如果你真的需要一个IUserRepositry工作w / IPrincipalProvider依赖必须是IUserRepositoryFactory(TypedFactory).
我尝试使用打字的工厂来修复你的样本并且它有效,但是我遇到了NHibernate配置的问题,因为我不是那个专家,所以我没有再进一步了.

如果您需要帮助w /工厂的东西… LMK和我将使用DummyPrincipalProvider中的工厂更新我的git示例

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读