异步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
如果您想在不更改任何现有代码的情况下扩展应用程序,可以使用MEF,即Microsoft扩展框架。
有关将MEF与silverlight一起使用,请参阅:http://development-guides.silverbaylabs.org/Video/Silverlight-MEF
我不会等待来自Silverlight的2个WCF调用,原因如下:
- 您正在使代码变得更加复杂和不易维护
- 您正在客户端中存储业务知识,即应该同时调用两个服务
我会调用聚合了两个服务的单个服务。
老实说,这对我来说不是个好主意。我认为,如果您可以将两个"部分"请求打包为一个"完整"请求,然后等待,会更整洁。不幸的是,我不知道在WCF中实现这一点的最佳方法。可能有一个通用的机制,但我不知道。基本上,你需要一些松散类型的服务层,在那里你可以表示一个通用请求和一个通用响应,在服务器中适当地路由请求。然后,您可以轻松地表示请求和响应的集合。
这是我个人会考虑的方法,但我不知道它在WCF中会有多巧妙。