10

ASP.NETWebAPIを使用してCastleWindsorをセットアップしようとしています。

Hyprlinkrパッケージ(https://github.com/ploeh/Hyprlinkr)も使用しているため、コントローラーの依存関係の1つにHttpRequestMessageのインスタンスを挿入する必要があります。

Mark Seemannによるこの記事をフォローしています-http ://blog.ploeh.dk/2012/04/19/WiringHttpControllerContextWithCastleWindsor.aspxですが、APIは実行されていますが、APIを呼び出すと、リクエストはハングします。エラーメッセージはありません。まるで無限ループに入っているかのようです。カスタムControllerActivatorでResolveの呼び出しがハングしています

Castleの登録の一部が間違っていると思います。上記の記事に記載されているものを削除すると、APIを正常に呼び出すことができます(解決する必要のある依存関係はありませんが)

何か案は?

コードは以下です

//Global.asax
public class WebApiApplication : HttpApplication
{
    private readonly IWindsorContainer container;

    public WebApiApplication()
    {
        container = 
            new WindsorContainer(
                new DefaultKernel(
                    new InlineDependenciesPropagatingDependencyResolver(), 
                    new DefaultProxyFactory()), 
                new DefaultComponentInstaller());

        container.Install(new DependencyInstaller());
    }

    protected void Application_Start()
    {        
        GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new WindsorCompositionRoot(this.container));
    }

// installer
public class DependencyInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.AddFacility<TypedFactoryFacility>();

        container.Register(
            Component.For<ValuesController>()
                .Named("ValuesController")
                .LifeStyle.PerWebRequest,

            Component.For<IResourceLinker>()
                .ImplementedBy<RouteLinker>()
                .LifeStyle.PerWebRequest,

            Component.For<IResourceModelBuilder>()
                .ImplementedBy<ResourceModelBuilder>()
                .LifeStyle.PerWebRequest,

                Component.For<HttpRequestMessage>()
                .Named("HttpRequestMessage")
                .LifeStyle.PerWebRequest
            );
    }
}

//Activator

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

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

    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType)
    {
        var controller = (IHttpController)this.container.Resolve(controllerType, new { request = request });

        request.RegisterForDispose(
            new Release(
                () => this.container.Release(controller)));

        return controller;
    }

// DependencyResolver   
public class InlineDependenciesPropagatingDependencyResolver : DefaultDependencyResolver
{
    protected override CreationContext RebuildContextForParameter(CreationContext current, Type parameterType)
    {
        if (parameterType.ContainsGenericParameters)
        {
            return current;
        }

        return new CreationContext(parameterType, current, true);
    }
}

編集***********追加情報****************

そこで、コントローラーがHttpRequestMessageをctor引数として受け取るシナリオを設定し、次のことを見つけました。

これは機能します:

