1

I'm building server in C# and WCF. I have my Service and Contract with methods used by Client app. But the whole logic is separated in different class: BusinessLogic. I will inject all I need in BussinessLogic, like repositories/database providers or other data stored in memory. I use Poor man's dependency to build my BussinessLogic (it's my composition root). It's a console application, so BussinessLogic is creaed/resolved in Main(string[] args) method.

My problem is that WCF services are created with parameterless constructor, independent of the rest of the server. They are created every time, when used be the Client.

This is how my server looks like:

    static void Main(string[] args)
    {
        ServiceHost host = new ServiceHost(typeof(ServiceLayer), new Uri("net.tcp://localhost:8005"));
        host.Open();

        Console.WriteLine("Running... Press key to stop");
        Console.ReadKey();
    }

My services:

[ServiceContract]
public interface IServiceContract
{
    [OperationContract]
    ...
}

public class ServiceLayer : IServiceContract
{
    IBusinessLogic _businessLogic;
    public ServiceLayer(IBusinessLogic businessLogic)
    {
        _businessLogic = businessLogic;
    }

    // Here, I would like to use IBusinessLogic
    ...
}

I found how to do this using IoC here (I didn't test it tho), but I'm looking for a best solution with Poor man's dependency, without any container or tool, just C# and .NET. If there isn't any solution as good as IoC or close to it, please comment.

Tom
  • 47
  • 7

2 Answers2

4

If you model your application around commands and queries, it becomes very easy to create your WCF service as a thin maintenance free layer with just one service class.

When you have just one service class, you can use this service class itself as Composition Root or Humble Object and this means you don't need to inject any dependencies into the service class. This prevents you from having to do any integration into the WCF pipeline when it comes to dependency injection, at all!

When you apply these patterns, you can reduce your service to the following code:

[ServiceKnownType(nameof(GetKnownTypes)]
public class CommandService
{
    [OperationContract, FaultContract(typeof(ValidationError))]
    public void Execute(dynamic command) {
        CreateCommandHandler(command.GetType()).Handle(command);
    }

    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider cap) {
        yield return typeof(ShipOrder);
        yield return typeof(CancelOrder);
        yield return typeof(ConfirmOrder);
    }

    // Singletons
    private static IUserContext userContext = new WcfUserContext();

    private static dynamic CreateCommandHandler(Type commandType)
    {
        var context = new DbContext();

        if (commandType == typeof(ShipOrder))
            return Decorate(new ShipOrderHandler(context));
        if (commandType == typeof(CancelOrder))
            return Decorate(new CancelOrderHandler(context));
        if (commandType == typeof(ConfirmOrder))
            return Decorate(new ConfirmOrderHandler(context, userContext));

        throw new ArgumentException("Unknown: " + commandType.FullName);
    }

    private static ICommandHandler<T> Decorate<T>(ICommandHandler<T> handler) {
        return new WcfExceptionTranslatorCommandHandlerDecorator(
            new LoggingCommandHandlerDecorator(
                new Logger(),
                new AuditTrailingCommandHandlerDecorator(
                    new PermissionCheckerCommandHandlerDecorator(
                        new ValidationCommandHandlerDecorator(
                            new TransactionCommandHandlerDecorator(
                                handler))))));
    }
}
Steven
  • 166,672
  • 24
  • 332
  • 435
  • Thanks @Steven, I'll have to read few articles of yours to fully understand your answer, It's a little bit.. not entirely clear. But as far as I see now you have `CommandService` without implementing its interface (Contract) which is kinda odd. Second thing, I'm looking at `solidservices` project now and this Bootstrapper static class looks a little bit like Service Locator. It's not injected, but it's global static class – Tom Dec 02 '15 at 14:07
  • Hi @Tom, WCF can work perfectly fine without using an interface, but if an interface is really relevant to you, you can simply add it. I have never needed it. About the Service Locator, please try to understand the concept of the [Composition Root](http://blog.ploeh.dk/2011/07/28/CompositionRoot/) and [when something is and isn't a Service Locator](http://blog.ploeh.dk/2011/08/25/ServiceLocatorrolesvs.mechanics/). In the solidservices project, the `CommandService` class is a Humble Object and can be viewed as being part of the Composition Root. – Steven Dec 02 '15 at 14:43
3

Poor man's DI is now called Pure DI.

You can use Pure DI to compose WCF applications. You need to do that in the Composition Root.

In WCF application, the Composition Root is a custom ServiceHostFactory.

This answer shows an example of how to do that.

You can customize the code in that answer to add more dependencies.

Community
  • 1
  • 1
Yacoub Massad
  • 27,509
  • 2
  • 36
  • 62
  • First thing: Correct me if I'm wrong, but when I want to self-host I don't need `MyServiceHostFactory`. Don't have to touch `ServiceHostFactory` at all, right? It's needed incase of hosting in IIS. Second thing: What if I want more then just one `ServiceLayer`. For example I could have `SecondServiceLayer : ISecondServiceContract` service :/ – Tom Dec 02 '15 at 00:22
  • To add to my "First thing": I could say `MyInstanceProvider` is my kinda "Composition Root". It's created by `MyServiceHost`, but `IDependency` object (so that'd be my server logic) is "stored" in my `MyInstanceProvider` provider. So every time, when new request is sent from Client and my `ServiceLayer` service needs to be created it doesn't create new `IDependency` which is good. `IDependency` has only one instnace during the whole life of the server. Is that correct, what I've written ? – Tom Dec 02 '15 at 00:37
  • @Tom, you are right about IIS and `ServiceHostFactory`. When hosting outside of IIS, you have more options. If you host your WCF service in a Console Application (for example), the composition root becomes the `main` method and you would create your dependencies there and inject whatever dependencies to custom Instance Providers that you create for your WCF services. You can create two instance provider classes for the two services that you have. – Yacoub Massad Dec 02 '15 at 14:33
  • One question. Is there already a concrete class that implements `IInstanceProvider` and `IContractBehavior`? I mean, right now I have to write a lot of code (MyInstanceProvider class) just to implement my constructor (with injection) and `GetInstance(InstanceContext instanceContext)` method to new my service. I could derive from class that implements those two interfaces and just override this single method and add my constructor with injection. It would be easier. Of course if such class exists – Tom Dec 02 '15 at 16:41