1

In my project, I have a service class.

class KLAService : IKLAService
{
    CentralLogic centralLogic;

    .....
}

Using this class, I set up the ServiceHost like this:

centralLogic = new CentralLogic();

ServiceHost host = new ServiceHost(typeof(KLAService));
using (host)
{ 
    host.Open();

    Application app = new Application();
    app.Run(new ConfigurationWPF.MainWindow(centralLogic));

    host.Close();
}

As it might have become clear, I create one instance of the CentralLogic class. This very instance is used in the UI but also in the host to manage other stuff in my solution.

The problem I'm having now, is to set the centralLogic-variable in the KLAService-class (or in the host). I don't know how to do this. I've read about the plugin Ninject and how to inject objects in the service, but that's way out of my league and I can't help but think there is an easy way.

How can I achieve my goal the best?

EDIT: Another solution proposed was to start the ServiceHost and let CentralLogic get created there instead of the other way around. That would mean the ServiceHost needs some sort of a constructor. I don't know what the best practice is nor how to achieve this. Any help is appreciated.

Joetjah
  • 6,292
  • 8
  • 55
  • 90
  • Possible duplicate of http://stackoverflow.com/questions/2454850/how-do-i-pass-values-to-the-constructor-on-my-wcf-service – haim770 Jun 03 '13 at 08:10

2 Answers2

1

The simplest solution is to create a singleton for the CentralLogic class.

If you want to do dependency injection, I would recommend structuremap and you can set it up pretty easily with nuget and I'd advice for you to do the injection in the KLAService

Here's a console app that shows how to set it up and inject some local object to other classes:

class KLAService : IKLAService
{
    // Constructor injection
    public KLAService(ICentralLogic logic)
    {
        Console.WriteLine(logic.Value);
    }

    // Manual instance creation
    internal void PrintLogicValue()
    {
        var logic = ObjectFactory.Container.GetInstance<ICentralLogic>();
        Console.WriteLine(logic.Value);
    }
}

interface IKLAService
{
}

class CentralLogic : ICentralLogic
{
    public int Value { get; set; }

    public CentralLogic()
    {
        Value = 12345;
    }
}

interface ICentralLogic
{
    int Value { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var logic = new CentralLogic();

        ObjectFactory.Initialize(x => x.Scan(scan => scan.TheCallingAssembly()));
        ObjectFactory.Container.Configure(x => x.For<ICentralLogic>().Use(y => logic));

        var service = ObjectFactory.Container.GetInstance<KLAService>();
        service.PrintLogicValue();

        Console.ReadKey();
    }
}

When the code calls var service = ObjectFactory.Container.GetInstance<KLAService>(); the constructor expects an object of type ICentralLogic and the injector will provide the configured logic object.

Alternatively, you can manually get the configured object for ICentralLogic with ObjectFactory.Container.GetInstance<ICentralLogic>();.

Candide
  • 30,469
  • 8
  • 53
  • 60
  • This makes sense. How would creating the `ServiceHost` fit in here? – Joetjah Jun 03 '13 at 08:02
  • The simplest approach is to change `new ServiceHost(typeof(KLAService))` with `new ServiceHost(ObjectFactory.Container.GetInstance())` – Candide Jun 03 '13 at 08:23
  • Ok, let me try this one out. Can you explain to me what you do with the two `ObjectFactory` lines? After that, you declare the `var service`. I could use that `service` in the `new ServiceHost...` line, correct? – Joetjah Jun 03 '13 at 08:25
  • `ObjectFactory.Initialize` initializes the structure map to scan the types of the calling assembly, ie, the current running app. The second line `ObjectFactory.Container.Configure` tells it whenever you need an instance with `ObjectFactory.Container.GetInstance` you will get a the configured object. Your code would then become: `ServiceHost host = new ServiceHost(ObjectFactory.Container.GetInstance());` – Candide Jun 03 '13 at 08:39
  • Singletons are good for a quick solution, and by no means, I've used them too in many projects. However, when you have to do unit testing configuring all the singletons will be quite a hassle. If you are planning on doing unit testing, I really would urge you to veer away from singletons, they're just too much of a headache to maintain and configure, especially if you want to write reusable code by others. – Candide Jun 03 '13 at 22:11
1

I don't think you really need dependency injection. Since CentralLogic has a single instance, it is effectively a singleton. Read about singleton pattern here.

You can implement the singleton pattern on CentralLogic

public sealed class CentralLogic
{
    private static readonly Lazy<CentralLogic> lazy =
        new Lazy<CentralLogic>(() => new CentralLogic());

    public static CentralLogic Instance { get { return lazy.Value; } }

    private CentralLogic()
    {
    }
}

Then in the Service Impl's contructor (and in the UI), you get the instance, this way:

class KLAService : IKLAService
{
    CentralLogic m_centralLogic;

    public KLAService() 
    {
       m_centralLogic = CentralLogic.Instance;
       ....
    }
}

There is no need to pass anything to ServiceHost.

The most important thing for you here is make sure your CentralLogic's instance is thread safe.

YK1
  • 7,327
  • 1
  • 21
  • 28
  • This is more like it, I didn't understand why everything had to be so difficult. In the `ServiceHost`, how can I call the constructor? I'm having troubles with that. On the other hand, I don't really need a constructor which declares `m_centralLogic`, but could just use for example `CentralLogic.Instance.GetUsers();`. Let me try this one out. – Joetjah Jun 03 '13 at 09:31
  • You should not have problem with `KLAService` constructor - it is default (parameter-less) constructor after all - WCF will handle it. Yes, you can use - `CentralLogic.Instance.Methods()` - please make sure all the methods and properties of the `CentralLogic` class are thread-safe in thier implementation. – YK1 Jun 03 '13 at 09:34