//controller
public class ValuesController : ApiController
    {
        private readonly HttpRequestMessage _httpReq;

        public ValuesController(HttpRequestMessage httpReq)
        {
            _httpReq = httpReq;
        }
//IHttpControllerActivator
public IHttpController Create(
            HttpRequestMessage httpRequest,
            HttpControllerDescriptor controllerDescriptor,
            Type controllerType)
        {

            var controller = (IHttpController)this.container.Resolve(
                controllerType, new { httpReq = httpRequest });

            return controller;

ただし、これはそうではありません。

//controller
public class ValuesController : ApiController
    {
        private readonly HttpRequestMessage _httpReq;

        public ValuesController(HttpRequestMessage request)
        {
            _httpReq = request;
        }

//IHttpControllerActivator
public IHttpController Create(
            HttpRequestMessage request,
            HttpControllerDescriptor controllerDescriptor,
            Type controllerType)
        {

            var controller = (IHttpController)this.container.Resolve(
                controllerType, new { request = request });

            return controller;

つまり、anonオブジェクトに「request」というプロパティがあり、コントローラーのctorargが「request」と呼ばれる場合です。どういうわけか、コントローラーに要求プロパティがnullであると思わせています。これが私が見るエラーの原因です:

'ApiController'インスタンスを再利用できません。「ApiController」は、着信メッセージごとに作成する必要があります。カスタムの「IHttpControllerActivator」をチェックして、同じインスタンスを作成しないことを確認してください。

System.Web.Http.ApiController.ExecuteAsync(HttpControllerContext controllerContext、CancellationToken cancelToken)at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage request、CancellationToken cancelToken)at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessageリクエスト、CancellationToken cancelToken)

これを読んでください セッターインジェクションを呼び出さずにStructureMapでオブジェクトコンポジションを強化するにはどうすればよいですか?

同様のシナリオを説明しています。

もちろん、hyprlinkrには「request」と呼ばれるHttpRequestMessageのctor argがあるので、そのプロパティ名でanonオブジェクトを指定する必要があります。

何か案は?

4

2 に答える 2

13

これが私のために働くコンポジションルートです:

public class WindsorCompositionRoot : IHttpControllerActivator
{
    private readonly IWindsorContainer container;

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

    public IHttpController Create(
        HttpRequestMessage request,
        HttpControllerDescriptor controllerDescriptor,
        Type controllerType)
    {
        var controller = (IHttpController)this.container.Resolve(
            controllerType,
            new
            {
                request = request
            });

        request.RegisterForDispose(
            new Release(
                () => this.container.Release(controller)));
        return controller;
    }

    private class Release : IDisposable
    {
        private readonly Action release;

        public Release(Action release)
        {
            this.release = release;
        }

        public void Dispose()
        {
            this.release();
        }
    }
}

コンテナを作成する方法は次のとおりです。

this.container =
    new WindsorContainer(
        new DefaultKernel(
            new InlineDependenciesPropagatingDependencyResolver(),
            new DefaultProxyFactory()),
        new DefaultComponentInstaller())
        .Install(new MyWindsorInstaller());

InlineDependenciesPropagatingDependencyResolverは次のとおりです。

public class InlineDependenciesPropagatingDependencyResolver : 
    DefaultDependencyResolver
{
    protected override CreationContext RebuildContextForParameter(
        CreationContext current,
        Type parameterType)
    {
        if (parameterType.ContainsGenericParameters)
        {
            return current;
        }

        return new CreationContext(parameterType, current, true);
    }
}

最後に、RouteLinkerを登録する方法は次のとおりです。

container.Register(Component
    .For<RouteLinker, IResourceLinker>()
    .LifestyleTransient());

注意すべきことの1つは、ApiController基本クラスにRequestHttpRequestMessageタイプという名前のパブリックプロパティがあることです。私の本のセクション10.4.3で説明されているように、 Windsorは、一致するコンポーネントがあり、その一致で大文字と小文字が区別されない場合、各書き込み可能プロパティに値を割り当てようとします。

Resolveメソッドに名前を付けたHttpRequestMessageを渡すと、requestまさにこれが発生するため、CastleWindsorにApiControllerのプロパティインジェクションを放棄するように指示する必要があります。コンベンションベースの登録でこれを行う方法は次のとおりです。

container.Register(Classes
    .FromThisAssembly()
    .BasedOn<IHttpController>()
    .ConfigureFor<ApiController>(c => c.Properties(pi => false))
    .LifestyleTransient());
于 2012-10-23T00:06:24.480 に答える
0

ASP.NETWebAPIにすでに組み込まれているメカニズムを使用しない理由-依存関係リゾルバー

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver

プロジェクトWebApiContribには、CastleWindsorリゾルバーの実装がありますが、依存関係リゾルバーで見たように

https://github.com/WebApiContrib/WebApiContrib.IoC.CastleWindsor

そしてマークがコメントで言ったように-IHttpControllerActivatorを実装する方法の1つ

http://blog.ploeh.dk/2012/10/03/DependencyInjectionInASPNETWebAPIWithCastleWindsor.aspx

于 2012-10-20T06:05:11.720 に答える