How to inject my ambient context?

Topics: Writing modules
Apr 1, 2013 at 6:32 PM
I wrote an ambient context class to collect properties information. The reason I use an ambient context is because I can't guarantee where it will be used so I can't just rely on constructor injection.

My question is how do I inject my ambient context with an implementation in Orchard?

I tried this but it didn't work:
            builder.RegisterType<NotificationP>().As<NotificationProfileContext>().SingleInstance();
Here is my ambient context:
    public abstract class NotificationProfileContext : IDependency
    {
        private static NotificationProfileContext ctx;

        public static NotificationProfileContext Current
        {
            get
            {
                if (ctx == null)
                {
                    ctx = NotificationProfileContext.Default;
                }
                return ctx;
            }
            set
            {
                ctx = value;
            }
        }

        // TODO do not return null
        public static NotificationProfileContext Default = null;

        public abstract string EmailOutHost { get; }
        public abstract string EmailOutUsername { get; }
        public abstract string EmailOutPassword { get; }
        public abstract string EmailOutFrom { get; }
        public abstract string NotificationFrom { get; }
        public abstract string ConnectionString { get; }
    }
and here is a snippet of the implementation:
    public class NotificationP : NotificationProfileContext
    {
        private NotificationSettingsPart notificationSettings;
        public NotificationP(IOrchardServices orchardServices)
        {
            notificationSettings = orchardServices.WorkContext.CurrentSite.As<NotificationSettingsPart>();
        }

        public override string EmailOutHost
        {
            get { return notificationSettings.EmailOutHost; }
        }
Apr 1, 2013 at 7:15 PM
I suppose I have to add:
            var test = orchardServices.WorkContext.Resolve<NotificationProfileContext>();
            NotificationProfileContext.Current = test;
But then the question is where do I put this code? I don't want to have to add it to every controller.
Coordinator
Apr 5, 2013 at 8:55 AM
Implementing a singleton is almost always a bad idea. Using static to implement a singleton is almost always a worse idea. Looks like your thing should be a site setting instead.
Apr 5, 2013 at 5:02 PM
BertrandLeRoy wrote:
Implementing a singleton is almost always a bad idea. Using static to implement a singleton is almost always a worse idea. Looks like your thing should be a site setting instead.
Interesting, I'm fairly new to Dependency Injection and Unit Testing. The DI book I am reading suggests using ambient contexts under certain situations. In this case I cannot use constructor injection because this object could be used anywhere and not necessarily in only Orchard modules.

If I use site settings, is there a pattern I should be using to access that information in unit testing too?
Apr 6, 2013 at 1:05 AM
I was able to refactor my code and remove the singletons. Using proper constructor injection now.
Coordinator
Apr 6, 2013 at 1:27 AM
Great.