c# - 将 PerWcfSession 生活方式与 CaSTLe WCF 集成工具结合使用

标签 c# wcf castle-windsor wcffacility

以下代码使用 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 方法会导致以下错误:

Could not obtain scope for component SelfHost.PerSession. This is most likely either a bug in custom IScopeAccessor or you're trying to access scoped component outside of the scope (like a per-web-request component outside of web request etc)

PerWcfSession 组件的正确使用方法是什么?

最佳答案

所以我遗漏了一些东西:

ServiceContract需要设置SessionMode属性

[ServiceContract(SessionMode = SessionMode.Required)]

同样,ServiceBehavior 需要设置 InstanceContextMode

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

最后,服务注册需要更改默认的 Lifestyle(单例),以便为每个请求重新创建它(并重新评估依赖项)- Transient 或 PerWcfSession 都可以。

此外,因为我们需要一个 session ,绑定(bind)需要从 basicHttpBinding 更改为支持 session 的绑定(bind):

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

关于c# - 将 PerWcfSession 生活方式与 CaSTLe WCF 集成工具结合使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11023491/

相关文章:

仅在 HP Z620 站上发生的 C# Out Of Memory/COMException

wcf - 通过命名管道从 Windows 服务( session #0)连接到桌面应用程序( session #1)

c# - 在 CaSTLe Windsor 中注册通用类型

c# - 如何使用 CaSTLe Windsor 注册通用装饰器?

c# - IoC 容器的使用;特别是温莎

c# - 如何使用Mvvm将页面推送到MasterDetailPage

c# - MissingManifestResourceException 是什么意思以及如何修复它?

c# - 捕获 WCF 超时异常

api - 在 Postman 中使用路径参数测试 WCF API

c# - 创建 CaSTLe.Windsor 拦截器的问题