Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to inject dependencis into WCF Attribute with Simple Injector

I have a bunch of WCF services that works with REST and SOAP. I have created an WCF attribute who checks if the current httpcontext exists, if exists it use cookie authentication, other way it use custom WCF authentication.

My attribute looks like this:

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

So, my question is how can I inject dependencies into this attribute using Simple Injector? I google for a while but the only thing I found was for Ninject, or inject filters on WebAPI.

Cheers!

like image 871
Emanuel Gianico Avatar asked Mar 27 '15 16:03

Emanuel Gianico


Video Answer


1 Answers

You can't do constructor injection into attributes, because it is the CLR who is in control over the creation of attributes; not the DI library. Although you could initialize/build-up attributes after they have been created and inject dependencies using property injection, this is very risky for the following reasons:

  • Many frameworks cache attributes, which make them effectively singletons. This will cause Captive Dependencies in cases the dependencies themselves aren't singletons themselves.
  • It will be hard to impossible to let the container verify object graphs that start from the attributes, which might cause a false sense of security when verifying and diagnosing the container's configuration.

Instead, a much better approach is to either make attributes either passive or humble objects.

With a humble object, you extract all logic out of the attribute into its own service. The only code that will be left in the attribute is a call to your container or Service Locator to resolve that service and you call the method. This might look like this (excuse my 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>();
            }
        }
    }
}

This requires you to expose the container in a way that your attributes can resolve the services they need. Advantage of this is that it is easy implemented, quite clean. Downside is that that you have to fall back to the Service Locator anti-pattern to get this working, and you have to make sure that your service is registered, because the container won't warn about this and this will, therefore, fail at runtime instead of during application startup of inside an integration test that calls container.Verify().

The second option is using passive attributes. This is especially useful when you have multiple of these attributes. This article describes the basic idea behind passive attributes and gives an example how to implement this in Web API. WCF has different interception points, so applying this to WCF requires a different implementation, but the concept stays the same.

like image 90
Steven Avatar answered Oct 21 '22 09:10

Steven