WCF 4新功能介紹(2)

by vivid 7. 九月 2011 01:00

.NET Magazine國際中文電子雜誌

作 者:許薰尹

審 稿:張智凱

文章編號:N110911601

出刊日期:2011/9/7

 

本文延續N110811502《WCF 4新功能介紹(1)》一文的內容,介紹WCF 4提供的新功能,以便於了解如何在分散式服務的開發上應用這些新技術。

訊息路由服務(Router Service)

WCF 4新增一個路由服務可以將用戶端的請求,利用一個名為RoutingService類別,繞送給適當的WCF服務來執行,WCF會檢視訊息的內容,根據你在組態中定義的規則,將訊息正確的繞送。當然,在執行時期你也可以視實際需求來變更路由規則,例如當服務所在的主機掛點時,您可以將訊息送到備援的主機。

路由服務很適合應用在以下情境:

  • 服務備援(Fail-over)。
  • 負載平衡(Load banancing)。
  • 做為不同協定間的轉換橋樑(Protocol Bridging)。

WCF 4提供以下路由服務合約可供使用,本例使用IRequestReplyRouter:

  • ISimplexDatagramRouter:適用在單向訊息,可以有工作階段(Session)。
  • ISimplexSessionRouter:適用在單向訊息,必需有工作階段(Session)。
  • IRequestReplyRouter:適用在請求、回應訊息交換,可以有工作階段(Session)。
  • IDuplexSessionRouter:適用在雙工訊息,必需有工作階段(Session)。

路由服務也支援訊息廣播(Multicast),一個請求可以同時送給多個服務。但只有使用單向、與雙工的訊息交換模式時才能夠支援廣播。請求/回應這類型的訊息交換模式則不支援。

WCF 4提供一個RoutingService類別來支援路由服務,你需要使用裝載程式(host)將其載入執行。RoutingService類別是定義在System.ServiceModel.Routing組件之中,使用之前要先將組件加入參考。路由服務讓用戶端程式不必知道服務的實際位址以及如何實作,用戶端程式只要知道路由服務的所在。裝載此服務的方式和一般的WCF服務差不多,你可以利用ServiceHost類別進行裝載,例如服務裝載程式如下:

using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Discovery;
using System.ServiceModel.Routing;
namespace WF4ConHost {
    class Program {
        static void Main (string[] args) {
            Uri baseAddress = new Uri ( "http://localhost:2924/Service1" );
            Type instanceType = typeof ( WCF4Demo.Service1 );
            ServiceHost host = new ServiceHost ( instanceType , baseAddress );
            host.Open ();
            Console.WriteLine ("Service " + "running. Press <ENTER> to quit." );
            ServiceHost routerSvc = new ServiceHost ( typeof ( RoutingService ) );
            routerSvc.Open ();
            Console.WriteLine ( "RoutingService  " + "running. Press <ENTER> to quit." );
            Console.ReadLine ();
            host.Close ();
        }
    }
}

你可以使用程式或組態檔來設定Routing Service的端點,例如以下組態設定:

<system.serviceModel>
  <services>
    <service behaviorConfiguration = "rconfig" name = "System.ServiceModel.Routing.RoutingService" >
      <host>
        <baseAddresses>
          <add baseAddress = "http://localhost:2925/RoutingService" />
        </baseAddresses>
      </host>
      <endpoint address = "" binding="basicHttpBinding" name="requestReplyEndpoint"
      contract = "System.ServiceModel.Routing.IRequestReplyRouter" />
    </service>
  </services>
  <behaviors>
    <serviceBehaviors>
      <behavior name = "rconfig" >
        <serviceMetadata httpGetEnabled = "True" />
        <routing filterTableName = "ft" />
      </behavior>
    </serviceBehaviors>
  </behaviors>
  <client>
    <endpoint name = "DemoService" address  ="http://localhost:2924/Service1"
    binding = "basicHttpBinding" contract = "*">
    </endpoint>
  </client>
  <routing>
    <filters>
      <filter name = "MatchAllFilter" filterType = "MatchAll" />
    </filters>
    <filterTables>
      <filterTable name = "ft">
        <add filterName = "MatchAllFilter" endpointName = "DemoService" />
      </filterTable>
    </filterTables>
  </routing>
