Silverlight 呼叫自託管的wcf 報跨域異常的處理

sinodzh發表於2013-11-19

  Sileverlight很多時候需要通過wcf和後臺,程式進行互動。如果 iis was託管還好,極端的遇到自託管的程式,console,windowsservice,winform,wpf等,就會出現跨域問題。網上很多解決方式。俺在以下博文基礎上又總結了點。

  以下博文可以先學習下:

    http://blog.csdn.net/boyhxy/article/details/5224112

    http://blog.sina.com.cn/s/blog_74066ace0100vhs5.html

    http://www.cnblogs.com/lxblog/archive/2012/08/02/2620393.html


 

    以下是個人總結

     1.此解決方案與Silverlight版本無關。

     2.可以跨程式託管Domain

     3.可以不寫配置檔案託管Domain和Service

     4.可以用 Stream和Message當Domain返回值

     5.不通過配置實現的自託管程式碼如下:

         


 

     跨域解決方案

     方案1:

      1.在專案中加入clientaccesspolicy.xml,編譯生成內容,複製=true

<?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>

      2. 加入域提供類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.Xml;
namespace TEST
{
    public class DomainService : IDomainService
    {
        public System.ServiceModel.Channels.Message ProvidePolicyFile()
        {
            XmlReader reader = XmlReader.Create("clientaccesspolicy.xml");
            System.ServiceModel.Channels.Message result = Message.CreateMessage(MessageVersion.None, "", reader);
            return result;
        }

    }

    [ServiceContract]

    public interface IDomainService
    {
        [OperationContract]
        [WebGet(UriTemplate = "/clientaccesspolicy.xml")]
        System.ServiceModel.Channels.Message ProvidePolicyFile();
    }
}

 

     3.自託管 啟動跨域訪問

           //啟動跨域訪問
            ServiceHost crossDomainserviceHost = new ServiceHost(typeof(DomainService));
            crossDomainserviceHost.AddServiceEndpoint(typeof(IDomainService), new WebHttpBinding()
                , "http://127.0.0.1:4514/");

            crossDomainserviceHost.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior());
            crossDomainserviceHost.Open();

        注:

            優點:跨域訪問的返回檔案型別是:Content-Type: application/xml 。IE,Chrome都測試過,都可以使用。

            缺點:客戶端過多可能對造成過多的IO請求,需要做多客戶端壓力測試。


 

      方案2:

    1.在專案中加入clientaccesspolicy.xml,編譯生成嵌入資源

    2.加入域提供類

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.Xml;
namespace Test
{
public class DomainService : IDomainService
    {
        public Stream ProvidePolicyFile()
        {

            var policyfile = "Test.clientaccesspolicy.xml";
            Stream result= Assembly.GetExecutingAssembly().GetManifestResourceStream(policyfile);

return result;
} } [ServiceContract] public interface IDomainService { [OperationContract] [WebGet(UriTemplate = "/clientaccesspolicy.xml")] Stream ProvidePolicyFile(); } }

     3.自託管 啟動跨域訪問

        注:

            優點:沒有過多的IO請求。

            缺點:跨域訪問的返回檔案型別是:Content-Type: application/octet-stream 。IE可用,Chrome不可用。


 

     方案3:

         1.加入域提供類

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
using System.ServiceModel.Channels;
using System.Xml;
namespace TEST
{
    public class DomainService : IDomainService
    {
        public Stream ProvidePolicyFile()
        {
            string clientAccessPolicy = "<?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(clientAccessPolicy);
        }

        private Stream StringToStream(string result)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";

            return new MemoryStream(Encoding.UTF8.GetBytes(result));
        }


    }

    [ServiceContract]

    public interface IDomainService
    {
        [OperationContract]
        [WebGet(UriTemplate = "/clientaccesspolicy.xml")]
        Stream ProvidePolicyFile();

    }
}

     3.自託管 啟動跨域訪問

        注:

            優點:沒有過多的IO請求。跨域訪問的返回檔案型別是Content-Type: application/xml。IE,Chrome可用

            缺點:指定了編碼方式,可能帶來侷限性。

   


 

        總結:

              方案3,1一般情況均較好。個人喜歡第3種。

 


 

 

      --Domain--
  ServiceHost crossDomainserviceHost = new ServiceHost(typeof(DomainService));
  crossDomainserviceHost.AddServiceEndpoint(typeof(IDomainService), new WebHttpBinding()
     , "http://localhost:9090/");

  crossDomainserviceHost.Description.Endpoints[0].Behaviors.Add(new WebHttpBehavior());
  crossDomainserviceHost.Open();

  --Service--

  ServiceHost testHost = new ServiceHost(typeof(WCFService), new Uri("http://localhost:9090/WCFService/"));
  testHost.AddServiceEndpoint(typeof(IWCFService), new BasicHttpBinding()
    , "");

  ServiceMetadataBehavior bb = new ServiceMetadataBehavior();
  bb.HttpGetEnabled = true;
  bb.HttpGetUrl = new Uri("http://localhost:9090/WCFService/mex");
  testHost.Description.Behaviors.Add(bb);

  ServiceCredentials credential = new ServiceCredentials();
  testHost.Description.Behaviors.Add(credential);

  testHost.Open();

     注意:請用“http://localhost:9090/WCFService/mex”來尋找服務,目前水平有限,還不能直接通過程式碼實現和配置一樣通過http://localhost:9090/WCFService/"來尋找服務。望大家知道的能回覆答案。

 

相關文章