在开发Silverlight应用程序时,开发者经常会遇到与WCF服务集成的常见问题。本文旨在分享一种解决方案,使得WCF服务引用变得可配置,从而简化在不同服务器(如开发、测试、用户验收测试等)上的部署过程,而无需修改代码和重新发布。
为了实现这个应用程序,将使用以下技术:
创建一个新的Silverlight业务应用程序,并命名为‘BusinessAppMVVM’。
添加WCF服务到解决方案中,并命名为‘BusinessAppMVVM.AppWCFService’。
在‘Service1.svc.cs’中编写一个测试方法:
public string GetUserAddress(string value)
{
return string.Format("You entered: {0}", value);
}
为此方法添加契约:
[OperationContract]
string GetUserAddress(string value);
为了使Silverlight控件能够访问另一个域中的服务,服务必须明确选择允许跨域访问。还将部署WCF服务和Silverlight应用程序在不同的服务器上。
添加‘CrossDomainService’服务,并添加以下代码:
public class CrossDomainService : ICrossDomainService
{
Message ICrossDomainService.ProvidePolicyFile()
{
FileStream filestream = File.Open(@"ClientAccessPolicy.xml", FileMode.Open);
XmlReader reader = XmlReader.Create(filestream);
System.ServiceModel.Channels.Message result = Message.CreateMessage(MessageVersion.None, "", reader);
return result;
}
}
为此服务添加契约:
[ServiceContract]
public interface ICrossDomainService
{
[OperationContract]
[WebGet(UriTemplate = "ClientAccessPolicy.xml")]
Message ProvidePolicyFile();
}
添加‘ClientAccessPolicy.xml’文件以描述策略。
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
在'web.comfig'文件中添加以下‘appsettings’节:
<appSettings>
<add key="WCFServiceURL" value="http://localhost:59761/Service1.svc" />
</appSettings>
在这一节中,可以拥有所有WCF服务部署的服务器URL,如开发、测试、用户验收测试等。只需取消注释想要在Silverlight项目中使用的服务URL,而无需修改任何代码,也不需要重新部署。
将添加RIA服务以将此URL值传递给Silverlight项目。
在Web项目中添加RIA服务‘BusinessAppRIAService’。
在新的RIA服务中添加以下方法:
[Invoke]
public string GetWCFServiceAddress()
{
string url = ConfigurationManager.AppSettings.Get("WCFServiceURL");
return url;
}
向Silverlight项目添加服务引用。
在‘app.xaml.cs’中声明属性:
public string WCFServiceURL {
get;
set;
}
编写以下代码以在‘Application_UserLoaded’中调用RIA服务获取‘WCFServiceURL’值:
// Call RIA Service to get WCF Service URL
var context = new BusinessAppMVVM.Web.Services.BusinessAppRIAContext();
context.GetWCFServiceAddress(GetWCFServiceURLCompleted, null);
定义‘GetWCFServiceURLCompleted’如下:
private void GetWCFServiceURLCompleted(InvokeOperation args)
{
try
{
WCFServiceURL = args.Value;
}
catch (Exception ex)
{
// log
}
}
现在已经准备好编写测试代码来调用WCF服务了。在‘Home.xaml’中添加按钮控件。在按钮点击事件中编写以下代码:
private void button1_Click(object sender, System.Windows.RoutedEventArgs e)
{
// Create Instance.
BusinessAppServiceModel.Service1Client _serviceClient = null;
if (_serviceClient == null)
{
var myBinding = new BasicHttpBinding();
string url = ((App)Application.Current).WCFServiceURL;
if (url != null)
{
var address = new EndpointAddress(url);
_serviceClient = new BusinessAppServiceModel.Service1Client(myBinding, address);
}
else
{
MessageBox.Show("WCF Service URL is not found.");
}
}
// Call Service
_serviceClient.GetUserAddressCompleted -= new EventHandler<GetUserAddressCompletedEventArgs>(OnGetUserAddressCompleted);
_serviceClient.GetUserAddressCompleted += new EventHandler<GetUserAddressCompletedEventArgs>(OnGetUserAddressCompleted);
_serviceClient.GetUserAddressAsync("Called from UI");
}
定义‘OnGetUserAddressCompleted’如下:
private void OnGetUserAddressCompleted(object sender, GetUserAddressCompletedEventArgs e)
{
MessageBox.Show(e.Result);
}
部署Silverlight和WCF服务。转到Web.config以更改服务URL。可以看到项目在不重新部署的情况下正常工作。