问题描述
|
我们的框架中有一个旧的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中效果如何。