1

The ServiceStack AppHost provides a Funq.Container with which to register types that can be injected into Services as they are constructed. Can this container be used to register an ILog factory that returns an ILog appropriate for the type in which it will reside?

Put another way, given the following AppHost:

public class AppHost : AppHostBase
{
    public AppHost() : base("Example Web Services", Assembly.GetExecutingAssembly())
    {
    }

    public override void Configure(Funq.Container container)
    {
        var baseLogFactory = new ServiceStack.Logging.NLogger.NLogFactory();
        LogManager.LogFactory = new ServiceStack.Logging.Elmah.ElmahLogFactory(baseLogFactory);
        // Would prefer to register a Func<Type, ILog> one time here
    }
}

And a Service:

public class FooService : IService<FooRequest>
{
    static ILog Log { get { return LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); } }
    // Would prefer:
    // public ILog { get; set; }

    public object Execute(FooRequest request)
    {
        Log.Info("Received request: " + request.Dump());
        return new FooResponse();
    }
}

Is there anything I can add to AppHost.Configure to avoid the static ILog boilerplate in all of my Services (and instead just use a plain old ILog property)?

Put a third way, most succinctly, Can I use Funq.Container for ILog injection instead of LogManager?

Jacob Foshee
  • 2,704
  • 2
  • 29
  • 48
  • IIRC, Funq isn't well suited for automated property injection. I suppose you could could implement the `InitializedBy` portion of any type and have it assign the appropriate logger. So `container.Register>(() => new FooService()).InitializedBy((c, foo) => foo.Log = c.Resolve(typeof(FooService)))` But you can see how that can get unweildy and have to explicitly apply it to all types that you intend to log with. Personally, I just use snippets to insert the code you have (but as a static readonly field rather than a property to avoid extra lookups) – Chris Sinclair Jan 15 '13 at 22:56
  • In addition, I'm not keen on the exposing of `ILog` as a public get/set member; of course, that's property injection for you. I suppose that's a whole other debate entirely. – Chris Sinclair Jan 15 '13 at 22:58
  • `IIRC, Funq isn't well suited for automated property injection` - I am afraid that you are not recalling it properly. ServiceStack will do it for you. See my answer. – Darin Dimitrov Jan 15 '13 at 22:58
  • @DarinDimitrov Ahh, sorry, I glossed over the "ServiceStack" part of it. :) My prior experience used Funq directly and not with ServiceStack. Good that you're here to take my foot out of my mouth! – Chris Sinclair Jan 15 '13 at 23:03

1 Answers1

1
container.Register<ILog>(
    ctx => LogManager.LogFactory.GetLogger(typeof(IService))
);

Now your service could look like this:

public class FooService : IService<FooRequest>
{
    public ILog { get; set; }

    public object Execute(FooRequest request)
    {
        Log.Info("Received request: " + request.Dump());
        return new FooResponse();
    }
}
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • Does Funq automagically resolve/apply property injection? I didn't think it did (memory hazy though) – Chris Sinclair Jan 15 '13 at 22:54
  • Yes, it automatically does constructor **and** property injection. – Darin Dimitrov Jan 15 '13 at 22:58
  • This is close, but not quite. I would like to get the logger for the concrete type so that the log message looks like "2013-01-15 17:23:20.6192|INFO|FooService|..." rather than "2013-01-15 17:23:20.6192|INFO|IService|..." – Jacob Foshee Jan 15 '13 at 23:26
  • 1
    I am not sure whether this is possible. – Darin Dimitrov Jan 16 '13 at 06:38
  • 2
    What is the purpose of injecting ILog? Unless you are doing some hardcore mods to something like LogEventInfo in Nlog, I don't see a need to inject this. That's why the LogManager class exists. To accomplish what you are after, just do ILog log = LogManager.GetCurrentClassLogger(); – Fred Jan 17 '13 at 04:31