3

次のコードは、Castle Windsor 3.0 のWCF Integration Facilityを使用して、WCF セルフホステッド サービスを登録します。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace SelfHost
{
    [ServiceContract]
    public interface IHelloWorldService
    {
        [OperationContract]
        string SayHello(string name);
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true)]
    public class HelloWorldService : IHelloWorldService
    {
        private readonly PerSession _perSession;

        public HelloWorldService(PerSession perSession)
        {
            _perSession = perSession;
        }

        public string SayHello(string name)
        {
            return string.Format("Hello, {0} {1}", name, _perSession.Info());
        }
    }

    public class PerSession
    {
        private readonly string _now;

        public PerSession()
        {
            _now = DateTime.Now.ToString();
        }

        public string Info()
        {
            return _now;
        }
    }

    internal class Program
    {
        private static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/hello");

            var container = new WindsorContainer();

            container.AddFacility<WcfFacility>();

            container.Register(
                Component.For<PerSession>().LifeStyle.PerWcfSession(),
                Component.For<IHelloWorldService>()
                    .ImplementedBy<HelloWorldService>()
                    .AsWcfService(
                        new DefaultServiceModel()
                            .AddBaseAddresses(baseAddress)
                            .AddEndpoints(WcfEndpoint.BoundTo(new BasicHttpBinding()).At("basic"))
                            .PublishMetadata(o => o.EnableHttpGet())
                    )
                );

            Console.WriteLine("The service is ready at {0}", baseAddress);
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();
        }
    }
}

WcfTestClient.exe を使用して SayHello メソッドを呼び出そうとすると、次のエラーが発生します。

コンポーネント SelfHost.PerSession のスコープを取得できませんでした。これは、カスタム IScopeAccessor のバグであるか、スコープ外のスコープ コンポーネントにアクセスしようとしている可能性があります (Web リクエストの外部にある Web リクエストごとのコンポーネントなど)。

PerWcfSession コンポーネントを使用する正しい方法は何ですか?

4

1 に答える 1

2

だから私はいくつかのことを見逃していました:

ServiceContract は SessionMode プロパティを設定する必要があります

[ServiceContract(SessionMode = SessionMode.Required)]

同様に、ServiceBehavior は InstanceContextMode を設定する必要があります

[ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]

最後に、サービス登録では、Lifestyle をデフォルト (Singleton) から変更して、要求ごとに再作成する (そして依存関係を再評価する) 必要があります。Transient または PerWcfSession が機能します。

また、セッションが必要なため、バインディングを basicHttpBinding からセッションをサポートするものに変更する必要があります。

Component.For<IHelloWorldService>()
    .ImplementedBy<HelloWorldService>()
    .LifestyleTransient()
    .AsWcfService(
        new DefaultServiceModel()
            .AddBaseAddresses(baseAddress)
            .AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
            .PublishMetadata(o => o.EnableHttpGet())
    )

最終的なコードは次のようになります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;

using Castle.Facilities.WcfIntegration;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace SelfHost
{
    [ServiceContract(SessionMode = SessionMode.Required)]
    public interface IHelloWorldService
    {
        [OperationContract]
        string SayHello(string name);
    }

    [ServiceBehavior(IncludeExceptionDetailInFaults = true, InstanceContextMode = InstanceContextMode.PerSession)]
    public class HelloWorldService : IHelloWorldService
    {
        private readonly PerSession _perSession;

        public HelloWorldService(PerSession perSession)
        {
            _perSession = perSession;
        }

        public string SayHello(string name)
        {
            return string.Format("Hello, {0} {1}", name, _perSession.Info());
        }
    }

        public class PerSession
        {
            private readonly string _now;

            public PerSession()
            {
                _now = DateTime.Now.ToString();
            }

            public string Info()
            {
                return _now;
            }
        }

    internal class Program
    {
        private static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/hello");

            var container = new WindsorContainer();

            container.AddFacility<WcfFacility>();

            container.Register(
                Component.For<PerSession>().LifeStyle.PerWebRequest,
                Component.For<IHelloWorldService>()
                    .ImplementedBy<HelloWorldService>()
                    .LifeStyle.PerWebRequest
                    .AsWcfService(
                        new DefaultServiceModel()
                            .AddBaseAddresses(baseAddress)
                            .AddEndpoints(WcfEndpoint.BoundTo(new WSHttpBinding()).At("myBinding"))
                            .PublishMetadata(o => o.EnableHttpGet())
                    )
                );

            Console.WriteLine("The service is ready at {0}", baseAddress);
            Console.WriteLine("Press <Enter> to stop the service.");
            Console.ReadLine();
        }
    }
}
于 2012-06-14T00:32:43.657 に答える