异步WCF:等待另一个调用

本文关键字:另一个 调用 等待 WCF 异步 | 更新日期: 2023-09-27 17:59:24

我们的框架中有一个旧的Silverlight UserControl+WCF组件,我们希望增加此功能的可重用性。默认情况下,该组件应与基本功能一起使用,但我们希望基于当前项目扩展(不修改原始控件,因此更多控件可以出现在具有不同功能的完整系统中)。

所以我们制定了一个计划,除了一件事,一切看起来都很棒。以下是一个简短的总结:

Silverlight UserControl可以通过UI上的ContentPresenter和客户端逻辑中的ViewModel继承、事件和消息来扩展和操作。

后端业务逻辑可以通过模块加载进行操作。

我想这会好起来的。例如,您可以使用overriden ViewModel属性禁用/删除UI中的字段,并且在后端可以避免对自定义模块执行某些操作。

有趣的部分是通过ContentPresenter添加新字段。好的,将新属性添加到继承的ViewModel中,然后可以绑定到它们。您有附加数据。当您保存基本数据时,您知道它成功了,然后您就可以开始保存您的附加数据(附加数据可以是任何,例如在后端的不同表中)。很好,我们扩展了UserControl和后端逻辑,原始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

异步WCF:等待另一个调用

如果您想在不更改任何现有代码的情况下扩展应用程序,可以使用MEF,即Microsoft扩展框架。

有关将MEF与silverlight一起使用,请参阅:http://development-guides.silverbaylabs.org/Video/Silverlight-MEF

我不会等待来自Silverlight的2个WCF调用,原因如下:

  • 您正在使代码变得更加复杂和不易维护
  • 您正在客户端中存储业务知识,即应该同时调用两个服务

我会调用聚合了两个服务的单个服务。

老实说,这对我来说不是个好主意。我认为,如果您可以将两个"部分"请求打包为一个"完整"请求,然后等待,会更整洁。不幸的是,我不知道在WCF中实现这一点的最佳方法。可能有一个通用的机制,但我不知道。基本上,你需要一些松散类型的服务层,在那里你可以表示一个通用请求和一个通用响应,在服务器中适当地路由请求。然后,您可以轻松地表示请求和响应的集合

这是我个人会考虑的方法,但我不知道它在WCF中会有多巧妙。