Получение Ninject для работы

Очевидно, я что-то упустил. У меня есть приложение MVC и я установил Ninject 3 и расширения MVC3 (хотя я использую MVC4). у меня есть SiteSettings класс, на который ссылается весь проект, который выглядит так:

public class SiteSettings
{
    private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
    private static ObservableDictionary<string, string> settings;
    private static bool Initialized = false;
    private static DataPersister persister;

    public static void Initialize()
    {
        if (Initialized) throw new InvalidOperationException("The SiteSettings object has already been initialized.");
        persister = new DataPersister();
        using (var u = persister.UnitOfWorkFactory.GetUnitOfWork())
        {
            var settingsList = u.SiteSettings.GetAll();
            settings = new ObservableDictionary<string, string>(settingsList.ToDictionary(key => key.SiteSettingName, value => value.SiteSettingValue));
            settings.OnChange += new kvpChangeEvent<string, string>(settings_OnChange);
        }
        Initialized = true;
    }

    static void settings_OnChange(object sender, odKVPChangeEventArgs<string, string> e)
    {
        using (var u = persister.UnitOfWorkFactory.GetUnitOfWork())
        {
            var setting = u.SiteSettings.GetByName(e.Key);
            setting.SiteSettingValue = e.Value;
            u.SiteSettings.Update(setting);
            u.Save();
            Logger.Info(i => i("Changed the '{0}' site setting from '{1}' to '{2}'.", e.Key, e.OldValue, e.Value));
        }
    }

    private static int _ItemsPerPage;
    public static int ItemsPerPage
    {
        get
        {
            return _ItemsPerPage;
        }
        set
        {
            _ItemsPerPage = value;
            settings["itemsPerPage"] = value.ToString();
        }
    }

    private static int _SessionLifeInMinutes;
    public static int SessionLifeInMinutes
    {
        get
        {
            return _SessionLifeInMinutes;
        }
        set
        {
            _SessionLifeInMinutes = value;
            settings["sessionLifeInMinutes"] = value.ToString();
        }
    }

    private static string _DateFormat;
    public static string DateFormat
    {
        get
        {
            return _DateFormat;
        }
        set
        {
            _DateFormat = value;
            settings["defaultDateFormat"] = value;
        }
    }
}

Я построил объект персистентности данных так:

public class DataPersister
{
    public IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
}

... и у меня есть NinjectWebCommon.cs выглядит так:

public static class NinjectWebCommon
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();

    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start()
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
    }

    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }

    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {
        var kernel = new StandardKernel();
        kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
        kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();

        RegisterServices(kernel);
        return kernel;
    }

    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<IUnitOfWork>().To<NHUnitOfWork>();
        kernel.Bind<IUnitOfWorkFactory>().To<NHUnitOfWorkFactory>();
    }
}

Мне кажется, я выполнил все свои требования для внедрения зависимости. мой Global.asax.csApplication_Start() выглядит так:

protected void Application_Start()
{
    ViewEngines.Engines.Clear();
    ViewEngines.Engines.Add(new MonoRazorViewEngine());

    AreaRegistration.RegisterAllAreas();
    RegisterGlobalFilters(GlobalFilters.Filters);
    RegisterRoutes(RouteTable.Routes);
    ControllerBuilder.Current.DefaultNamespaces.Add("MyApplication.Application.Controllers");
    Initialize.Security();
    SiteSettings.Initialize();
}

... и все же мой SiteSettings класс всегда имеет нуль IUnitOfWorkFactory когда я пытаюсь собрать нужные мне данные.

Что я делаю неправильно? Кажется, все так, как показывают все примеры, но я не получаю любви.

ОБНОВИТЬ

Используя совет Бассама Механни, я переписал свой DataPersister класс, чтобы выглядеть так:

public class DataPersister
{
    private IUnitOfWorkFactory UnitOfWorkFactory;
    public DataPersister(IUnitOfWorkFactory unitOfWorkFactory)
    {
        UnitOfWorkFactory = unitOfWorkFactory;
    }
    public IUnitOfWork GetUnitOfWork()
    {
        return UnitOfWorkFactory.GetUnitOfWork();
    }
}

... но, конечно, теперь мой SiteSettings класс жалуется на мой конструктор без параметров. Что мне с этим делать?

ОБНОВЛЕНИЕ 2

Хорошо, продолжая, я переписал свой DataPersister класс вроде так:

public class DataPersister
{
    private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();

    private IUnitOfWorkFactory UnitOfWorkFactory { get; set; }
    public IUnitOfWork GetUnitOfWork()
    {
        return UnitOfWorkFactory.GetUnitOfWork();
    }
    [Inject]
    public DataPersister(IUnitOfWorkFactory factory)
    {
        Logger.Info("Injected constructor called");
        UnitOfWorkFactory = factory;
    }
    public DataPersister()
    {
        Logger.Info("Parameterless constructor called");
    }
}