</system.serviceModel>

 

在Client區段之中,你需要設定要叫用的服務之端點資訊,此例中服務的位址為http://localhost:2924/Service1;使用basicHttpBinding。路由服務不必要知道服務的合約為何,因此合約設定為「*」。路由服務使用一個Filter Table來將傳入的訊息對應到Client區段中的端點。在filter元素中將filterType設定為MatchAll,然後在filterTable利用endpointName指明DemoService,表示所有的訊息都會被轉送給DemoService,最後透過ServiceBehavior來套用到路由服務。

用戶端程式組態設定參考如下,Address指向路由服務:

<system.serviceModel>
      <client>
           <endpoint address = "http://localhost:2925/RoutingService"
              binding = "basicHttpBinding"
              contract = "ServiceReference1.IService1"
              name = " MyRouteService" />
      </client>
    </system.serviceModel>

當用戶端使用以下程式建立代理程式,叫用服務SayHi方法時,便將請求送到http://localhost:2925/RoutingService時,會被轉送到http://localhost:2924/Service1

ServiceReference1.Service1Client svc = new ServiceReference1.Service1Client ();
Console.WriteLine (svc.SayHi ("Mary"));

訊息路由服務--Protocol Bridging

訊息路由服務(Protocol Bridging)功能可以讓路由服務來當做一個轉接站,轉換呼叫服務時使用的通訊協定。例如用戶端程式可以使用BasicHttpBinding,使用Http協定和路由服務(Routing Service)溝通,路由服務則可以使用其它Binding,如NetTcpBinding,透過TCP/IP來和服務溝通,參考圖1所示。

clip_image002

圖 1:訊息路由服務--Protocol Bridging。

用戶端程式不需要知道服務所在位置,和使用的Binding,只需要新增一端點,參考如下設定,用戶端程式組態檔案中,位址設定為路由服務所在的URI,使用basicHttpBinding:

<?xml version = "1.0" encoding = "utf-8" ? >
<configuration>
    <system.serviceModel>
<client>
           <endpoint address = "http://localhost:1943/MyRouteService.svc/"
              binding = "basicHttpBinding"  contract = "IService1"  name = "MyRouteService" />
      </client>
    </system.serviceModel>

我們利用一個WCF Service Application來當做是路由服務,假設此服務聽在以下位址:

http://localhost:1943/MyRouteService.svc

MyRouteService.svc不需要包含程式碼,但需要加上路由服務的資訊:

<%@ ServiceHost Service = "System.ServiceModel.Routing.RoutingService, System.ServiceModel.Routing, version = 4.0.0.0, Culture = neutral, PublicKeyToken = 31bf3856ad364e35" %>

路由服務的組態檔案中設定好路由資訊:

<system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name = "MyDemoService" >
          <security mode = "None" />
        </binding>
      </netTcpBinding>
    </bindings>
<client>
      <endpoint name = "DemoService"
                address = "net.tcp://localhost:8384/Service1"
                binding = "netTcpBinding"
                bindingConfiguration = "MyDemoService"
                contract = "*" />
    </client>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "rconfig">
          <routing filterTableName = "ft" />
          <serviceDebug includeExceptionDetailInFaults = "true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <routing>
      <filters>
        <filter name = "MatchAllFilter" filterType = "MatchAll" />
      </filters>
      <filterTables>
        <filterTable name = "ft">
          <add filterName = "MatchAllFilter"   
               endpointName = "DemoService" priority = "0" />
        </filterTable>
      </filterTables>
    </routing>
    <services>
      <service behaviorConfiguration = "rconfig" name = "System.ServiceModel.Routing.RoutingService" >
        <endpoint address = "" binding = "basicHttpBinding"  contract = "System.ServiceModel.Routing.IRequestReplyRouter" />
      </service>
    </services>
  </system.serviceModel>

在Client區段之中,設定服務端點,目前服務的位址為net.tcp://localhost:8384/Service1;使用NetTcpBinding;並透過Binding組態設定將安全性設為None。

