WCF and Windows Activation Service(WAS) We have writing WCF services for the last year or so and many have remarked that these can be a pain because of the hosting requirements. In fact I think some wonder why we worry about WCF anyways given that it is so easy to write a Web service. Well let me mention a few features like security, instrumentation, error masking, fault isolation reliability, remoting and transactions that come for free in using WCF. Many of our services run inside the firewall and thus benefit from the performance of using TCP as the transport. We are developing SOA solutions and WCF is the Microsoft platform for delivering SOA. However, functionality did not come without effort as with WCF we must add two host(s) to our project, a console application for testing and a Windows Service for deployment. The Windows service is the most onerous. Well there is hope on the horizon with the introduction of Windows Process Activation Services (WAS) on Windows 2008 Server(W2K8). IIS 7 then becomes the host for our non-http services that are based on TCP or MSMQ. We can then enjoy the same ease of development and deployment that existing for simple Web Services and still derive all the framework benefits that WCF. For those interested in the gory details, with IIS 6, W3Svc module acted as a HTTP listener and then performed process activation (to handle the requests). In IIS 7, these two services are separated and WAS is responsible for the process activation. WAS contains a Configuration component that reads application info from \windows\system32\config\applicationhost.config. This really replaces the IIS metabase. Its process manager will spawn new application pools in response to activation request that are passed to it by listen adapters such as TCP. WCF uses this listening adapter to communicate activation requests received for non-http protocols. As a result we can use IIS 7 to host our WCF services that are using protocols such as TCP or MSMQ.
W3SVC HTTP Manager Configuration Manager SVCHOST.EXE Windows Process Acivation Service Listener Adapter Interface Process Manager IIS 7 Components HTTP.SYS Listeners Non-IIS TCP Listener Adapter named Pipes Adapter MSMQ Adapter Components For an in-depth article on how all this works click http://msdn2.microsoft.com/en-us/magazine/cc163357.aspx.the bottom line is this should make our development effort simpler but there is some setup required on the server side.
Windows Server 2008 Setup Windows Server 2008 is a new product with a Vista-like UI so there is learning curve in feeling our way around but the following must be done. The Application Server component must be started and support enabled for Windows Process Activation Services and for each non-http listener such as TCP Activation.These are configured using the Server Manager and if you want TCP then you should see the following services started: Only using TCP with Port Sharing Additionally, if IIS 7 was installed after WCF then make sure that you run ServiceModelReg so that the WCF extension SVC is recognized by IIS : ServiceModelReg.exe /i /x.
Web Site Setup First we must tell the Web Site(assume Default) about the non-http protocols that our Service(s) might use. In the Server Manager we bring up the IIS Manager and click on the Bindings for the Web Site as shown below: TCP Listener needs to know what port(s) to listen on... 808* Changes made by the Server Manager are reflected in the C:\Windows\System32\inetsrv\config\applicationHost file so its Default site section should now have a bindings section that looks like: <bindings> <binding protocol="http" bindinginformation="*:80:" /> <binding protocol="net.tcp" bindinginformation="808:*" /> of course we can edit this file
Development With the combination of VS2008 and W2K8 there is no need to add a Console and Windows Service Host to each WCF service that we are writting as we can use the built in testing facility that comes with VS2008 for can still use development stage and then WAS for the deployment. the existing techniques VS2008 has a new WCF client testing tool that is evoked when one hits the debug mode F5, however this only works when one is building a WCF Service Library project type. This testing tool is handy as it saves the developer from writing a test client (this is itself is not real hard) so lets assume that we desire this capabilty. We need to combine this capability with the desire to end up with a Web Application for deployment. There are 2 options here: 1. We can start with a Web WCF Service Application project and add a WCF Service Library for testing. 2. Start with a WCF Service Library then manually create a.svc file and Web.Config needed to produce a Web Application hosted as a W2K8 Web Application. The problem with 1 is that we will end up defining the service contract in the WCF Service project. We the add a reference to this Library in the Web project and point the.svc file to it : <%@ ServiceHost Language="C#" Debug="true" Service="WcfServiceLibrary1.Service1" CodeBehind="WcfServiceLibrary1.Service1.cs" %> As a result I recommend solution 2 as it is it pretty easy to copy the WCF library over to the W2K8 server and create an SVC file.
Changing the Solution defaults Create a WCF Service Library, which will setup a project with an App.Config containing all the ServiceModel definitions for the default service name which is Service1. Lets us assume that we want this to be Logger. It is also setup for HTTP which we will change later. But the first thing is to change the Service name to something more meaningful so do a CTRL-H to bring up the replace dialog and globally change in the project Service1 to Logger, (make sure Look In is set to Current project) this should make about 11-12 changes. The name of the Files in Solution Explorer is still the defaults so just inline change them to ILogger.cs and Logger.cs.We also need to change the default Namespace to follow IEI conventions so IEI.Adept.NNNNN where NNNNN is your asssigned name. e.g IEI.Adept.Logger. Both the ILogger.cs and Logger.cs files must be changed. As a result the Logger.svc.cs file that contains the implemention of our service should look like : namespace IEI.Adept.Logger public class Logger : ILogger
Changing the Solution defaults The Binding defaults to HTTP so change it to TCP with the following changes: binding = wshttpbinding to binding = nettcpbinding baseaddress = "net.tcp://localhost:8001" Change the MetaData binding to MexTcpBinding This is only needed for testing Finally on the <ServiceMetaData> Tag remove the httpgetenabled=true We can now test the TCP binded service by just pressing F5. The app.config should look like: namespace IEI.Adept <system.servicemodel> public class Logger : ILogger <services> <service name="iei.adept.logger" <host> <baseaddresses> <add baseaddress = "net.tcp://localhost:8001/" /> </baseaddresses> </host> behaviorconfiguration="iei.adept.logger.loggerbehavior"> <endpoint address ="" binding="nettcpbinding" contract="iei.adept.ilogger"> </endpoint> <endpoint address="mex" binding="mextcpbinding" contract="imetadataexchange"/> </service> </services> Implementation namespace IEI.Adept [ServiceContract()] public interface ILogger
Deployment After building the WCF service and testing it then it can be deployed as Web Application on W2K8 as follows: 1. Create a new directory under the IIS virtual root for example Logger. Copy the service library (DLL) to Logger/Bin and the PDB file for debugging. In this case assume it is Logger.DLL. 2. Open a text file in VS and create the SVC file. This file is specific to WCF and is used by IIS to find the Service Contract as the servicehost is the link between incoming request and the service model. <%@ ServiceHost Language="C#" Debug="true" Service="IEI.Adept.Logger"%> <%@ Assembly Name="Logger"%>" Now save this file as Logger.svc. 3. We need a Web.Config for our web application so take a basic generated Web.config for a IIS Web Site and add the ServiceModel information from the development project. 4. Finally go into Server Manager and create a new IIS Application called Logger pointing to Logger directory and use the Advanced Settings tab to add net.tcp support. As long as the PDB files are in the Bin and the source is available on the server then standard break points can be set in tghe application even though it is launced just-in-time by IIS. Yes we can Debug NOTE: As we are using IIS to hos the service when a client is adding a service reference the address we supply is of the form: net.tcp://server/logger/logger.svc Virtual directory
Development WCF Library Look Ma, no Windows service needed Windows 2008 Server IIS 7 Logger project Logger.cs ILogger.cs App.Config. Extract ServiceModel IIS App Default Web Site Logger Logger.svc web.config tells IIS where to find the service Bin Logger.DLL Logger.PDB Copy Bin Logger.DLL Logger.pdb Just press F5 to Test JIT Activation Client will use net.tcp://iis server name/logger/logger.svc when adding a service refernce
Factory One major problem with the Web Application is that there is no where to place startup code as there is no Main, I often put configuration code here instead of the config file. However in 3.5 a new keyword was added to the SVC file called Factory that can solve this issue. Now the SVC file will look like : <%@ ServiceHost Language="C#" Factory="MyFactory" Debug="true" Service="Service" %> We the add our Factory code such as : public class MyFactory : ServiceHostFactory protected override ServiceHost CreateServiceHost(Type servicetype, Uri[] baseaddresses) MyCustomHost customhost = new MyCustomHost(serviceType, baseaddresses); return customhost; Force Break Point } public class MyCustomHost : ServiceHost public MyCustomHost(Type servicetype, params Uri[] baseaddress) : base(servicetype, baseaddress) Debugger.Break(); NetTcpBinding Binding = new NetTcpBinding(SecurityMode.Message); this.addserviceendpoint(typeof(iservice), cb, baseaddress[0]); Depends on which transport protocols configured Setup the service Endpoint ServiceMetadataBehavior smb = this.description.behaviors.find<servicemetadatabehavior>(); if (smb == null) smb = new ServiceMetadataBehavior(); smb.httpgetenabled = true; this.description.behaviors.add(smb); this.addserviceendpoint( ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex" ); Setup Metadata endpoint