关于c#:每次调用端点时,似乎都会自动创建自托管的WCF服务全局对象。

Self hosted WCF service global object appears to be newly created every time an endpoint is invoked

在遵循本教程之后,我将在Windows服务内部自行托管WCF服务。我的WCF服务包含一个我定期更新的全局对象。我想将该对象序列化为JSON,然后通过服务端点返回该JSON字符串。当我访问在服务上调用serialize方法的端点时,我得到的似乎是全局的全新实例。服务设置为[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]

我以与教程相同的方式实例化:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyWindowsService: ServiceBase
{public ServiceHost serviceHost = null;

    public Service()
    {
        ServiceName ="MyService";
    }

    public static void Main()
    {
        ServiceBase.Run(new MyWindowsService());
    }

    protected override void OnStart(string[] args)
    {
        if (serviceHost != null)
        {
            serviceHost.Close();
        }

        serviceHost = new ServiceHost(typeof(MyWCFService));
        serviceHost.Open();
    }

    protected override void OnStop()
    {
        if (serviceHost != null)
        {
            serviceHost.Close();
            serviceHost = null;
        }
    }

我的WCF服务如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class MyWCFService: IWCFService
{
    private myObject = mySerializableObject;

    public MyWCFService()
    {
        myObject = new MySerializableObject();
        myObject.Init();
    }

    public Stream GetJSON()
    {
        MemoryStream stream = new MemoryStream();
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(MySerializableObject));

        ser.WriteObject(stream, myObject);

        string jsonString = Encoding.ASCII.GetString(stream.ToArray());


        byte[] resultBytes = Encoding.UTF8.GetBytes(jsonString);
        WebOperationContext.Current.OutgoingResponse.ContentType ="text/plain";
        return new MemoryStream(resultBytes);
    }
}

如果我GET GetJSON端点,则返回的字符串是该对象的全新初始化。如果我中断了GetJSON方法,则myObject将显示所有新初始化的值。在MySerializableObject更新代码中放置一个断点表明更新正确进行,并且已保存到内存中的对象中。

在普通控制台应用程序中运行相同的代码可以正常工作。为什么会有差异?我对全局变量的处理不正确吗?


弄清楚了...我遇到了几个问题。

  • 如此处所示,我的InstanceContextMode声明
    没有装饰正确的服务,因此它仍在运行中
    默认的每次调用上下文-因此,每个连接上都有一个新的状态对象。
  • 奥赖利(O'Reilly)向我展示了我不是在创建单身汉
    实例正确。旁注,使用实例创建ServiceHost时,可以在构造函数中或App.config中显式指定基本URI。这让我有些困惑,因为我遇到的许多示例都是在构造函数中而不是在配置中传递的。
  • 这是我为后代工作的实现方式:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    [ServiceContract(Namespace ="http://my.super.original.namespace")]
    public interface IWCFService
    {
        [OperationContract, WebGet]
        Stream GetJSON();
    }

    //Decorator goes on WCF service, not the Windows service
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public class MyWCFService : IWCFService
    {
        private StateObject _myStateObject;

        public MyWCFService()
        {
            _myStateObject = new StateObject();
            _myStateObject.Init();
        }

        public Stream GetJSON()
        {
            .
            .
            .
            return"JSON String Here";
        }
    }

    public class MyWindowsService : ServiceBase
    {
        public ServiceHost serviceHost = null;
        private readonly MyWcfService _wcfSingleton;

        public MyWindowsService()
        {
            ServiceName ="WindowsServiceNameHere";
            _wcfSingleton = new MyWCFService();
        }

        public static void Main()
        {
            ServiceBase.Run(new MyWindowsService());
        }

        // Start the Windows service.
        protected override void OnStart(string[] args)
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
            }

            //load WCF Singleton Instance and open it for connections
            serviceHost = new ServiceHost(_wcfSingleton);
            serviceHost.Open();
        }

        protected override void OnStop()
        {
            if (serviceHost != null)
            {
                serviceHost.Close();
                serviceHost = null;
            }
        }
    }