тогда я переписал свой SiteSettings класс вроде так:

public class SiteSettings
{
    private static readonly Common.Logging.ILog Logger = Common.Logging.LogManager.GetCurrentClassLogger();
    private ObservableDictionary<string, string> settings;
    private DataPersister persister;
    private SiteSettings()
    {
        persister = new DataPersister();
        using (var u = persister.GetUnitOfWork())
        {
            var settingsList = u.SiteSettings.GetAll();
            settings = new ObservableDictionary<string, string>(settingsList.ToDictionary(key => key.SiteSettingName, value => value.SiteSettingValue));
            settings.OnChange += new kvpChangeEvent<string, string>(settings_OnChange);
        }
    }
    private static SiteSettings instance;

    public static SiteSettings Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new SiteSettings();
            }
            return instance;
        }
    }

    private void settings_OnChange(object sender, odKVPChangeEventArgs<string, string> e)
    {
        using (var u = persister.GetUnitOfWork())
        {
            var setting = u.SiteSettings.GetByName(e.Key);
            setting.SiteSettingValue = e.Value;
            u.SiteSettings.Update(setting);
            u.Save();
            Logger.Info(i => i("Changed the '{0}' site setting from '{1}' to '{2}'.", e.Key, e.OldValue, e.Value));
        }
    }

    private int _ItemsPerPage;
    public int ItemsPerPage
    {
        get
        {
            return _ItemsPerPage;
        }
        set
        {
            _ItemsPerPage = value;
            settings["itemsPerPage"] = value.ToString();
        }
    }

    private int _SessionLifeInMinutes;
    public int SessionLifeInMinutes
    {
        get
        {
            return _SessionLifeInMinutes;
        }
        set
        {
            _SessionLifeInMinutes = value;
            settings["sessionLifeInMinutes"] = value.ToString();
        }
    }

    private string _DateFormat;
    public string DateFormat
    {
        get
        {
            return _DateFormat;
        }
        set
        {
            _DateFormat = value;
            settings["defaultDateFormat"] = value;
        }
    }
}

Разве это не должно работать? потому что это не так. DataPersister Класс всегда вызывается с помощью конструктора без параметров. Моя привязка к ядру выглядит так:

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<IUnitOfWork>().To<NHUnitOfWork>();
    kernel.Bind<IUnitOfWorkFactory>().To<NHUnitOfWorkFactory>();
}

Есть что-то еще, что я пропускаю? Это очень расстраивает.

2 ответа

Решение

Статические классы, которые не зависят ни от каких статических классов, - это то, что вы не должны делать при использовании контейнера IoC. Вместо этого вы должны создать не статический класс с одиночным временем жизни.

  1. Сделайте ваш класс SiteSettings не статичным.
  2. Вставьте все зависимости, например, IUnitOfWorkFactory, в SiteSettings, используя конструктор
  3. Создайте привязку в одноэлементной области для SiteSettings
  4. Получите экземпляр SiteSettings, где бы вам ни понадобился доступ к инъекции unsing constructor.

Пример:

public class SiteSettings {
    public SiteSettings(IUnitOfWorkFactory uowFactory) { .... }

    ....
}


public class INeedToAccessSiteSettings
{
    public INeedToAccessSiteSettings(SiteSettings siteSettings) { .... }
}

kenrel.Bind<SiteSettings>().ToSelf().InSingletonScope();

Обычно ninject вводит ваш сервис в конструктор или что-то в этом роде, он волшебным образом не превращает все ваши интерфейсы в экземпляры объектов во время выполнения.

например:

public class MyController : Controller
{
   private IServiceThatINeed _serviceThatINeed;
   public MyController(IServiceThatINeed serviceThatINeed)
   { 
       _serviceThatINeed = _serviceThatINeed;
   }
}

в этом случае, поскольку вы зарегистрировали свой экземпляр ядра, mvc знает, как разрешить эту зависимость, и передаст экземпляр объекта, который реализует IServiceThatINeed (Предполагая, что вы рассказали, как разрешить эту зависимость.

Теперь может быть случай, когда вам понадобится получить сервис без его внедрения в конструктор средой mvc, в этих случаях (например, тот, что у вас есть здесь) вам нужно будет использовать ServiceLocator

например:

var myService = ServiceLocator.Current.GetInstance<IServiceThatINeed>()

использовать ServiceLocatorнеобходимо добавить ссылку на Microsoft.Practices.ServiceLocation

Надеюсь, это поможет!

Другие вопросы по тегам