我建议您构建一个紧密耦合的模型层以用于您的 RIA 服务。如果模型层能够通过 RIA 完成所需的所有工作,(它应该是可独立测试的)然后您可以使用您建议的接口通过您的视图模型开始转换这些操作;您可以在单独的 Silverlight 库中构建模型层。
我通过使用 TDD 的企业解决方案成功地做到了这一点。如果需要,我可以提供更具体的代码示例,但即使是简单的服务调用也会有很多类。我可以添加一些代码示例。
例如,从底部(服务)到顶部(视图):
我们从非常复杂的 MultiplyService 开始:
namespace StackOverflow.Tutorial.Web
{
using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ServiceModel.DomainServices.Hosting;
using System.ServiceModel.DomainServices.Server;
[EnableClientAccess()]
public class MultiplyService : DomainService
{
[Invoke]
public MultiplyDTO Multiply(MultiplyDTO input)
{
input.Answer = input.A * input.B;
return input;
}
public class MultiplyDTO
{
public int Answer { get; set; }
public int A { get; set; }
public int B { get; set; }
}
}
}
这通过MultiplyContext 类向我们的 Silverlight 客户端公开了一些 RIA 魔法。我们在模型的 Silverlight 端使用这个类:
using System;
using StackOverflow.Tutorial.Web;
using System.ServiceModel.DomainServices.Client;
namespace StackOverflow.Tutorial.Models
{
// This class is tightly coupled to
public class MultiplyServiceAgent : IMultiplyServiceAgent
{
public void Multiply(int a, int b, Action<int> callback)
{
MultiplyContext context = new MultiplyContext();
MultiplyDTO question = new MultiplyDTO() { A = a, B = b };
context.Multiply(question, (answer) =>
{
callback(answer.Value.Answer);
}, null);
}
}
}
我还包括一个接口IMultiplyServiceAgent:
using System;
using System.ServiceModel.DomainServices.Client;
using StackOverflow.Tutorial.Web;
namespace StackOverflow.Tutorial.Models
{
public interface IMultiplyServiceAgent
{
void Multiply(int a, int b, Action<int> callback);
}
}
如果您愿意,可以将服务代理和接口编译到单独的类库中,然后供silverlight 应用程序的视图模型和视图使用,如下所示。首先是 ViewModel:
using System;
using System.Net;
using System.Windows;
using StackOverflow.Tutorial.Models;
namespace StackOverflow.Tutorial.ViewModels
{
public class MultiplyViewModel : DependencyObject
{
IMultiplyServiceAgent agent = new MultiplyServiceAgent();
public int A
{
get { return (int)GetValue(AProperty); }
set { SetValue(AProperty, value); }
}
// Using a DependencyProperty as the backing store for A. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AProperty =
DependencyProperty.Register("A", typeof(int), typeof(MultiplyViewModel), new PropertyMetadata(0));
public int B
{
get { return (int)GetValue(BProperty); }
set { SetValue(BProperty, value); }
}
// Using a DependencyProperty as the backing store for B. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BProperty =
DependencyProperty.Register("B", typeof(int), typeof(MultiplyViewModel), new PropertyMetadata(0));
public int Answer
{
get { return (int)GetValue(AnswerProperty); }
set { SetValue(AnswerProperty, value); }
}
// Using a DependencyProperty as the backing store for Answer. This enables animation, styling, binding, etc...
public static readonly DependencyProperty AnswerProperty =
DependencyProperty.Register("Answer", typeof(int), typeof(MultiplyViewModel), new PropertyMetadata(0));
public void Calculate()
{
agent.Multiply(this.A, this.B, (answer) =>
{
this.Answer = answer;
});
}
}
}
最后是视图:
<UserControl x:Class="StackOverflow.Tutorial.Views.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<StackPanel x:Name="LayoutRoot" Background="White">
<TextBox Name="txtA" Text="{Binding A, Mode=TwoWay}" />
<TextBox Name="txtB" Text="{Binding B, Mode=TwoWay}" />
<Button Name="btnCalculate" Content="Calculate" Click="btnCalculate_Click" />
<TextBlock Name="txtAnswer" Text="{Binding Answer}" />
</StackPanel>
</UserControl>
View 后面有一个简单的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using StackOverflow.Tutorial.ViewModels;
namespace StackOverflow.Tutorial.Views
{
public partial class MainPage : UserControl
{
public MultiplyViewModel ViewModel { get; set; }
public MainPage()
{
InitializeComponent();
this.ViewModel = new MultiplyViewModel();
this.DataContext = this.ViewModel;
}
private void btnCalculate_Click(object sender, RoutedEventArgs e)
{
this.ViewModel.Calculate();
}
}
}
因此,在上面的示例中,我们看到 Silverlight 应用程序的 Web 服务和模型是紧密耦合和集成的。具有 ServiceAgent(s) 和 IService 接口的模型可以构建在其自己的 Silverlight 类库中,并与企业解决方案中的各种 Silverlight 应用程序共享。正如您在问题中指出的那样,由于 RIA 确实要求提供者和消费者如此紧密地耦合,因此限制这种依赖性将防止将来出现问题。
现在提供者和消费者已准备就绪,Silverlight 主应用程序通过 ViewModel 将模型连接到视图。 (通常,ViewModel 和 View 也是紧密耦合的)。