我正在自托管WCF服务,并希望我的服务对象是单例。我的客户使用渠道访问服务。主机和客户端是控制台应用程序,在下面列出。
我的服务有一个方法可以将接口返回到内部对象。该内部对象包含获取/设置数字的方法。我的服务有其他方法来获取/设置内部对象的编号。
我的问题是,通过服务返回的接口设置内部对象的编号,并使用服务方法(SetInternalNumber)进行设置似乎并没有设置相同的对象。当我检索这些值时,它们是不同的。
我的客户端应用程序显示内部对象的初始编号,更改该编号,获取该对象的另一个接口及其初始值,通过服务设置值以及不同对象的列表值。
我认为已创建了内部对象的多个实例,但事实并非如此。我之所以知道这一点,是因为我在对象构造函数中打印了一行,并且只看到该行一次。
这是怎么回事?我认为也许Internal类必须标记为单例(InstanceContextMde.Single),但这不起作用。
服务界面
[ServiceContract]
public interface IMyService
{
[OperationContract]
[ServiceKnownType(typeof(Internal))]
IInternal GetMyInterface();
[OperationContract]
int GetInternalNumber();
[OperationContract]
void SetInternalNumber(int number);
}
服务实施
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class MyService : IMyService
{
private IInternal _internal;
public MyService()
{
Random rng = new Random();
_internal = new Internal(rng.Next());
}
public int GetInternalNumber()
{
return _internal.GetNumber();
}
public IInternal GetMyInterface()
{
return _internal;
}
public void SetInternalNumber(int number)
{
_internal.SetNumber(number);
}
}
内部对象界面
[ServiceContract]
public interface IInternal
{
[OperationContract]
int GetNumber();
[OperationContract]
void SetNumber(int number);
}
内部对象实现
[DataContract]
public class Internal : IInternal
{
[DataMember]
private int _number;
public Internal(int number)
{
_number = number;
Console.WriteLine($"creating Internal - {_number}");
}
public int GetNumber()
{
return _number;
}
public void SetNumber(int number)
{
_number = number;
}
}
自托管应用
static void Main(string[] args)
{
Uri baseAddress = new Uri(@"http://localhost:12345/GettingStarted");
MyService singleton = new MyService();
ServiceHost selfHost = new ServiceHost(singleton, baseAddress);
try
{
selfHost.AddServiceEndpoint(typeof(IMyService), new BasicHttpBinding(), "MyService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Open();
Console.WriteLine("host is open");
Console.ReadLine();
selfHost.Close();
}
catch (Exception ex)
{
Console.WriteLine($"exception: {ex.Message}");
Console.ReadLine();
selfHost.Abort();
}
}
客户端应用
static void Main(string[] args)
{
var myBinding = new BasicHttpBinding();
var myEndpoint = new EndpointAddress(@"http://localhost:12345/GettingStarted/MyService");
using (var myChannelFactory = new ChannelFactory<IMyService>(myBinding, myEndpoint))
{
IMyService service = null;
try
{
service = myChannelFactory.CreateChannel();
Console.WriteLine("channel created");
// get interface to concrete object
IInternal myInternal = service.GetMyInterface();
Console.WriteLine($"initial number = {myInternal.GetNumber()}");
Console.ReadLine();
// set a new # with Internal interface
Console.WriteLine("set new number");
myInternal.SetNumber(123);
Console.WriteLine($"new number = {myInternal.GetNumber()}");
Console.ReadLine();
// get another interface, don't set its number
Console.WriteLine("get another interface, initial value");
IInternal anotherInternal = service.GetMyInterface();
Console.WriteLine($"number(another) = {anotherInternal.GetNumber()}");
Console.ReadLine();
// set # with service
Console.WriteLine("set # through server");
service.SetInternalNumber(789);
// what are the #s?
Console.WriteLine();
Console.WriteLine($"from Internal: {myInternal.GetNumber()}");
Console.WriteLine($"from another Internal = {anotherInternal.GetNumber()}");
Console.WriteLine($"from service = {service.GetInternalNumber()}");
Console.ReadLine();
((ICommunicationObject)service).Close();
myChannelFactory.Close();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
(service as ICommunicationObject)?.Abort();
}
}
}
答案 0 :(得分:0)
Wcf是一种发送消息和接收消息的通信框架。
返回内部的方法GetMyInterface首先将序列化为xml,然后当客户端收到消息时,它将反序列化消息以重建对象。
这意味着,如果您的方法返回一个对象,则该对象将始终不是同一对象,并且与服务中的内部无关,因为客户端将从消息中重建它。 您可以进行以下测试
Console.WriteLine($"are the two internal the same?" + (myInternal == anotherInternal ? "the same" : "not the same"));
我的结果。
因为客户端内部的两个和服务内部的两个都不相同,所以您的SetInternalNumber方法只会将数字设置为单独的内部对象,而不会互相影响。
客户端内部仅具有服务内部的初始值,然后与它以及彼此无关。这就是为什么您的两个内部客户具有相同的初始编号的原因。