如何使用简单注入器将依赖项注入 WCF 属性

How to inject dependencis into WCF Attribute with Simple Injector

我有一堆与 REST 和 SOAP 一起工作的 WCF 服务。我创建了一个 WCF 属性,用于检查当前的 httpcontext 是否存在,如果存在则使用 cookie 身份验证,否则使用自定义 WCF 身份验证。

我的属性如下所示:

Public Class AuthRequired
    Inherits Attribute
    Implements IOperationBehavior, IParameterInspector

    Public Sub AddBindingParameters(operationDescription As OperationDescription, bindingParameters As Channels.BindingParameterCollection) Implements IOperationBehavior.AddBindingParameters

    End Sub

    Public Sub ApplyClientBehavior(operationDescription As OperationDescription, clientOperation As ClientOperation) Implements IOperationBehavior.ApplyClientBehavior

    End Sub

    Public Sub ApplyDispatchBehavior(operationDescription As OperationDescription, dispatchOperation As DispatchOperation) Implements IOperationBehavior.ApplyDispatchBehavior
        dispatchOperation.ParameterInspectors.Add(Me)
    End Sub

    Public Sub Validate(operationDescription As OperationDescription) Implements IOperationBehavior.Validate

    End Sub

    Public Sub AfterCall(operationName As String, outputs() As Object, returnValue As Object, correlationState As Object) Implements IParameterInspector.AfterCall

    End Sub

    Public Function BeforeCall(operationName As String, inputs() As Object) As Object Implements IParameterInspector.BeforeCall
        ' IDS is the custom authentication service.
        If IDS.Usuario Is Nothing Then
            If HttpContext.Current Is Nothing Then
                Throw New SecurityException("Las credenciales no son válidas para esta operación o no fueron provistas.")
            Else
                Throw New WebFaultException(Of String)("ACCESO DENEGADO. REVISE SUS CREDENCIALES.", Net.HttpStatusCode.Forbidden)
            End If
        End If
    End Function
End Class

所以,我的问题是如何使用 Simple Injector 将依赖项注入此属性?我 google 了一段时间,但我唯一发现的是 Ninject,或者在 WebAPI 上注入过滤器。

干杯!

您不能对属性进行构造函数注入,因为是 CLR 控制着属性的创建;不是 DI 库。尽管您可以 initialize/build-up 属性在创建后使用 属性 注入来注入依赖项,但由于以下原因,这是非常危险的:

  • 许多框架缓存属性,这使它们成为有效的单例。这将导致 Captive Dependencies 在依赖项本身不是单例的情况下。
  • 很难甚至不可能让容器验证从属性开始的对象图,这可能会在 verifying and diagnosing 容器配置时造成错误的安全感。

相反,更好的方法是使属性成为 passive or humble objects

对于一个不起眼的对象,您可以将属性中的所有逻辑提取到它自己的服务中。留在属性中的唯一代码是调用您的容器或服务定位器来解析该服务,然后您调用该方法。这可能看起来像这样(请原谅我的 C#):

public class AuthRequiredAttribute : Attribute, IOperationBehavior
{
    public object BeforeCall(string operationName, object[] inputs) {
        var checker = Global.Container.GetInstance<IAuthorizationChecker>();
        checker.Check();
    }
}

// Attribute's logic abstracted to a new service. This service can be
// registered, verified, diagnosed, and tested.
public class AuthorizationChecker : IAuthorizationChecker
{
    private readonly IDS authenticationService;
    public AuthorizationChecker(IDS authenticationService) {
        this.authenticationService = authenticationService;
    }

    public void Check() {
        if (this.authenticationService.Usuario == null) {
            if (HttpContext.Current == null) {
                throw new SecurityException();
            } else {
                throw new WebFaultException<string>();
            }
        }
    }
}

这需要您以您的属性可以解析所需服务的方式公开容器。这样做的好处是它很容易实现,非常干净。缺点是你必须回退到 Service Locator anti-pattern 才能让它工作,并且你必须确保你的服务已注册,因为容器不会对此发出警告,因此,这将失败运行时而不是在调用 container.Verify().

的集成测试内部的应用程序启动期间

第二个选项是使用被动属性。当您拥有多个这些属性时,这尤其有用。 This article 描述了被动属性背后的基本思想,并举例说明了如何在 Web 中实现它 API。 WCF 有不同的拦截点,因此将其应用于 WCF 需要不同的实现,但概念保持不变。