There exists a service implementation in Test1 as well as in Test2.Service folders.
You can download the source referenced here from http://sourceforge.net/projects/asyncwcflib.
We use code from Test2.Service to explain the main points you need to know.
Solution and projectfiles for the following environments are provided:
This sourcefile contains code for program startup and shutdown.
Our service is implemented in class 'Test2ServiceNew'. This class exposes an Input member of interface type 'IActorInput'.
To prepare a WCF service we just link this input to network and provide the service name 'Test2.ServiceNew'. "New" stands for the newer version of this service (Test2 is prepared to test communication between older and newer data contracts).
public FrmService() // constructor { Test2Rsp.AddKnownMessageTypes(); m_ServiceNew = new Test2ServiceNew (); m_ServiceNew.Input.LinkInputToNetwork ("Test2.ServiceNew"); }
On program shutdown we only need to call 'ActorPort.DisconnectAll()' to send disconnect messages from all ActorOutputs and shutdown all ActorInputs of the application.
private void Form1_FormClosing(object sender, FormClosingEventArgs e) { // Close+Dispose the ServiceHost and RouterClient. ActorPort.DisconnectAll(); }
To open and reconnect the ActorInput and to check whether clients have timed out, we need a periodic timer.
Here we also update some information about the service on the WinForm.
private void timer1_Tick (object sender, EventArgs e) { m_ServiceNew.DoPeriodicTasks (); }
In the constructor we create a ActorInput object. Its 'Input' interface is exposed to FrmService. There it is linked to network.
In turn, a WCF service and host are created under the hood.
As on the client, we have to provide a messagehandler method to the constructor. This method will be called upon reception of a WcfMessage (the requests).
public Test2ServiceNew () { m_Input = new ActorInput ("NEW", WcfRequest); } public void WcfRequest (WcfReqIdent req) { if (req.Message is Test2Req) { response = new WcfIdleMessage(); } else { req.SendResponse (new WcfErrorMessage (...)); // an additional notification response = new Test2Rsp(); } req.SendResponse (response); }
To generate your own response you must lookup the type of request and react accordingly.
In case of error (unknown request, data not available, exception, ...) you should return a WcfErrorMessage containing information helping find the error reason.
You are free to send more than one response to the client.
From any place in your program you can queue notifications to the client represented by req.Sender (a ActorPort property).
The last response to a request is appended to all queued notifications and returned to the client after its await statement.
When no response is provided, AsyncWcfLib returns a WcfIdleMessage to the client.
Applications with services contain at least one automatically created client for the WcfRouter. This client connects itself to the WcfRouter service on the local host using TCP portnumber from WcfDefault class.
When no configuration block for the service is present, the service uses the default binding from WcfLib.WcfDefault.Instance when connected to network.
Library users may plug in their own implementation of 'WcfLib.IWcfDefault' or subclass 'WcfLib.WcfDefault.cs' in order to overwrite the default binding.
By providing the optional parameter 'serviceConfig' to LinkInputToNetwork() it is possible to programmatically overwrite the default binding for each service.
See also [Service- and client identification].
The WcfRouter synchronizes its known services with other routers on other hosts.
These hosts must be configured in the SF.AsyncWcfLib.Router.exe.config file.
Each router will receive the list of services and will merge the list with its own known services.
Then each router will propagate the merged list to the hosts configured in its own config file.
In order to merge the list of servicenames, the following rules apply:
The list of peer hosts is configured as follows:
<applicationSettings> <SourceForge.AsyncWcfLib.Properties.Settings> <setting name="PeerHosts" serializeAs="Xml"> <value> <ArrayOfString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <string>TESTHOST37</string> <string>192.168.1.77</string> </ArrayOfString> </value> </setting> </SourceForge.AsyncWcfLib.Properties.Settings> </applicationSettings>
It may be interesting for you to fully configure a service with two endpoints as intended by WCF.
This configuration block is optional. When not provided, the defaults fom WcfLib.WcfDefault.cs are used.
One instance of WcfRouter runs on every host. It is therefore easy to configure. The same file can be used on every host.
As second endpoint we open "mex", metadata exchange endpoint. It can be used to read out operation- and data contracts with VisualStudio or with a browser.
"/AsyncWcfLib/" in the URI is the hardcoded constant AsyncWcfLib.WcfDefault.WsNamespace. When you change this value, you have to adapt the configured service baseAddress accordingly.
<configuration> <system.serviceModel> <services> <service behaviorConfiguration="RouterServiceBehavior" name="AsyncWcfLib.RouterService"> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="" name="RouterServiceEndpoint" contract="AsyncWcfLib.ServiceContract" /> <endpoint address="mex" binding="mexHttpBinding" name="mex" contract="IMetadataExchange" /> <host> <baseAddresses> <add baseAddress="http://localhost:40000/AsyncWcfLib/RouterService" /> </baseAddresses> </host> </service> </services> <behaviors> <serviceBehaviors> <behavior name="RouterServiceBehavior"> <serviceMetadata httpGetEnabled="true" /> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
Wiki: AsyncWcfLib package diagram
Wiki: Home
Wiki: Run AsyncWcfLib.Test1
Wiki: Service- and client identification