Служба WCF создает несколько внутренних объектов? - PullRequest
0 голосов
/ 19 февраля 2019

Я самостоятельно размещаю службу WCF и желаю, чтобы мой объект службы был единичным.Мой клиент использует канал для доступа к сервису.Хост и клиент являются консольными приложениями и перечислены ниже.

У моей службы есть метод, который возвращает интерфейс внутреннему объекту.Этот внутренний объект содержит методы для получения / установки числа.Мой сервис имеет альтернативные методы для получения / установки номера этого внутреннего объекта.

Моя проблема заключается в том, что установка номера внутреннего объекта через интерфейс, возвращаемый службой, и установка его с помощью метода службы (SetInternalNumber), по-видимому, не устанавливают один и тот же объект.Когда я получаю значения, они разные.

Мое клиентское приложение показывает начальный номер внутреннего объекта, изменяя этот номер, получая другой интерфейс к объекту и его начальное значение, устанавливая значение через службу и перечисляяразличные значения.

Я думал, что было создано несколько экземпляров моего внутреннего объекта, но это не так.Я знаю это, потому что напечатал строку в конструкторе объектов и вижу эту строку только один раз.

Что происходит?Я подумал, что, возможно, Внутренний класс должен быть помечен как одиночный (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();
            }
        }
    }

1 Ответ

0 голосов
/ 20 февраля 2019

Wcf - это коммуникационная среда, которая отправляет сообщение и получает сообщение.

Ваш метод GetMyInterface, который возвращает внутреннее, сначала будет сериализован в xml, а затем, когда клиент получит сообщение, он десериализует сообщение для перестройки объекта.

Это означает, что если ваш метод возвращает объект, он всегда будет не тем же объектом и не имеет никакого отношения к внутреннему в вашем сервисе, потому что клиент перестраивает его из сообщения.Вы можете пройти тест следующим образом:

 Console.WriteLine($"are the two internal the same?" + (myInternal == anotherInternal ? "the same" : "not the same"));

Мой результат.

enter image description here

Потому что два внутренних в клиенте и внутренний вваш сервис не тот же, поэтому ваш метод SetInternalNumber будет только устанавливать число для отдельного внутреннего объекта и не будет влиять друг на друга.

Внутренний клиент имеет только начальное значение внутреннего сервиса, а затем не имеет ничего общего сэто и друг с другом.Вот почему ваши два внутренних клиента имеют одинаковый начальный номер.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...