2

I have a WCF service hooked with a Unity interceptor and all calls to the WCF layer is intercepted by Unity for auditing purposes. However, Unity seems to intercept ALL calls to resolve the interface, whether the call originated from WCF or internally.

Consider the following code:

[ServiceContract]
public interface IMyUtilityService
{
    [OperationContract]
    void DoUtilityStuff();
}

[ServiceContract]
public interface IMyService
{
    [OperationContract]
    void DoStuff();
}

class MyService : IMyService
{
    public MyService(IMyUtilityService myUtilityService)
    {
    }

    public void DoStuff()
    {
    }
}

The service interfaces are registered with Unity with interception:

container.RegisterType<IMyUtilityService, MyUtilityService>(
    new Interceptor<InterfaceInterceptor>(), 
    new InterceptionBehavior<PipelineInterceptor>());

container.RegisterType<IMyService, MyService>(
    new Interceptor<InterfaceInterceptor>(), 
    new InterceptionBehavior<PipelineInterceptor>());

When a WCF call is made to IMyService I get the interceptor firing which is great and I can do some auditing. When IMyService is resolved, however, the interceptor triggers again as IMyUtilityService is injected into the IMyService constructor.

Is there a way to configure Unity to prevent this? Or is there a way inside the interceptor to determine that the interception was directly triggered by WCF? Or do I need to create a different interface layer to separate the external calls and the internal calls?

Hawk
  • 692
  • 2
  • 7
  • 18
  • Why are you using the service-interface internally? The problem should solve itself by moving your logic from the service-interface into a more proper class (manager, repo etc). Then you can resolve that class/interface instead. The service-layer should be as "dumb" as possible. – smoksnes May 27 '16 at 05:15
  • Our architecture is divided into a repository layer and a service layer. Services can be consumed by other services. Some services are exposed via WCF. – Hawk May 27 '16 at 05:46
  • I see. Then you should be able to use my answer below. – smoksnes May 27 '16 at 05:48
  • If I understand your suggestion correctly then I should introduce a business logic layer between the service layer and the data layer where all business logic resides. I believe we chose not to do this as in most cases it will be a straight mapping of the WCF service onto a business logic layer. Also, the application is light on business logic so dumb service, dumb business logic, some persistence logic. The layer felt redundant. – Hawk May 27 '16 at 05:53
  • I totally see your point. My suggestion only makes sense if you got a lot of logic in your services. – smoksnes May 27 '16 at 05:54

2 Answers2

1

I managed to solve the issue with creative registration of services in Unity. Previously a service was registered with Unity as either an internal only service or as a WCF service with interception. If the WCF service is then used internally problems ensued with the interceptor.

Note: the problem with the interceptor may have been because we used Lazy resolution of dependencies.

The problem can be solved by registering all services with Unity for internal resolution and then registering WCF services with explicit names. When the WCF endpoint is activated the instance can be resolved using the explicit name.

For instance, registering the service:

container.RegisterType(interfaceType, implementationType);

if (isWCF)
    container.RegisterType(
        interfaceType, 
        implementationType, 
        "WCF", // name for resolving WCF services
        new Interceptor<InterfaceInterceptor>(), 
        new InterceptionBehaviour<PipelineInterceptor>());

And then creating the instance in the Instance Provider:

public object GetInstance(InstanceContext instanceContext, Message message)
{
    return _container.Resolve(_interfaceType, "WCF");
}

Solution is preferred as the interceptor is now only registered and activated against invocation of the WCF services.

Hawk
  • 692
  • 2
  • 7
  • 18
0

The simplest way could be to check if you got an OperationContext.

if (OperationContext.Current != null)
{
    // Called through WCF.
}
else
{
    // Not WCF.
}

And in an interceptor.

public class PipelineInterceptor : IInterceptionBehavior
{
    public bool WillExecute
    {
        get { return OperationContext.Current != null; }
    }

    // Other ...

}
smoksnes
  • 10,509
  • 4
  • 49
  • 74