Silverlight中WCF的百分百完美简单实现!
在我刚开始接触Silverlight的时候,要建一个网站是多么容易的事情。但是如果用到了WCF,经常会出现跨域错误,而且Silverlight-enabled WCF也不好用,因为发布不方便,头痛无比。网上的攻略很多,但是大都都是只能针对他们自己的机器能用,或者断断续续的讲一些原理,看了还是不是很懂。
这里我贴出代码,让你直接复制粘贴代码就能使,保证能用。
我的构建方法很简单:WCF就是一个C#的Console Window Application,简而言之:“控制台程序”,注意我用的是.Net Framework 3.5,别的版本不知道能不能使,尤其是中间有个WebGet属性,需要调用System.ServiceModel.Web,有些System.ServiceModel.Web可能没有WebGet,所以这个保证能用啦!
第一步:新建一个控制台程序,拷贝下面一段代码复制到你的Program.cs,覆盖原来的,改一下那个namespace和类名成为你自己需要的,添加一些没有添加的引用,注释里面写的很清楚(亲测可用)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Threading;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Runtime.Serialization;
using System.Net;
using System.ServiceModel.Description;
namespace Test
{
//using System.ServiceModel;
[ServiceContract]
public interface IPolicyRetriever
{
//WebGet: using System.ServiceModel.Web;
[OperationContract, WebGet(UriTemplate = "/clientaccesspolicy.xml")]
Stream GetSilverlightPolicy();
[OperationContract, WebGet(UriTemplate = "/crossdomain.xml")]
Stream GetFlashPolicy();
}
//using System.Runtime.Serialization;
[DataContract]
public class People
{
[DataMember]
public string Name { get; set; }
[DataMember]
public int Age { get; set; }
}
[DataContract]
public enum Sex
{
[EnumMember]
Male,
[EnumMember]
Female
}
[ServiceContract]
public interface IPeople
{
[OperationContract]
List<People> GetAllPeople();
}
public class PeopleService : IPolicyRetriever, IPeople
{
public List<People> GetAllPeople()
{
//Add your own code
return null;
}
public Stream GetSilverlightPolicy()
{
string result = @"<?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>";
return StringToStream(result);
}
public Stream GetFlashPolicy()
{
string result = @"<?xml version=""1.0""?>
<!DOCTYPE cross-domain-policy SYSTEM ""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">
<cross-domain-policy>
<allow-access-from domain=""*"" />
</cross-domain-policy>";
return StringToStream(result);
}
Stream StringToStream(string result)
{
WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
return new MemoryStream(Encoding.UTF8.GetBytes(result));
}
}
class Program
{
static void Main(string[] args)
{
// Step 1 of the address configuration procedure: Create a URI to serve as the base address.
//using System.Net;
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
string ipAddr = localIPs[3].ToString();
Console.WriteLine(ipAddr);
Uri baseAddress = new Uri("http://" + ipAddr + ":8681");
// Step 2 of the hosting procedure: Create ServiceHost
ServiceHost selfHost = new ServiceHost(typeof(PeopleService), baseAddress);
try
{
// Step 3 of the hosting procedure: Add a service endpoint.
selfHost.AddServiceEndpoint(
typeof(IPeople),
new BasicHttpBinding(),
"PeopleService");
selfHost.AddServiceEndpoint(
typeof(IPolicyRetriever),
new WebHttpBinding(),
"").Behaviors.Add(new WebHttpBehavior()); //using System.ServiceModel.Description;
// Step 4 of the hosting procedure: Enable metadata exchange.
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
// Step 5 of the hosting procedure: Start (and then stop) the service.
selfHost.Open();
Console.WriteLine("Service:" + baseAddress.AbsoluteUri);
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
// Close the ServiceHostBase to shutdown the service.
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("An exception occurred: {0}", ce.Message);
selfHost.Abort();
}
}
}
}
第二步:在工程的根目录里建立两个文件:
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
crossdomain.xml
<?xml version="1.0"?>
<cross-domain-policy>
<allow-access-from domain="*"/>
</cross-domain-policy>
如图:
然后再把这两个文件添加到Visual Studio的Solution Explorer的相应工程的引用中去,如图:
这里的工程名字是我的另外一个工程的名字,与本文无关,希望不会影响你的理解。
反正就是把文件拖到这里面就行了,或者右键单击工程,选择add->exist items,然后选这两个添进来就行了
第三步:重新Build工程,找到工程的bin/debug文件夹,里面的exe打开,如图:
这个时候WCF就建好了,建在显示的那个地址上的,包含了两个Service,一个是你自定义的Service,一个是跨域的Service
拷贝一下那个http://XXX.XX.XXX.XXX:8681
然后右键单击你的Silverlight工程,添加Service Reference, 如图:
就看到啦,就可以在Silverlight里用啦。
第四步:发布网站
当你的网站建好了之后,你想发布,你想让别人也看到这个网站,就这么做:
先安装好IIS,我图中的显示的是IIS6.0还是7.0忘记了,版本低的盆友自己赶紧升级哦。
然后在IIS中新建一个网站,注意程序池一定要选.net 4.0哦,端口号自己随便设一个,比如8624
物理路径就是建Silverlight时自带的.Web工程
然后图中的默认文档(Default Document)添加.Web工程中的那个主页,名字复制好点添加就行了
这个时候你就可以直接通过右击网站,选择Manage Web Site->Browse进行浏览了,你会发现网址中是一个很纯粹的localhost:8624的形式,没有什么多余的文件名。
如果想通过外部访问这个网站,只需要把localhost改成你的主机名就行了,主机名的查询方法就是右击“我的电脑”,选择属性,就有主机名显示了。当然,如果你用了路由器就比较麻烦,要做端口映射,自己查别的文献去吧,这个不在本文的讨论范围之内了。
综上所述,这个方法不受电脑的限制,也就是说两台联网的机器上,一台建WCF,一台建Silverlight工程也行,反正就是很简答,百试不爽!
如果讲的这么清楚你还搞不好,发邮件给我 ustcwhc@gmail.com
Good luck!