根據條件繞送訊息

WCF 4提供多種選項來定義篩選條件,可以讓你根據不同的條件來繞送訊息,這些Filter包含:

  • XPathMessageFilter :使用XPath查詢進行篩選。
  • ActionMessageFilter :篩選WS-Addressing 的action參數。
  • EndpointAddressMessageFilter:根據端點位址篩選。
  • PrefixEndpointAddressMessageFilter :根據端點位址篩選。

如果以上所列尚不能滿足需求,也允許客製化處理。使用組態檔案<filter>區段定義Filter時需要指定名稱(name) 、類型(filterType)與篩選條件( filterData),然後就可以在< filterTable >區段中使用它們。當用戶端的請求送入,找到符合篩選條件時,便利用<client>區段中的端點進行服務的叫用。底下是使用ActionMessageFilter的範例,根據不同的Action,繞送到不同的服務:

<system.serviceModel>
    <services>
      <service behaviorConfiguration = "rconfig" name = "System.ServiceModel.Routing.RoutingService" >
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:2925/RoutingService" />
          </baseAddresses>
        </host>
        <endpoint address = "" binding ="basicHttpBinding"  name = "requestReplyEndpoint"
        contract = "System.ServiceModel.Routing.IRequestReplyRouter" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "rconfig" >
          <serviceMetadata httpGetEnabled = "True" />
          <routing filterTableName = "ft" />   
          <serviceDebug includeExceptionDetailInFaults = "true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <client>
      <endpoint name = "DemoService" address = "http://localhost:2924/Service1"
      binding = "basicHttpBinding" contract = "*" >
      </endpoint>
    </client>
    <routing>
      <filters>
        <filter name = "actFilter1" filterType = "Action" filterData = "http://tempuri.org/IService1/SayHello" />
        <filter name = "actFilter2" filterType = "Action" filterData = "http://tempuri.org/IService1/SayHi" />
       </filters>
      <filterTables>
        <filterTable name = "ft" >
          <add filterName = "actFilter1" endpointName = "DemoService2" />
          <add filterName = "actFilter2" endpointName = "DemoService" />
        </filterTable>
      </filterTables>
    </routing>
  </system.serviceModel>

XPathMessageFilter分組成多種FilterTable,可以使用程式或者是組態檔來定義。你可以設定FilterTable中Filter的優先順序(priority),根據組態設定由上至下,優先順序由高至低。只要其中一個篩選條件符合,便套用不再往下比對。

底下是使用XPathMessageFilter的範例,您可以根據用戶端傳送的訊息加以篩選再繞送到適當的服務以便做到一些分流處理,增進整體執行效能。例如路由服務的組態檔設定如下:

<system.serviceModel>
    <bindings>
      <netTcpBinding>
        <binding name = "MyDemoService" >
          <security mode = "None" />
        </binding>
      </netTcpBinding>
    </bindings>
    <client>
      <endpoint name = "DemoServiceContentilter" address ="net.tcp://localhost:8384/Service1"
            Binding = "netTcpBinding" bindingConfiguration = "MyDemoService"  contract = "*" />
    </client>
    <behaviors>
      <serviceBehaviors>
        <behavior name = "rconfig">
          <routing filterTableName = "ft" />
          <serviceDebug includeExceptionDetailInFaults = "true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <routing>
      <namespaceTable>
        <add prefix ="myns" namespace = "http://MyDemoService.com/" />
      </namespaceTable>
      <filters>
        <filter name = "XPF" filterType = "XPath" filterData="sm:header()/myns:MyDemoService = 100" />
      </filters>
      <filterTables>
        <filterTable name = "ft">
          <add filterName = "XPF"  endpointName = "DemoServiceContentilter"  priority = "1" />
        </filterTable>
      </filterTables>
    </routing>
    <services>
      <service behaviorConfiguration = "rconfig"  name = "System.ServiceModel.Routing.RoutingService">
        <endpoint address = "" binding = "basicHttpBinding"  contract = "System.ServiceModel.Routing.IRequestReplyRouter" />
      </service>
    </services>
  </system.serviceModel>

