我们的框架中有一个旧的 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调用(可能会调用也可能不会调用,所以在一个真实的例子中它会更复杂),并与交叉线程一起处理它们通讯? 或者不是,我应该寻找其他解决方案?
提前致谢,
内格拉
答案 0 :(得分:2)
如果要在不更改任何现有代码的情况下扩展应用程序,可以使用Microsoft Extensibility Framework的MEF。
对于使用带有silverlight的MEF,请参阅:http://development-guides.silverbaylabs.org/Video/Silverlight-MEF
我不会等待来自Silverlight的2个WCF调用,原因如下:
我会打电话给一个聚合这两项服务的服务。
答案 1 :(得分:1)
说实话,对我来说这不是一个好主意。我认为如果你可以在一个“完整”请求中打包“部分”请求并等待它,那将更加简洁。不幸的是,我不知道在WCF中这样做的最佳方式。 可能有一个广义的机制,但我不知道。基本上,您需要一些松散类型的服务层,您可以在其中表示通用请求和通用响应,在服务器中适当地路由请求。然后,您可以轻松地表示请求和响应的集合。
这是我个人看待的方法 - 但我不知道它在WCF中会变得多么巧妙。