如何使用Simple Injector将依赖项注入WCF属性

时间:2015-03-27 16:40:03

标签: wcf attributes inversion-of-control 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将依赖项注入此属性?我谷歌了一段时间,但我发现的唯一的东西是Ninject,或者在WebAPI上注入过滤器。

干杯!

1 个答案:

答案 0 :(得分:8)

您无法对属性进行构造函数注入,因为正是CLR可以控制属性的创建;不是DI库。虽然您可以在创建属性之后初始化/构建属性并使用属性注入注入依赖项,但由于以下原因,这是非常危险的:

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

相反,更好的方法是创建passivehumble 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需要不同的实现,但概念保持不变。