在<filters>區段中,加入一個XPath類型的篩選條件,將封包中header區段內含命名空間為http://MyDemoService.com/的MyDemoService項目,而MyDemoService項目的值為100的用戶端呼叫篩選出來。

用戶端呼叫時,可以利用MessageHeaders類別加入標頭資訊:

ServiceReference1.Service1Client svc = new ServiceReference1.Service1Client ();
using (OperationContextScope scope =
                new OperationContextScope ( svc.InnerChannel )) {
                OperationContext ctx = OperationContext.Current;
                MessageHeaders messageHeadersElement = ctx.OutgoingMessageHeaders;
                ctx.OutgoingMessageHeaders.Add ( MessageHeader.CreateHeader (
                    "MyDemoService" , "http://MyDemoService.com/" ,  "100"));
                Console.WriteLine (svc.SayHi ("Mary"));
}

這段程式碼產生的封包如下,參考標頭:

<s:Envelope xmlns:s = "http://schemas.xmlsoap.org/soap/envelope/" >
<s:Header>
<MyDemoService xmlns = "http://MyDemoService.com/" > 100 </MyDemoService>
<To s:mustUnderstand = "1" xmlns = "http://schemas.microsoft.com/ws/2005/05/addressing/none"> http://localhost:1943/MyRouteService.svc/ </To>
<Action s:mustUnderstand = "1" xmlns = "http://schemas.microsoft.com/ws/2005/05/addressing/none"> http://tempuri.org/IService1/SayHi </Action>
</s:Header>
<s:Body>
<SayHi xmlns = "http://tempuri.org/" >
<name> Mary </name>
</SayHi>
</s:Body>
</s:Envelope>

備援伺服器清單

有時服務所在的伺服器難免會需要停機,做硬體升級,或故障排除,您可以利用組態檔案來設定備援清單,將用戶端的請求繞送到備援伺服器。這對沒有Web Farm架構的服務而言非常地有用。

參考以下組態檔案中<backupList>備援伺服器清單設定,當WCF遇到CommunicationException 或TimeoutException例外錯誤時,會自動搜尋備援清單,將訊息繞送到備援伺服器。

<routing>
      <backupLists>
        <backupList  name = "bklist" >
          <add endpointName = "DemoServiceContentilter" />
        </backupList>
      </backupLists>
        <namespaceTable>
        <add prefix = "myns" namespace="http://MyDemoService.com/" />
      </namespaceTable>
         <filters>
        <filter name = "XPF" filterType = "XPath" filterData="sm:header()/myns:MyDemoService=100"/>
      </filters>
      <filterTables>
        <filterTable name = "ft">
         <add filterName = "XPF" endpointName = "DeadDemoService"  priority = "0"   backupList = "bklist"
               />
        </filterTable>
      </filterTables>
    </routing>

WCF Web HTTP 服務輔助說明頁面

WCF 4在開發WCF Web HTTP 服務,也新增一些特性,WCF Web HTTP 服務支援REST開發架構。RESTful WCF服務可以讓用戶端程式直接使用HTTP的GET或POST來送出請求。你可以將它想像為類似網站的WCF服務。這類的服務會直接提供用戶端XML類型的資料,因此不需要透過代理程式來叫用。

為了讓用戶端程式較易了解WCF Web HTTP 服務的細節,WCF 4提供了WCF Web HTTP 服務輔助說明頁面,自動產生HTML網頁,來描述叫用服務的相關資訊,例如服物提供的作業(Operation),以及請求與回應的格式。

例如服務定義與實作如下,在SayHi方法上方套用[WebGet],在SayHello方法上方套用[WebInvoke],這樣就可以讓你透過HTTP Get叫用SayHi方法;透過HTTP POST叫用SayHello方法:

using System.ServiceModel.Web;
namespace WCF4Demo {  
    [ ServiceContract]
    public interface IService1 {
        [OperationContract]
        [WebGet]
        string SayHi ( string name );
        [OperationContract]
        [WebInvoke]
        string SayHello ( string name );
    }

