Создание WindsorViewPageActivator - PullRequest
       1

Создание WindsorViewPageActivator

0 голосов
/ 14 декабря 2010

Я играл с новым Asp net mvc 3 RC2.Я создал класс WindsorViewPageActivator следующим образом:

public class WindsorViewPageActivator : IViewPageActivator
    {
        object IViewPageActivator.Create(ControllerContext controllerContext, Type type)
        {
            return DependencyResolver.Current.GetService(type);              
        }
    }

, а затем класс WindsorDependencyResolver

public class WindsorDependencyResolver : IDependencyResolver
{
    private readonly IWindsorContainer container;

    public WindsorDependencyResolver(IWindsorContainer container)
    {
            this.container = container;
    }

    #region IDependencyResolver Members

    public object GetService(Type serviceType)
    {
        return Resolve(serviceType);
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        return container.ResolveAll(serviceType).Cast<object>();
    }

    public IEnumerable<TService> GetAllInstances<TService>()
    {
        return container.ResolveAll<TService>();
    }

    public TService GetInstance<TService>()
    {
        return (TService)Resolve(typeof(TService));
    }

    #endregion
    private object Resolve(Type serviceType)
    {
        try
        {
            return container.Resolve( serviceType);
        }
        catch (Exception ex)
        {
            return null;
        }
    }
}

}

Теперь я выполняю в Global.asax нечто подобное1009 *

container.Register(Component.For<IControllerActivator>().ImplementedBy<WindsorControllerActivator>());
container.Register(Component.For<IViewPageActivator>().ImplementedBy<WindsorViewPageActivator>());
container.Register(Component.For<IControllerFactory>().ImplementedBy<DefaultControllerFactory>());               
DependencyResolver.SetResolver (new WindsorDependencyResolver(container));

'Теперь я получаю следующую ошибку. Представление, найденное в' ~ / Views / Account / LogOn.cshtml ', не было создано.Нужно ли регистрировать каждую страницу просмотра в контейнере Windsor? Если да, то как мне зарегистрировать каждый просмотр?Я использую Razor View Engine.Спасибо

Ответы [ 2 ]

2 голосов
/ 14 декабря 2010

Да, для того, чтобы решить проблему, вам необходимо зарегистрировать ее. Ознакомьтесь с документацией, чтобы ознакомиться с API .

1 голос
/ 24 октября 2011

Я попробовал это сам, и, к сожалению, я не могу заставить его работать должным образом. В моем решении я делаю следующее:

public class WindsorViewPageActivator : IViewPageActivator
{
    private readonly IKernel _kernel;

    /// <summary>
    /// Initializes a new instance of the <see cref="WindsorViewPageActivator"/> class.
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    public WindsorViewPageActivator([NotNull] IKernel kernel)
    {
        if (kernel == null) throw new ArgumentNullException("kernel");
        _kernel = kernel;
    }

    public object Create(ControllerContext controllerContext, Type type)
    {
        if (!_kernel.HasComponent(type))
        {
            if (IsSupportedView(type))
            {
                _kernel.Register(Component.For(type).LifestylePerWebRequest());
            }
            else
            {
                return Activator.CreateInstance(type);
            }
        }

        var viewPageInstance = _kernel.Resolve(type);

        return viewPageInstance;
    }

    /// <summary>
    /// Determines whether the specified type is of a supported view type.
    /// </summary>
    /// <param name="viewType">Type of the service.</param>
    /// <returns>
    ///     <c>true</c> if the specified type is of a supported view type; otherwise, <c>false</c>.
    /// </returns>
    private static bool IsSupportedView(Type viewType)
    {
        return viewType.IsAssignableTo<WebViewPage>()
            || viewType.IsAssignableTo<ViewPage>()
            || viewType.IsAssignableTo<ViewMasterPage>()
            || viewType.IsAssignableTo<ViewUserControl>()
            ;
    }
}

Это работает до тех пор, пока вы ничего не измените в своей разметке. Если вы это сделаете, вы получите ошибку регистрации, так как представление теперь сгенерирует новый тип, который не существует в контейнере (но он имеет то же имя!). Я подумал о том, чтобы агрессивно освободить компонент представления, как только он будет разрешен, но по какой-то причине я не могу избавиться от него в контейнере. Даже явный вызов _kernel.ReleaseComponent(viewPageInstance) не сделает этого (но это, конечно, просто освобождение экземпляра, а не типа).

Что нам действительно нужно сделать, так это заставить Виндзор вводить свойства в существующие экземпляры. То есть используйте Activator.CreateInstance(type), а затем скажите Виндзору, чтобы он вставил свойства в экземпляр. Но Виндзор не поддерживает внедрение свойств в существующие экземпляры, поэтому нам нужно что-то взломать, и это сделает это за нас. Я видел это http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ (внизу), но это не очень хорошо работает.

Мое решение состояло в том, чтобы просто вручную установить мои свойства в активаторе просмотровой страницы (у вас есть базовый тип просмотровой страницы), но, может быть, есть какое-то лучшее решение?

EDIT

Мне все-таки удалось заставить его работать!

Мое решение состоит в том, чтобы просто создать собственный активатор компонента и имитировать то, что делается в инфраструктуре MVC, например:

public class ViewPageComponentActivator : DefaultComponentActivator
{
    public ViewPageComponentActivator(ComponentModel model, IKernel kernel, ComponentInstanceDelegate onCreation, ComponentInstanceDelegate onDestruction)
        : base(model, kernel, onCreation, onDestruction)
    {
    }

    protected override object CreateInstance(CreationContext context, ConstructorCandidate constructor, object[] arguments)
    {
        // Do like the MVC framework.
        var instance = Activator.CreateInstance(context.RequestedType);
        return instance;
    }
}

Активатор компонента просто всегда возвращает новый экземпляр представления. Поскольку компонент зарегистрирован как временный, всегда вызывается CreateInstance. Здесь могут быть некоторые возможности настройки.

Активатор просмотра страниц теперь намного проще. Обратите внимание, что тип службы меняется каждый раз, когда вы меняете представление, поэтому мы должны зарегистрировать тип, основываясь на его уникальном имени (я еще не настроил это, но может быть более хороший способ назвать компонент).

/// <summary>
/// An activator using Castle Kernel for activating views.
/// </summary>
public class WindsorViewPageActivator : IViewPageActivator
{
    private readonly IKernel _kernel;

    /// <summary>
    /// Initializes a new instance of the <see cref="WindsorViewPageActivator"/> class.
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    public WindsorViewPageActivator([NotNull] IKernel kernel)
    {
        if (kernel == null) throw new ArgumentNullException("kernel");
        _kernel = kernel;
    }

    public object Create(ControllerContext controllerContext, Type type)
    {
        if (!_kernel.HasComponent(type.FullName))
        {
            _kernel.Register(Component.For(type).Named(type.FullName).Activator<ViewPageComponentActivator>().LifestyleTransient());
        }
        return _kernel.Resolve(type.FullName, type);
    }
}

Надеюсь, это может пригодиться кому-то в подобных ситуациях.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...