This is the third article in the endpoints and service addressing series.Article.
3. Use channelfactory <tchannel> to replace the Service proxy object
In the previous two experimentsProgramCodeWe can see that the client uses the service proxy object to call the remote service. Is there any other choice? The answer is yes.
In this experiment, the server code, server configuration file, and client configuration file in [WCF] endpoint and service addressing (ii) are still used. Therefore, this experiment studies the code of the client program. First, define a method:
Code
Private Static Void Callservicebychannelwithoutspecifyingendpoint_getservermachinename ()
{
Channelfactory < Wcf_study1.client.services.isysteminfoservicecontract > Factory
= New Channelfactory < Wcf_study1.client.services.isysteminfoservicecontract > ();
Wcf_study1.client.services.isysteminfoservicecontract proxy=Factory. createchannel ();
/*
* An exception is thrown when you call the method used to create a proxy, because a clear endpoint is not specified for channelfactory,
* The correct method of use should be passed in a configuration endpoint name in the constructor method of channelfactory, or manually constructed
* An endpoint object is passed in.
*/
Console. writeline ("Call Background: No endpoint is specified to call the service.");
Console. writeline ("Agent category: A Channel directly created using channelfactory.");
Console. writeline ("Call result: Remote Server Name: {0}", Proxy. getservermachinename ());
Console. writeline ();
}
One interesting part of this Code is that I didn't use the wcf_study1.client.services.systeminfoservicecontractclient Service proxy like in my previous experiment. Instead, I switched to a type called channelfactory <consumer>. This type can be known from the name, that is, the channel factory. It is a generic type, so what type is specified in the type parameter for control? The answer is: control the creation of a channel that serves a specific endpoint, which is the service contract specified in the public type parameter. So what is the relationship between the channel and the endpoint? I will leave the answer to this question in the subsequent channel topic articles, because I do not need to know this relationship where I am concerned.
In the preceding method definition, another highlight is the call of the createchannel method. As the name suggests, this method is used to construct a channel object, which implements the interface defined in the type parameter. As we define the type parameter as a service contract, the returned channel can be used as a service contract to call the remote service. However, when we call this method, the following exception occurs:
The description of this exception is similar, because the client has two endpoints, the client endpoint used must be specified for the Service proxy (although it is not a service proxy, it is similar to creating a service proxy ). This topic is introduced again because the exception occurred this time, instead of creating a service proxy, but calling the createchannel method. This shows that the direct construction of the Service proxy is similar to the construction using the createchannel method. The modified method definition is as follows:
Code
Private Static Void Callservicebychannel_useservicecontract_getservermachinename ()
{
Channelfactory < Wcf_study1.client.services.isysteminfoservicecontract > Factory
= New Channelfactory < Wcf_study1.client.services.isysteminfoservicecontract > ( " Basichttpbinding_isysteminfoservicecontract " );
Wcf_study1.client.services.isysteminfoservicecontract proxy=Factory. createchannel ();
Console. writeline ("Call Background: Use the HTTP protocol as the binding endpoint to call the service.");
Console. writeline ("Agent category: A Channel directly created using channelfactory.");
Console. writeline ("Call endpoint Logical Address: {0}", Factory. endpoint. Address. tostring ());
Console. writeline ("Channel Type: {0}", Proxy. GetType ());
//Note: Check the end point used by the proxy, which is provided by channelfactory.
Console. writeline ("Call result: Remote Server Name: {0}", Proxy. getservermachinename ());
Console. writeline ();
}
Readers may already have a question: how is a mechanism to ensure that the type specified by the type parameter in channelfactory <tchannel> must be able to construct a correct service proxy (Channel) what about it? It is impossible to create a normalclass (this is what I will do later? Before answering this question through an experiment, let's look at the definition of a method:
Code
Private Static Void Callservicebychannel_useservicecontractchannel_getservermachinename ()
{
Channelfactory < Wcf_study1.client.services.isysteminfoservicecontractchannel > Factory
= New Channelfactory < Wcf_study1.client.services.isysteminfoservicecontractchannel > ( " Basichttpbinding_isysteminfoservicecontract " );
Wcf_study1.client.services.isysteminfoservicecontractchannel proxy=Factory. createchannel ();
Console. writeline ("Call Background: Use the HTTP protocol as the binding endpoint to call the service.");
Console. writeline ("Agent category: A Channel directly created using channelfactory.");
Console. writeline ("Call endpoint Logical Address: {0}", Factory. endpoint. Address. tostring ());
Console. writeline ("Channel Type: {0}", Proxy. GetType ());
//Note: Check the end point used by the proxy, which is provided by channelfactory.
Console. writeline ("Call result: Remote Server Name: {0}", Proxy. getservermachinename ());
Console. writeline ();
}
There is a new type in the code, that isWcf_study1.client.services.isysteminfoservicecontractchannel, which is the real service proxy channel type (which is an interface). It used the service contract type (which is also an interface) And now uses the channel type. I used the same method in the above method to let channelfactory <tchannel> use the createchannel method to construct a usable object for me (using it to call remote services ), the only difference is that the Service proxy channel type object is constructed this time. This code can still work normally, but it also deepens questions.
In order to answer questions in the experiment, I have created three types:
[Servicecontract]
Public Interface Interfacewithservicecontractattr {}
Public InterfaceNormalinterface {}
Public ClassNomalclass {}
Then I use these three types as the type parameters in channelfactory <tchannel>. Then construct the channel factory and call the createchannel method to obtain the following three exceptions,
Use normalclass as the type parameter:
Use normalinterface as the type parameter:
Use interfacewithservicecontractattr as the type parameter:
The preceding three exceptions can be summarized to make channelfactory <tchannel> successfully construct the type object in the type parameter.At leastYes: there is a service contract type configured by the client endpoint. The two types just demonstrated are inherited from such a service contract type. Watch the following code:
Code
Namespace Wcf_study1.client.services {
[System. codedom. compiler. generatedcodeattribute ( " System. servicemodel " , " 4.0.0.0 " )]
[System. servicemodel. servicecontractattribute (namespace = " Http://www.dreamofflea.net " , Configurationname = " Services. isysteminfoservicecontract " )]
Public Interface Isysteminfoservicecontract {
[system. servicemodel. operationcontractattribute (Action = " http://www.dreamofflea.net/ISystemInfoServiceContract/GetServerMachineName " , replyaction = " http://www.dreamofflea.net/ISystemInfoServiceContract/GetServerMachineNameRespons " +
" E " )]
string getservermachinename ();
}
[System. codedom. compiler. generatedcodeattribute ("System. servicemodel","4.0.0.0")]
Public InterfaceIsysteminfoservicecontractchannel: wcf_study1.client.services.isysteminfoservicecontract, system. servicemodel. iclientchannel {
}
[System. Diagnostics. debuggerstepthroughattribute ()]
[System. codedom. compiler. generatedcodeattribute ( " System. servicemodel " , " 4.0.0.0 " )]
Public Partial Class Systeminfoservicecontractclient: system. servicemodel. clientbase < Wcf_study1.client.services.isysteminfoservicecontract > , Wcf_study1.client.services.isysteminfoservicecontract {
Is there any other way to use the createchannel method of channelfactory <tchannel> to create a proxy even if the endpoint is not configured on the client? After receiving a message from a netizen, I added this method (thanks to the netizen ).
Code
Private Static Void Createtchannelwithoutclientconfiguedendpoint ()
{
Console. writeline ( " Use the interface type marked as the service contract as the type parameter to construct the channelfactory, Does the service contract have a corresponding endpoint configured? When constructing a channel object, specify the logical address \ n of the service endpoint. " );
Endpointaddress EA= NewEndpointaddress (@"HTTP: /localhost: 8000/systeminfoservice");
Channelfactory<Isysteminfoservicecontract>Factory= NewChannelfactory<Isysteminfoservicecontract>(NewBasichttpbinding (), EA );
Isysteminfoservicecontract proxy=Factory. createchannel ();
Console. writeline ("Call Background: directly specify the end point address of the server to use channelfactory <tchannel> to create a channel object and call the service.");
Console. writeline ("Agent category: A Channel directly created using channelfactory.");
Console. writeline ("Call endpoint Logical Address: {0}", Factory. endpoint. Address. tostring ());
Console. writeline ("Channel Type: {0}", Proxy. GetType ());
//Note: Check the end point used by the proxy, which is provided by channelfactory.
Console. writeline ("Call result: Remote Server Name: {0}", Proxy. getservermachinename ());
Console. writeline ();
}
In the code of this method, I have not specified the client endpoint configuration anywhere, when constructing the channelfactory <tchannel> object, the access address of the end point of the server is explicitly specified as a parameter, and the binding type is also used. At the same time, the service contract type is used in the type parameter (in fact, the three elements of the endpoint are specified through programming rather than configuration-service contract, binding, and address ). In this way, remote service calls can be performed without configuration. In fact, all the things that can be done through configuration can be achieved through programming. I mentioned earlier that this series of articles only focus on the configuration method, because it is simple and flexible,