    public class Service1 :IService1 {
        public string SayHi ( string name ) {
            return "Hi," + name;
        }
        public string SayHello ( string name ) {
            return "Hello," + name;
        }
    }
}


我們利用主控台裝載此服務程式,這個範例改用WebServiceHost類別來進行服務裝載:

using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
namespace WF4ConHost {
    class Program {
        static void Main ( string[] args ) {
             Uri addr = new Uri ( "http://localhost:9999/Service1" );
            Type instanceType = typeof ( WCF4Demo.Service1 );
            Console.WriteLine ( "服務裝載位址: " + addr.AbsoluteUri );
            Console.WriteLine ( "服務輔助說明頁面位址: " + addr.AbsoluteUri + "help" );
            WebServiceHost host = new WebServiceHost ( instanceType , addr );        
            host.Open ();
            Console.WriteLine ("WCF Web Http Service " + "running. Press <ENTER> to quit." );
            Console.ReadLine ();
            host.Close ();
        }
    }
}

然後在組態檔案中,加入一個webHttpEndpoint標準端點,將其helpEnabled 設定為true:

<standardEndpoints>
      <webHttpEndpoint>
        <standardEndpoint name = "" helpEnabled = "true" />
      </webHttpEndpoint>
    </standardEndpoints>

當你執行裝載程式,可以取得服務資訊如圖2所示:

clip_image004

圖 2:WCF Web HTTP 服務輔助說明頁面。

根據圖14個URI,您可以直接存取輔助說明網頁,參考圖3所示。

clip_image006

圖 3:存取WCF Web HTTP 服務輔助說明頁面。

用戶端程式可以利用WebChannelFactory物件建立和服務的通訊,然後利用HTTP GET或POST來叫用服務:

using System.ServiceModel.Web;
using System.ServiceModel;

namespace WCF4ConsoleClient {
    class Program {
        static void Main ( string[] args ) {
            Uri baseAddr = new Uri ("http://localhost:9999/Service1/" );
            using (WebChannelFactory<WCF4Demo.IService1> cf =
                new WebChannelFactory<WCF4Demo.IService1> ( baseAddr )) {
                WCF4Demo.IService1 channel = cf.CreateChannel ();
                string s;
                s = channel.SayHi ( "Mary" );
                Console.WriteLine ( "使用Get呼叫 : " + s );
                s = channel.SayHello ( "May");
                Console.WriteLine ( "使用POST呼叫 : " + s );
            }
         }
    }
}


執行結果如圖4所示。

clip_image008

圖 4:叫用RESTful WCF服務。

輔助說明頁面也可以在endpointBehaviors中設定,例如以下組態片段所示:

<behaviors>
      <endpointBehaviors>
        <behavior>
          <webHttp helpEnabled = "true" />
          <enableWebScript/>
        </behavior>
      </endpointBehaviors>
    </behaviors>

HTTP快取 (HTTP Caching)

WCF 4也支援WCF Web HTTP 服務快取的功能,能把WCF作業的執行結果放到快取,以增進服務的執行效能。服務在定義時,可以在操作上方套用AspNetCacheProfile Attribute:

using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using System.ServiceModel.Activation;
namespace WCF4Demo {  
    [ServiceContract( Namespace="MyAjaxService" )]
    public interface IService1 {
        [OperationContract]
        [WebGet]
        [AspNetCacheProfile ("MyCache")]
        string SayHi ( string name );
        [OperationContract]
        [WebInvoke]
        string SayHello ( string name );
    }

實作服務的類別要套用AspNetCompatibilityRequirements,讓服務裝載於ASP.NET相容環境中:

[AspNetCompatibilityRequirements ( RequirementsMode = AspNetCompatibilityRequirementsMode.Required) ]
public class Service1 :IService1 {
    public string SayHi ( string name ) {
        return "V2 Hi," + name + " Time:" + System.DateTime.Now.ToString();
    }
    public string SayHello ( string name ) {
        return "V2 Hello," + name;
    }   }  }

裝載服務的組態檔案

