我的WCF客户端用的silverlight3实现,原因是silverlight3中加入了WCF服务安全性的支持。
首先,在你客户端的开发机器上安装为WCF制做好的证书,可以直接把服务器上的证书导入到新机器中。导入的储存区最好是本地计算机的受信任的根证书颁发机构中,一劳永逸。
新建silverlight项目,为silverlight工程添加服务引用,在生成的ServiceReferences.ClientConfig配置文件中会看到类似的结果,如果没生成,请手动写入,或是仔细检查发布完的WCF服务是否用的basicHttpBinding方式。
<configuration > <system.serviceModel> <bindings> <basicHttpBinding> <binding name="BasicHttpBinding_IServiceForMyself" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="TransportWithMessageCredential" /> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="https://10.11.41.87/WcfServiceForMyself/ServiceForMyself.svc" binding="basicHttpBinding" bindingConfiguration="BasicHttpBinding_IServiceForMyself" contract="ServiceReference2.IServiceForMyself" name="BasicHttpBinding_IServiceForMyself" /> </client> </system.serviceModel> </configuration>
接着让你的工程显示所有文件,打开被引用的WCF服务中的service.wsdl文件,看最后的几行文件,在<soap:address>结点中有你服务的地址,如https://dqgb-ldap001.dqgb.ldap2009.local/WcfServiceForMyself/ServiceForMyself.svc,由于我在内网中开发项目,这个地址是不会被正确解析的,所以要在整个解决方案中用IP地址替换掉dqgb-ldap001.dqgb.ldap2009.local。
下面给出客户端的代码:
XAML文件:
<UserControl xmlns:dataInput="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.Input" x:Class="TestSilverlight3.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:DesignWidth="640" d:DesignHeight="480"> <Grid x:Name="LayoutRoot" HorizontalAlignment="Left" VerticalAlignment="Top"> <Grid.RowDefinitions> <RowDefinition Height="Auto"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" /> </Grid.ColumnDefinitions> <TextBox Width="300" Height="Auto" Name="tb_box" Grid.Row="0" Grid.Column="0"></TextBox> <Button Width="30" Height="Auto" Content="调用" Click="Button_Click" Grid.Row="0" Grid.Column="1"></Button> <dataInput:Label Width="300" Height="Auto" Name="lbl_message" Grid.Row="0" Grid.Column="2"></dataInput:Label> </Grid> </UserControl>
XAML.CS文件:
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 System.Windows.Browser; namespace TestSilverlight3 { public partial class MainPage : UserControl { ServiceReference2.ServiceForMyselfClient myClient; public MainPage() { InitializeComponent(); myClient = new TestSilverlight3.ServiceReference2.ServiceForMyselfClient(); myClient.ClientCredentials.UserName.UserName = "Admin"; myClient.ClientCredentials.UserName.Password = "123"; } private void Button_Click(object sender, RoutedEventArgs e) { myClient.PrintMessageCompleted += new EventHandler<TestSilverlight3.ServiceReference2.PrintMessageCompletedEventArgs>(myClient_PrintMessageCompleted); myClient.PrintMessageAsync(tb_box.Text); } void myClient_PrintMessageCompleted(object sender, TestSilverlight3.ServiceReference2.PrintMessageCompletedEventArgs e) { lbl_message.Content = e.Result; } } }
到这里客户端程序完成。接下来是注意事项。
第一,就是前面提到的,WCF服务要用BasicHttpBinding。这是因为对 Silverlight 可以访问的服务类型存在一些限制。如果没有使用 “启用 Silverlight 的 WCF 服务”模板创建 WCF 服务,必须确保 WCF 服务配置为支持它的 BasicHttpBinding。
第二,当在承载 Silverlight 应用程序的网站之外的任何位置创建服务时,都会产生跨域问题。在 Silverlight 应用程序和服务之间进行跨域调用时会出现安全漏洞,且必须由相应跨域策略明确启用该跨域调用。
当在 Visual Studio 中调试多个单独的 Web 应用程序项目时,常常会出现这种情况,因为已向每个 Web 应用程序分配了不同的端口号。例如,您的 Silverlight 应用程序可能位于 http://localhost:1111 上,而您的服务可能位于http://localhost:2222 上。即使计算机名相同 (localhost),端口号的不同也足以造成跨域问题。
第三,跨域问题的解决。在承载服务的域的根目录中放置一个 clientaccesspolicy.xml 文件,以配置服务允许跨域访问。 配置文件内客如下:
<?xml version="1.0" encoding="utf-8" ?> <access-policy> <cross-domain-access> <policy> <allow-from http-request-headers="*"> <domain uri="http://*"/> </allow-from> <grant-to> <resource path="/" include-subpaths="true"/> </grant-to> </policy> </cross-domain-access> </access-policy>
这里要注意的是加入了<domain uri="http://*/">的配置,这是因为客户端是http的程序,而WCF是https的,若允许从某个 HTTP 应用程序访问 HTTPS 服务,则需要将 <domain uri="http://*/">元素放入<allow-from>元素。
OK,到这里为止,WCF的安全操练全部完成。