异步WCF:等待另一个呼叫

时间:2011-06-18 14:26:18

标签: c# wcf multithreading

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

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

Silverlight UserControl 可以通过UI上的 ContentPresenter 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调用(可能会调用也可能不会调用,所以在一个真实的例子中它会更复杂),并与交叉线程一起处理它们通讯? 或者不是,我应该寻找其他解决方案?

提前致谢,

内格拉

2 个答案:

答案 0 :(得分:2)

如果要在不更改任何现有代码的情况下扩展应用程序,可以使用Microsoft Extensibility Framework的MEF。

对于使用带有silverlight的MEF,请参阅:http://development-guides.silverbaylabs.org/Video/Silverlight-MEF

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

  • 您使代码更复杂,维护更少
  • 您正在存储业务知识,应该在客户端中一起调用两个服务

我会打电话给一个聚合这两项服务的服务。

答案 1 :(得分:1)

说实话,对我来说这不是一个好主意。我认为如果你可以在一个“完整”请求中打包“部分”请求并等待它,那将更加简洁。不幸的是,我不知道在WCF中这样做的最佳方式。 可能有一个广义的机制,但我不知道。基本上,您需要一些松散类型的服务层,您可以在其中表示通用请求和通用响应,在服务器中适当地路由请求。然后,您可以轻松地表示请求和响应的集合

这是我个人看待的方法 - 但我不知道它在WCF中会变得多么巧妙。

相关问题