<serviceHostingEnvironment aspNetCompatibilityEnabled = "true" multipleSiteBindingsEnabled = "true" />

總結

用戶端程式若要和服務溝通,用戶端程式需要有一個端點資訊,描述服務的位址。但服務所在的位址可能因為故障而變動時,用戶端程式可能就找不到服務,你可以利用WCF Discovery技術來克服這個問題。

如果服務使用到了狀態資料,您可以考慮將狀態資料儲存在AppFabric 分散式的快取系統,如此可以在服務之中共享狀態資訊。

Protocol Bridging可以將SOAP Message 1.1與SOAP Message 1.2轉換,以及使用或不使用WS-Addressing的轉換。

Tags:

WCF | NET 開發 | 許薰尹Vivid Hsu | .NET Magazine國際中文電子雜誌

評論 (49) -

cours de theatre
cours de theatre United States
2017/10/1 上午 12:05:34 #

Major thanks for the blog.Really looking forward to read more. Keep writing.

回覆

can ho osimi
can ho osimi United States
2017/10/7 上午 12:26:14 #

Great, thanks for sharing this blog post.Thanks Again. Really Great.

回覆

can ho bien vung tau
can ho bien vung tau United States
2017/10/9 下午 06:14:48 #

Wow, great article post.Really thank you! Really Cool.

回覆

solarmovie
solarmovie United States
2017/10/10 下午 08:02:51 #

Really enjoyed this blog.Really looking forward to read more. Will read on...

回覆

pirater un compte facebook
pirater un compte facebook United States
2017/10/11 上午 12:28:31 #

Say, you got a nice article post.Really looking forward to read more. Much obliged.

回覆

Website
Website United States
2017/10/14 下午 04:09:33 #

I value the blog.Really thank you! Want more.

回覆

dragon city hack android 1
dragon city hack android 1 United States
2017/10/15 下午 03:38:14 #

Appreciate you sharing, great article.Thanks Again.

回覆

omega xl
omega xl United States
2017/10/15 下午 08:19:27 #

I think this is a real great article.Really looking forward to read more. Much obliged.

回覆

see this page
see this page United States
2017/10/17 下午 02:56:37 #

Im thankful for the article post.Really thank you! Awesome.

回覆

sletrokor
sletrokor United States
2017/10/17 下午 08:28:17 #

Great blog article.Really looking forward to read more. Keep writing.

回覆

VigRx Plus Review
VigRx Plus Review United States
2017/10/19 上午 07:32:30 #

Great, thanks for sharing this article.Thanks Again. Will read on...

回覆

try this website
try this website United States
2017/10/19 下午 06:28:05 #

Wow, great blog post.Much thanks again.

回覆

Osimi SeaView
Osimi SeaView United States
2017/10/21 上午 03:43:27 #

I cannot thank you enough for the article post.Really looking forward to read more. Awesome.

回覆

carte grise en ligne
carte grise en ligne United States
2017/10/21 上午 07:21:33 #

Thanks a lot for the blog.Really looking forward to read more. Want more.

回覆

Turbotax customer service
Turbotax customer service United States
2017/10/24 下午 01:30:43 #

Really enjoyed this blog article.Really thank you! Want more.

回覆

son thinh
son thinh United States
2017/10/28 上午 11:31:01 #

Looking forward to reading more. Great blog post.Really looking forward to read more. Want more.

回覆

EZ Battery Reconditioning
EZ Battery Reconditioning United States
2017/10/30 上午 10:26:36 #

Fantastic blog post.Much thanks again. Really Great.

回覆

plock
plock United States
2017/10/30 下午 06:11:03 #

I value the blog.Thanks Again. Awesome.

回覆

life leadership
life leadership United States
2017/11/1 上午 10:39:18 #

Great blog.Thanks Again. Keep writing.

回覆

phenocal
phenocal United States
2017/11/1 下午 06:07:42 #

Major thanks for the article.Really looking forward to read more. Keep writing.

回覆

phentaslim
phentaslim United States
2017/11/3 上午 10:20:40 #

Thanks-a-mundo for the article.

回覆

