Внедрение свойства в базовый контроллер с помощью Ninject 2 - PullRequest
5 голосов
/ 01 июля 2010

У меня есть следующий код в моем Global.aspx

protected override void OnApplicationStarted()
{
    AreaRegistration.RegisterAllAreas();
    RegisterRoutes(RouteTable.Routes);
    RegisterAllControllersIn(Assembly.GetExecutingAssembly());
}

protected override IKernel CreateKernel()
{
    return new StandardKernel(new ServiceModule());
}

У меня также есть следующий модуль Ninject:

internal class ServiceModule : NinjectModule
{
    public override void Load()
    {
        Bind<IProductService>().To<ProductService>().InRequestScope();
    }
}

У меня также есть базовый контроллер:

public class BaseController : Controller
{
    [Inject]
    public IProductService ProductService
    {
        get;
        set;
    }
}

Этот код работает. Проблема, с которой я столкнулся, заключается в том, что я хотел бы удалить атрибут inject из базового контроллера и указать его в Ninject ServiceModule. Иными словами, как мне написать в модуле ServiceModule правило связывания, которое говорит Ninject о необходимости вставки ProductService в свойство базового контроллера?

Если удалить атрибут, я получу исключение NullReferenceException.

Ответы [ 2 ]

3 голосов
/ 01 июля 2010

Условное связывание живет в http://github.com/ninject/ninject.extensions.conventions - один реализует IBindingGenerator.Тем не менее, это в основном связано с обнаружением интерфейсов и сервисов.

Как правило, внедрение в конструктор является хорошим подходом по умолчанию.Однако то, как работает ASP.NET MVC, усложняет эту задачу (следовательно, FubuMVC и т. Д.).Таким образом, внедрение свойства является следующим лучшим вариантом.

Вы можете обнаружить, что использование OnActivation в вашем Bind может позволить вам сделать достаточно - и если вы можете, это, безусловно, самое простое.

Я бы охарактеризовал то, что вы пытаетесь сделать, как активацию на основе соглашения.Проблема в том, что

  • решает, что вы собираетесь автоматически вводить.Собираетесь ли вы вводить все публичное, что не является конкретным?Все, что знает твое Ядро?Если вы не можете дать четкое определение того, что вы хотите сделать, процесс впрыска может стать непредсказуемым и трудным для понимания.Вы заканчиваете тем, что отлаживаете и объясняете коллегам много.

  • делая это эффективным.Ninject динамически генерирует код за кулисами, чтобы сделать активацию экземпляра эффективной (т. Е. Во время обхода класса, ищущего маркеры [Inject], он генерирует код один раз, чтобы сделать то, что затем соединяется, как если бы вы написали его от руки)).

Глядя в код, простого пути нет OOTB.Похоже, что добавление пользовательского IInjectionHeuristic сделает свое дело.

Однако, если вы углубляетесь в контейнеры, вам нужно

  1. приостановить и посмотреть, сможете ли вы его сохранить.просто не ходя по этому пути
  2. зайдите в список рассылки и найдите похожие вещи
  3. , если вы все еще хотите это сделать, отправьте письмо туда.
2 голосов
/ 06 июня 2011

Развивая идеи Рубена Бартелинка, вы можете создать собственную реализацию IInjectionHeuristic .

public class ControllerInjectionHeuristic : NinjectComponent, IInjectionHeuristic
{
    private readonly IKernel kernel;

    public BaseControllerInjectionHeuristic(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public bool ShouldInject(MemberInfo member)
    {
        if (member.ReflectedType != typeof(BaseController))
        {
            return false;
        }

        var propertyInfo = member.ReflectedType.GetProperty(member.Name);
        object service = kernel.TryGet(propertyInfo.PropertyType);

        return service != null;
    }
}

ControllerInjectionHeuristic внедрит любое свойство (службу) в BaseController, для которой ядро ​​может разрешить службу.

Зарегистрируйте пользовательскую реализацию в ядре.

var kernel = new StandardKernel();
kernel.Components.Add<IInjectionHeuristic, ControllerInjectionHeuristic>();

Другим решением проблемы является использование OnActivation. ( Это решение не проверено, но оно должно дать вам представление о том, как действовать ).

public class ControllerModule : NinjectModule
{
    public override void Load()
    {
        // Get all controller types. You could use
        // Ninject.Extensions.Conventions.
        IEnumerable<Type> controllerTypes = null;
        foreach (var controllerType in controllerTypes)
        {
            Bind(controllerType).ToSelf().InRequestScope()
                .OnActivation(ControllerActivation);
        }
    }

    private static void ControllerActivation(IContext context, object obj)
    {
        var controller = obj as BaseController;
        if (controller == null)
        {
            return;
        }

        controller.ProductService = context.Kernel.Get<IProductService>();
    }
}
...