Асинхронный WCF: ждать другого звонка - PullRequest
2 голосов
/ 18 июня 2011

У нас есть старый Silverlight UserControl + WCF компонент в нашей среде, и мы хотели бы увеличить возможность повторного использования этой функции.Компонент должен работать с базовыми функциями по умолчанию , но мы бы хотели расширить на основе текущего проекта (без изменения оригинала, чтобы больше этого элемента управления могло появиться в полной мере).система с разным функционалом).

Итак, мы составили план, где все выглядит великолепно, кроме одной вещи.Вот краткое резюме:

Silverlight UserControl можно расширять и манипулировать с помощью ContentPresenter в пользовательском интерфейсе и наследование ViewModel , событий и сообщений вклиентская логика.

Внутренней бизнес-логикой можно манипулировать с помощью загрузки модуля .

Думаю, все будет хорошо.Например, вы можете отключить / удалить поля из пользовательского интерфейса с переопределенными свойствами ViewModel, а на бэк-энде вы можете избежать некоторых действий с пользовательскими модулями.

Интересная часть - когда вы добавляете новые поля через ContentPresenter .Хорошо, вы добавляете новые свойства в унаследованную ViewModel, а затем можете связываться с ними.У вас есть дополнительные данные .Когда вы сохраняете базовые данные, вы знаете, что это было успешно, тогда вы можете начать сохранять свои дополнительные данные (дополнительные данные могут быть любыми , например, в другой таблице на сервере).Хорошо, мы расширили наш UserControl и внутреннюю логику, а original userControl до сих пор ничего не знает о нашем расширении.

Но мы потерялисделка .Например, мы можем сохранить базовые данные, но при дополнительном сохранении данных возникает исключение, у нас есть обновленные базовые данные, но в дополнительной таблице ничего нет.Мы действительно не хотим такой возможности, поэтому я пришел к этой идее:

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

Я сделал очень упрощенное решение концепции решение, это вывод:

1 начинается отправка

Нажмите клавишу возврата, чтобы отправить второй фрагмент

2 начинается отправка

2 отправка завершена, возвращено: 1

1 отправкавыполнено, возвращено: 2

Служба

namespace MyService
{
    [ServiceContract]
    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class Service1
    {

        protected bool _sameArrived;

        protected Piece _same;

        [OperationContract]
        public Piece SendPiece(Piece piece)
        {
            _sameArrived = false;
            Mediator.Instance.WaitFor(piece, sameArrived);

            while (!_sameArrived)
            {
                Thread.Sleep(100);
            }

            return _same;
        }

        protected void sameArrived(Piece piece)
        {
            _same = piece;
            _sameArrived = true;
        }
    }
}

Кусок (сущность)

namespace MyService
{
    [DataContract]
    public class Piece
    {
        [DataMember]
        public long ID { get; set; }

        [DataMember]
        public string SameIdentifier { get; set; }
    }
}

Посредник

namespace MyService
{
    public sealed class Mediator
    {
        private static Mediator _instance;

        private static object syncRoot = new Object();

        private List<Tuple<Piece, Action<Piece>>> _waitsFor;

        private Mediator()
        {
            _waitsFor = new List<Tuple<Piece, Action<Piece>>>();
        }

        public static Mediator Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (syncRoot)
                    {
                        _instance = new Mediator();
                    }
                }

                return _instance;
            }
        }

        public void WaitFor(Piece piece, Action<Piece> callback)
        {
            lock (_waitsFor)
            {
                var waiter = _waitsFor.Where(i => i.Item1.SameIdentifier == piece.SameIdentifier).FirstOrDefault();

                if (waiter != null)
                {
                    _waitsFor.Remove(waiter);
                    waiter.Item2(piece);
                    callback(waiter.Item1);
                }
                else
                {
                    _waitsFor.Add(new Tuple<Piece, Action<Piece>>(piece, callback));
                }
            }
        }
    }
}

И код на стороне клиента

    namespace MyClient
    {
        class Program
        {
            static void Main(string[] args)
            {
                Client c1 = new Client(new Piece()
                {
                    ID = 1,
                    SameIdentifier = "customIdentifier"
                });

                Client c2 = new Client(new Piece()
                {
                    ID = 2,
                    SameIdentifier = "customIdentifier"
                });

                c1.SendPiece();
                Console.WriteLine("Press return to send the second piece");
                Console.ReadLine();
                c2.SendPiece();
                Console.ReadLine();
            }
        }

        class Client
        {
            protected Piece _piece;

            protected Service1Client _service;

            public Client(Piece piece)
            {
                _piece = piece;
                _service = new Service1Client();
            }

            public void SendPiece()
            {
                Console.WriteLine("{0} send begins", _piece.ID);
                _service.BeginSendPiece(_piece, new AsyncCallback(sendPieceCallback), null);
            }

            protected void sendPieceCallback(IAsyncResult result)
            {
                Piece returnedPiece = _service.EndSendPiece(result);
                Console.WriteLine("{0} send completed, returned: {1}", _piece.ID, returnedPiece.ID);
            }
        }
    }

Так что это хорошая идея ждать другого вызова WCF (который может или не может быть вызван, так что в реальном примере это будет более сложным), и обрабатывать их вместе с межпотоковой связью? Или нет , и я должен искать другое решение?

Заранее спасибо,

negra

Ответы [ 2 ]

2 голосов
/ 18 июня 2011

Если вы хотите расширить свое приложение без изменения какого-либо существующего кода, вы можете использовать MEF, то есть Microsoft Extensibility Framework.

Для использования MEF с Silverlight см .: http://development -guides.silverbaylabs.org / Video / Silverlight-MEF

Я бы не стал ждать 2 вызовов WCF от Silverlight по следующим причинам:

  • Вы делаете свой код более сложным и менее обслуживаемым
  • Вы храните бизнес-знания о том, что две службы должны быть вызваны вместе в клиенте

Я бы назвал одну службу, которая объединила две службы.

1 голос
/ 20 июня 2011

Честно говоря, мне не кажется, что это отличная идея. Я думаю, что было бы лучше, если бы вы могли упаковать оба «частичных» запроса в один «полный» запрос и подождать этого. К сожалению, я не знаю лучшего способа сделать это в WCF. возможно , что есть обобщенный механизм для этого, но я не знаю об этом. По сути, вам понадобится какой-то слабо типизированный сервисный уровень, на котором вы сможете представить обобщенный запрос и обобщенный ответ, соответствующим образом направив запросы на сервер. Затем вы можете легко представить коллекцию запросов и ответов.

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

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