sciatica treatment for elderly
sciatica treatment for elderly United States
2017/11/15 上午 10:31:19 #

Looking forward to reading more. Great blog. Cool.

回覆

Hey, thanks for the post.Really thank you! Much obliged.

回覆

swimwear
swimwear United States
2017/11/24 上午 12:39:26 #

Major thankies for the blog article.Thanks Again. Will read on...

回覆

Chad Boonswang and Jeffrey Goodman
Chad Boonswang and Jeffrey Goodman United States
2017/11/26 下午 08:43:48 #

Thanks for sharing, this is a fantastic blog. Keep writing.

回覆

Initial coin offering
Initial coin offering United States
2017/12/3 上午 07:34:45 #

Fantastic post.Much thanks again. Much obliged.

回覆

sextus.mobi
sextus.mobi United States
2017/12/5 下午 12:26:10 #

I cannot thank you enough for the blog post.Really thank you! Much obliged.

回覆

Im thankful for the article. Want more.

回覆

I appreciate you sharing this blog post.Really looking forward to read more. Will read on...

回覆

Izola Lickfelt
Izola Lickfelt United States
2017/12/14 下午 12:05:00 #

Wow, great blog article.Really looking forward to read more. Fantastic.

回覆

advice
advice United States
2017/12/14 下午 07:01:30 #

I really liked your blog article.Thanks Again. Cool.

回覆

Christmas Music
Christmas Music United States
2017/12/15 上午 01:36:13 #

Say, you got a nice article.Really looking forward to read more. Will read on...

回覆

canon drivers
canon drivers United States
2017/12/16 下午 08:39:25 #

Major thankies for the article post.Thanks Again. Want more.

回覆

PMO
PMO United States
2017/12/17 下午 08:14:05 #

I cannot thank you enough for the blog article.Really thank you!

回覆

Darwin Horan
Darwin Horan United States
2017/12/23 下午 04:43:23 #

Thank you ever so for you blog.Thanks Again. Will read on...

回覆

I really liked your blog.Really looking forward to read more. Cool.

回覆

hp driver
hp driver United States
2017/12/25 下午 06:16:27 #

I really liked your article. Fantastic.

回覆

Thanks for sharing, this is a fantastic post.Really looking forward to read more. Really Great.

回覆

I cannot thank you enough for the blog.Much thanks again. Keep writing.

回覆

canon drivers
canon drivers United States
2017/12/27 下午 06:32:20 #

I loved your blog post.Really looking forward to read more.

回覆

drivers hp
drivers hp United States
2018/1/2 上午 09:13:52 #

I cannot thank you enough for the article post.Really looking forward to read more. Want more.

回覆

click resources
click resources United States
2018/1/2 下午 05:16:14 #

Major thanks for the blog.Thanks Again. Really Great.

回覆

A round of applause for your blog article.Really looking forward to read more. Awesome.

回覆

printer drivers
printer drivers United States
2018/1/3 上午 08:36:13 #

I think this is a real great post.Much thanks again. Really Cool.

回覆

best bitcoin casino
best bitcoin casino United States
2018/1/4 下午 07:14:02 #

Enjoyed every bit of your blog post.Really thank you!

回覆

hp printer driver
hp printer driver United States
2018/1/5 下午 07:48:12 #

Appreciate you sharing, great post.Really looking forward to read more. Awesome.

回覆

FBA
FBA United States
2018/1/6 上午 11:52:54 #

I think this is a real great blog.Much thanks again. Really Cool.

回覆

新增評論




  Country flag
biuquote
  • 評論
  • 線上預覽
Loading






NET Magazine國際中文電子雜誌

NET Magazine國際中文電子版雜誌,由恆逸資訊創立於2000,自發刊日起迄今已發行超過500篇.NET相關技術文章,擁有超過40000名註冊讀者群。NET Magazine國際中文電子版雜誌希望藉於電子雜誌與NET Developer達到共同學習與技術新知分享,歡迎每一位對.NET 技術有興趣的朋友們多多支持本雜誌,讓作者群們可以有持續性的動力繼續爬文。<請加入免費訂閱>

月分類Month List