异步WCF:等待另一个呼叫

问题描述

| 我们的框架中有一个旧的Silverlight UserControl + WCF组件,我们希望增加功能的可重用性。认情况下,该组件应具有基本功能,但是我们希望基于当前项目对其进行扩展(无需修改原始项目,因此该控件的更多部分可以在具有不同功能的完整系统中显示)。 因此,我们制定了一个计划,其中除了一件事外,其他所有方面看起来都很不错。这是一个简短的摘要: 可以通过UI上的ContentPresenter扩展和操作Silverlight UserControl,并在客户端逻辑中继承viewmodel的继承,事件和消息传递。 后端业务逻辑可以通过模块加载来操纵。 我想这会没事的。例如,您可以使用重写的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调用(可能会调用也可能不会调用,因此在实际示例中会更复杂)并通过跨线程通信一起处理它们是一个好主意吗?还是没有,我应该寻找其他解决方案? 提前致谢, 内格拉     

解决方法

        如果要扩展应用程序而不更改任何现有代码,则可以使用MEF,即Microsoft可扩展性框架。 有关在Silverlight中使用MEF的信息,请参见:http://development-guides.silverbaylabs.org/Video/Silverlight-MEF 由于以下原因,我不会等待Silverlight发出的2个WCF调用: 您正在使您的代码更加复杂且难以维护 您正在存储业务知识,即应该一起在客户端中调用两个服务 我将称呼增加这两项服务的一项服务。     ,        老实说,这对我来说不是一个好主意。我认为,如果可以将两个“部分”请求打包到一个“完整”请求中,然后等待,那会更整洁。不幸的是,我不知道在WCF中执行此操作的最佳方法。可能有一种通用的机制,但是我不知道。基本上,您将需要一些松散类型的服务层,在其中您可以代表广义的请求和广义的响应,从而在服务器中适当地路由请求。然后,您可以轻松地表示请求和响应的集合。 我个人就是用这种方法看的-但是我不知道在WCF中效果如何。