前幾天研究SilverLight時碰到了這個問題,本以為很輕鬆的實驗結果很不順利,查了很多資料才解決了這個問題,在此把解決問題的方法寫出來,也方便其它朋友借鑒。
問題是這樣產生了,我在測試SilverLight時為了測試與WCF的通訊,建立了一個控制台的應用程式做為WCF服務的宿主程式。
同時建立了一個SilverLight應用程式和一個承載SilverLight的Web程式.
解決方案:
控制台程式:
1.添加 WCF服務
命名為WCFService.cs,並添加服務,代碼如下:
namespace WCFBase
{
// 注意: 如果更改此處的類名 "WCFService",也必須更新 App.config 中對 "WCFService" 的引用。
public class WCFService : IWCFService
{
public int DoWork(int a,int b)
{
return a + b;
}
public int DoWork2(int a, int b)
{
return a - b;
}
}
}
系統會自動添加App.config檔案和相關配置節資訊
內容如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="WCFBase.WCFServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="WCFBase.WCFServiceBehavior" name="WCFBase.WCFService">
<endpoint address="" binding="basicHttpBinding" contract="WCFBase.IWCFService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9090/WCFService/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
2.載入WCF服務
開啟主程式入口Main方法,代碼如下
namespace WCFBase
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WCFService));
host.Open();
Console.WriteLine("I'am Here.");
Console.ReadKey();
host.Close();
}
}
}
至此運行該控制台程式,WCF服務啟可使用。
但當垮域訪問時會運行錯誤,提示沒有僅限操作。這時需要如下操作
3.使WCF可以垮域訪問
A.在控制台程式根目添加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>
B.添加介面 IDomainService (名稱可自訂)
首先要添加System.ServiceModel.Web 參考
代碼如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.ServiceModel;
using System.ServiceModel.Channels;
namespace WCFBase
{
/**/
/// <summary>
/// 跨域存取原則服務介面
/// 注意:如果你更新了ICrossDomainService介面,需要同時更新App.Config
/// </summary>
[ServiceContract]
public interface IDomainService
{
[OperationContract]
[WebGet(UriTemplate = "ClientAccessPolicy.xml")]
Message ProvidePolicyFile();
}
}
C.實現介面IDomainService
類:DomainService(可自訂)
代碼如下:
namespace WCFBase
{
public class DomainService:IDomainService
{
#region IDomainService 成員
public System.ServiceModel.Channels.Message ProvidePolicyFile()
{
FileStream filestream = File.Open(@"ClientAccessPolicy.xml", FileMode.Open);
// Either specify ClientAcessPolicy.xml file path properly
// or put that in /Bin folder of the console application
XmlReader reader = XmlReader.Create(filestream);
System.ServiceModel.Channels.Message result = Message.CreateMessage(MessageVersion.None, "", reader);
return result;
}
//CrossDomainServiceBehavior
#endregion
}
}
D.修改App.config檔案
修改後為
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<behaviors>
<serviceBehaviors>
<behavior name="WCFBase.WCFServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="DomainServiceBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="WCFBase.WCFServiceBehavior" name="WCFBase.WCFService">
<endpoint address="" binding="basicHttpBinding" contract="WCFBase.IWCFService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9090/WCFService/" />
</baseAddresses>
</host>
</service>
<service name="WCFBase.DomainService">
<endpoint address="" behaviorConfiguration="DomainServiceBehavior"
binding="webHttpBinding" contract="WCFBase.IDomainService" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9090/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>
灰色地區為新添加的資訊,還沒有完成,繼續...
E.修改控制台開啟主程式入口Main方法
代碼如下:
namespace WCFBase
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(WCFService));
host.Open();
ServiceHost crossDomainserviceHost = new ServiceHost(typeof(DomainService));
crossDomainserviceHost.Open();
Console.WriteLine("I'am Here.");
Console.ReadKey();
host.Close();
}
}
}
灰色地區為新添加代碼
最終程式結構如下:
到此WCF服務即可實現垮域訪問.
注意:需要將clientaccesspolicy.xml檔案複製到 WCFBase.exe相同目錄下。
4.SilverLight與WCF通訊測試
運行控制台程式 WCFBase.exe
:
在SilverLight程式中添加"服務引用",地址為http://localhost:9090/WCFService/
SilverLight代碼如下
private void btnTest_Click(object sender, RoutedEventArgs e)
{
ServiceReference1.WCFServiceClient wcf = new SilverlightApp.ServiceReference1.WCFServiceClient();
wcf.DoWorkCompleted += new EventHandler<SilverlightApp.ServiceReference1.DoWorkCompletedEventArgs>(wcf_DoWorkCompleted);
wcf.DoWorkAsync(1, 2);
}
void wcf_DoWorkCompleted(object sender, SilverlightApp.ServiceReference1.DoWorkCompletedEventArgs e)
{
MessageBox.Show(e.Result.ToString());
}
測試:
證明SilverLight可以正常調用WCF的DoWork方法,並正確返回結果。
原始碼下載:
http://download.csdn.net/source/2014616