创建 WindsorViewPageActivator

发布于 2024-10-07 18:12:11 字数 2052 浏览 0 评论 0原文

我正在玩新的 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 中做类似这样的事情

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”处找到的视图。 我是否需要在温莎容器中注册每个视图页面如果是,那么如何注册每个视图。我正在使用 Razor 视图引擎。 谢谢

I was playing with new Asp net mvc 3 RC2. I have created a WindsorViewPageActivator class as follows

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

and then a WindsorDependencyResolver class

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;
        }
    }
}

}

Now I am doing in Global.asax something like this

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));

'
Now I am getting the following error
The view found at '~/Views/Account/LogOn.cshtml' was not created.
Do I need to register each view page in windsor container If yes then how can I register each view. I am using Razor view engine.
Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鹤仙姿 2024-10-14 18:12:11

是的,为了解决问题,您需要注册它。 查看文档以熟悉 API

Yes, in order to resolve stuff you need to register it. Have a look at the documentation to familiarise yourself with the API.

一笔一画续写前缘 2024-10-14 18:12:11

我自己尝试过,不幸的是我似乎无法让它正常工作。我在我的解决方案中执行以下操作:

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) 也无法做到这一点(但这当然只是释放实例,而不是类型)。

我们真正需要做的是让 Windsor 将属性注入到现有实例中。也就是说,使用 Activator.CreateInstance(type) ,然后告诉 Windsor 将属性注入到实例中。但 Windsor 不支持将属性注入现有实例,因此我们需要一起破解一些东西,这将为我们做到这一点。
我见过这个 http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/(在底部),但这不会表现得很好。

我的解决方案只是在视图页面激活器中手动设置我的属性(您有基本视图页面类型),但也许有更好的解决方案?

编辑

毕竟我设法让它工作!

我的解决方案是简单地创建一个自定义组件激活器并模仿 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);
    }
}

我希望这对处于类似情况的人有用。

I have tried this myself, and unfortunately I can't seem to get it to work properly. I do the following in my solution:

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>()
            ;
    }
}

This works as long as you don't change anything in your markup. If you do, you'll get a registration error, as the view now will generate a new type, that doesn't exist in the container (but it has the same name!).
What I thought of doing, was to aggressively release the view component as soon as it's resolved, but I can't get rid of it in the container for some reason. Not even an explicit call to _kernel.ReleaseComponent(viewPageInstance) would do it (but that's of course just releasing the instance, not the type).

What we really need to do, is make Windsor inject properties into existing instances. That is, use Activator.CreateInstance(type) and then tell Windsor to inject the properties into the instance. But Windsor doesn't support injecting properties into existing instances, so we need to hack something together, that will do that for us.
I've seen this one http://www.jeremyskinner.co.uk/2008/11/08/dependency-injection-with-aspnet-mvc-action-filters/ (at the bottom), but that wouldn't perform very well.

My solution was simply to manually set my properties in the viewpage activator (you have a base viewpage type), but maybe there's some better solution?

EDIT

I managed to get it working after all!

My solution is to simply create a custom component activator and mimic what's being done in the MVC framework, like so:

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;
    }
}

The component activator simply always return a new instance of the view. Because the component is registered as being transient, CreateInstanceis always called. There might be some tweaking possibilities here.

The viewpage activator is now much simpler. Note that the type of service is different whenever you change the view, so we must register the type based on it's unique name (I haven't tweaked this yet, but there might be a nicer way to name the component).

/// <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);
    }
}

I hope this might be of use to someone in similar situations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文