.Net Remoting для WCF Challenge! - PullRequest
4 голосов
/ 10 ноября 2008

Я пытаюсь перенести код удаленного доступа .net в wcf, но мне трудно. Может ли кто-нибудь помочь мне перенести эту простую программу на основе Remoting, приведенную ниже, на использование WCF? В программе реализован простой шаблон издателя / подписчика, в котором у нас есть единственная программа TemperatureProviderProgram, которая публикует множество температурных программ, которые подписываются на TemperatureProvider.

Для запуска программ:

  1. Скопируйте TemperatureProviderProgram и TemperatureSubcriberProgram в отдельные проекты консольных приложений.
  2. Копирование в остальные классы и интерфейсы в общий проект библиотеки классов, а затем добавление ссылки на библиотеку System.Runtime.Remoting
  3. Добавить ссылку на проект библиотеки классов из проектов консольного приложения.
  4. Завершите и запустите 1 программу температурного провайдера и несколько программ температурного подписчика.

Обратите внимание, что не следует использовать IIS или xml. Заранее спасибо.

public interface ITemperatureProvider
{
    void Subcribe(ObjRef temperatureSubcriber);
}

[Serializable]
public sealed class TemperatureProvider : MarshalByRefObject, ITemperatureProvider
{
    private readonly List<ITemperatureSubcriber> _temperatureSubcribers = new List<ITemperatureSubcriber>();
    private readonly Random randomTemperature = new Random();

    public void Subcribe(ObjRef temperatureSubcriber)
    {
        ITemperatureSubcriber tempSubcriber = (ITemperatureSubcriber)RemotingServices.Unmarshal(temperatureSubcriber);
        lock (_temperatureSubcribers)
        {
            _temperatureSubcribers.Add(tempSubcriber);
        }
    }

    public void Start()
    {
        Console.WriteLine("TemperatureProvider started...");
        BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
        provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
        TcpServerChannel tcpChannel = new TcpServerChannel("TemperatureProviderChannel", 5001, provider);
        ChannelServices.RegisterChannel(tcpChannel, false);
        RemotingServices.Marshal(this, "TemperatureProvider", typeof(ITemperatureProvider));

        while (true)
        {
            double nextTemp = randomTemperature.NextDouble();

            lock (_temperatureSubcribers)
            {
                foreach (var item in _temperatureSubcribers)
                {
                    try
                    {
                        item.OnTemperature(nextTemp);
                    }
                    catch (SocketException)
                    {}
                    catch(RemotingException)
                    {}
                }
            }
            Thread.Sleep(200);
        }
    }
}

public interface ITemperatureSubcriber
{
    void OnTemperature(double temperature);
}

[Serializable]
public sealed class TemperatureSubcriber : MarshalByRefObject, ITemperatureSubcriber
{
    private ObjRef _clientRef;
    private readonly Random portGen = new Random();

    public void OnTemperature(double temperature)
    {
        Console.WriteLine(temperature);
    }
    public override object InitializeLifetimeService()
    {
        return null;
    }

    public void Start()
    {
        BinaryServerFormatterSinkProvider provider = new BinaryServerFormatterSinkProvider();
        provider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;

        int port = portGen.Next(1, 65535);
        TcpServerChannel tcpChannel = new TcpServerChannel(string.Format("TemperatureSubcriber_{0}", Guid.NewGuid()), port, provider);
        ChannelServices.RegisterChannel(tcpChannel, false);

        ITemperatureProvider p1 = (ITemperatureProvider)RemotingServices.Connect(typeof(ITemperatureProvider), "tcp://localhost:5001/TemperatureProvider");
        _clientRef = RemotingServices.Marshal(this, string.Format("TemperatureSubcriber_{0}_{1}.rem", Environment.MachineName, Guid.NewGuid()));
        p1.Subcribe(_clientRef);
    }
}

public class TemperatureProviderProgram
{
    static void Main(string[] args)
    {
        TemperatureProvider tp = new TemperatureProvider();
        tp.Start();
    }
}
public class TemperatureSubcriberProgram
{
    static void Main(string[] args)
    {
        Console.WriteLine("Press any key to start TemperatureSubcriber.");
        Console.ReadLine();
        TemperatureSubcriber ts = new TemperatureSubcriber();
        ts.Start();
        Console.ReadLine();
    }
}

Ответы [ 5 ]

1 голос
/ 11 декабря 2008

То, что вы хотите сделать, это использовать WCF NetTcpBinding с обратными вызовами.

Взгляните на это: http://www.codeproject.com/KB/WCF/publisher_subscriber.aspx

«Изучение WCF» Микеле Бустаманте тоже очень хорошо. Вы можете получить Chpt1 для VS2008 на ее веб-сайте вместе с кодом для книги. Chpt1 объяснит / демо настройку соединений и тому подобное. У нее также есть загружаемый образец кода. Одним из примеров является DuplexPublishSubscribe.

1 голос
/ 10 ноября 2008

В WCF, при «толчке» с сервера, вы действительно говорите о дуплексной связи; MarshalByRefObject здесь в значительной степени избыточен (AFAIK). На странице здесь обсуждаются различные сценарии, включая дуплекс / обратные вызовы.

Если проблема в XML (по какой-то философской причине), тогда может помочь просто использование NetDataContractSerializer вместо DataContractSerializer.

Другой подход заключается в том, чтобы клиенты периодически «извлекали» данные; это хорошо работает, если вам нужно поддерживать базовый http и т. д.

1 голос
/ 10 ноября 2008

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

Вам также понадобится служба или приложение Windows для размещения WCF, как консоли, которую вы используете в предыдущем коде.

0 голосов
/ 08 января 2009

Да, это правда, только одна поправка .. ObjRef создаются автоматически, когда любой производный объект MarshalByRefObject выходит за пределы домена приложения. Таким образом, в этом случае ваш метод подписки интерфейса ITengthProvider должен принимать ITengthSubscriber вместо objref. А затем на стороне клиента просто вызовите p1.Subscribe (this), и слой удаленного взаимодействия сгенерирует ObjRef из объекта, который будет сериализован и отправлен. (отправка ссылки b)

0 голосов
/ 10 ноября 2008

Ну, я строю системы реального времени, поэтому опрос не вариант - мне нужно отправить данные.

Также я нахожу, что нет эквивалента WCF System.Runtime.Remoting.ObjRef! Это чрезвычайно полезный тип, который инкапсулирует конечную точку службы и может быть сериализован и передан по сети другой удаленной службе.

Думаю, я буду придерживаться старого доброго удаленного взаимодействия, пока не будет введен эквивалент ObjRef.

...