·
Windows
Communication Foundation (WCF) introduced in .NET Framework 3.0
·
What was before WCF for distributed
applications: .Net Remoting, Web Services
o
.Net
Remoting: Both Client and Service should be of same technology i.e. .Net.
We can use these services with other applications but we should be careful
about data types that we are using. We cannot use some classes of .Net e.g:
Activator to activate .Net remote service
o
Web
Service: different protocols and message formatting needs different service
hosting
·
In WCF, using endpoints we can overcome both
above problems
·
System.ServiceModel
is the core assembly of WCF. All
required attributes and classes are present in this assembly
·
Sample
WCF Configuration
<configuration>
<system.serviceModel>
<services>
<service name=”Namespace.ClassName”
behaviorConfiguration=”mexBehaviorConfigName”>
<endpoint address=”ServiceName” binding=”basicHttpBinding” contract=”Namespace.InterfaceName”></endpoint>
<endpoint address=”ServiceName” binding=”netTcpBinding” contract=”Namespace.InterfaceName”></endpoint>
<endpoint
address="mex" binding="mexHttpBinding" contract="IMetadataExchange"></endpoint>
<host>
<baseAddresses>
<add baseAddress=”net.tcp://localhost:8090/” />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior
name=”mexBehaviorConfigName”>
<serviceMetadata
httpGetEnabled=”true”/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
·
Mex binding
is mandatory to get WSDL document, which is contains all the metadata of
service
·
We can use name
attribute of Service Contract to prevent from breaking the service in case of
any change in service name. e.g. [ServiceContract(name=”NameKnownToClient”)].
This sets the PortType property in
WSDL which is used to identify the service. So though we change the service
name (i.e. name of interface), client will be able to access the service using the
name provided in name attribute. Same we can use for Operation Contracts as
well.
·
With respect to WCF, Serialization is the process of converting an object into the XML representation
and the reverse process is known as Deserialization
·
By default WCF uses DataContractSerialization. We can serialize an object using either Serializable attribute or DataContract
attribute.
·
.Net 3.5
and above don’t need to explicitly use DataContract or DataMember attribute. Data
Contract Serializer will automatically serialize all your public properties (except private fields and properties) in
alphabetically.
·
If we use [Serializable]
attribute to serialize object then DataContractSerializer will serialize all
the fields [including private fields].
We don’t have explicit control on
which fields to be serialized.
·
If we use [DataContract]
attribute to serialize object, then DataContractSerializer will serialize only fields marked with [DataMember] attribute. Other fields/
properties are excluded.
·
[Datamember]
can be applied on both public as well as
private fields/ properties
·
[DataContract(Namespace=”http://localhost:8080/anyName”)] used to set custom namespace.
·
[DataMember(Name=”name”, Order= 1)] used to set custom name and order of the member.
·
WCF service generally accepts and returns base type, if we want to accept and return
inherited types then we use [KnownType(typeof(DerivedClassName))] attribute on top
of [DataContrtact]. E.g. Employee, PartTime, FullTime then use [KnownType(typeof(PartTime))] on
Employee class
·
If we use KnownType
attribute on DataContract i.e. base class then we will get access of those
derived classes everywhere where we are using the base class. For more granularity we can use [ServiceKnownType(typeof(derivedClass))]
with ServiceContract or OperationContract. If we use it with ServiceContract
then we will get access of those KnownTypes in that Service only. If we use it
with OperationContract then we will get access of those KnownTypes in that
Operation only. We can define KnownTypes in configuration file also, it will
work same as declaring knownType on DataContract
·
To enable message logging and tracing: right
click on configuration file and click on Service
Configuration Editor (also get in Tools), in editor, select Diagnostics, and click on Enable Auto Flush, Enable Message Logging and Enable
Tracing. It creates two log files i.e. web_messages.svclog
and web_tracelog.svclog in root
folder. Then under Diagnostics select Message
Logging, and set Log Entire Message
to True. Open these log files to see logs in MS
Service Trace Viewer
·
DataContract
gives us limited control over SOAP
message like we can set name and/or order of the elements. On the other
hand MessageContract gives us full control over SOAP message using MessageHeader and MessageBodyMember
·
In general we use MessageContract if we want to modify
the structure of the SOAP XML message or wants to add some additional
information (like User Credentials) in header section
·
Apply [MessageContract]
attribute to make a class Message Contract. Apply [MessageHeader] attribute on property that you want to include in
SOAP Header. Apply [MessageBodyMember]
on property that you want to include in the SOAP body section.
·
WCF uses IExtensibleDataObject
to preserve unknown elements. If any unknown elements of data within the XML is
received at the service side then those unknown elements can be stored in ExtensionData property of type ExtensionDataObject from interface IExtensibleDataObject
·
The downside
of using IExtensibleDataObject is the risk
of Denial of Service [DOS] attack. The attacker might flood the server with
the requests containing large amount of unknown elements which can lead to
system out of memory and DOS. To avoid this, we need to remove implementation of IExtensibleDataObject but this will not
work if we have large amount of data contracts. We can enable/ disable
IExtensibleDataObject using Service
Behavior configuration
<behaviors>
<serviceBehaviors>
<behavior name=”ignoreExtensionData”>
<dataContractSerializer
ignoreExtensionDataObject=”true”
/>
</behavior>
</serviceBehaviors>
</behaviors>
·
We can enable/ disable IExtensibleDataObject by
using ServiceBehavior attribute on
Service Contract like: [ServiceBehavior(IgnoreExtensionDataObject = true)]
·
Whenever exception occurs in WCF service, the
exceptions are serialized in to SOAP fault before returned to the client. By
default exception details are not included in SOAP Fault
·
For debugging purpose if we want to add exception details in SOAP fault/ result
then we need to enable includeExceptionDetailInFaults
setting in configuration as below:
<behaviors>
<serviceBehaviors>
<behavior name=”behaviorName”>
<serviceDebug
includeExceptionDetailInFaults=”true” />
</behavior>
</serviceBehaviors>
</behaviors>
·
Same setting we can do in code using [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
·
An Unhandled
exception in WCF service will cause the communication channel to fault and the session will be lost. Once communication channel is in faulted
state, we cannot use the same instance of proxy class. BasicHttpBinding does not have sessions, so though an unhandled
exception faults the server channel, the client proxy is still ok because this
channel does not maintain any session. wsHttpBinding
have secure session, so when the unhandled exception occurs it torn downs
the communication channel and the session along with it. So once the channel is
in fault state, client will not be able to access the service using same
instance of proxy class.
·
To handle such unhandled exceptions we use FaultException instead of DOT Net
exceptions. DOT NET exceptions are
platform specific, these exception needs client of same technology i.e. DOT
NET. Though we use DOT NET exceptions to handle WCF service exceptions, those
exceptions are not handled by WCF so this causes the communication to be in
faulted stated. So to maintain interoperability and keep server session alive
(after exception also) we use FAULTEXCEPTION.
·
We can throw a generic SOAP fault using
FaultException class but instead of throwing generic fault we can create
strongly typed SOAP Fault with some additional details about exception and
throw them. We can throw strongly typed
fault by creating data contract for the fault with custom data as: throw new FaultException<DataContractForFault>(objFault);
·
In Asp.Net we use Application_Error() event to handle all exceptions. In WCF, to centralize
the exception handling, we implement IErrorHandler
interface. IErrorHandler provides us two methods bool HandleError(Exception), void
ProvideFault(Exception, MessageVersion, ref Message fault)
·
ProvideFault()
method gets called automatically when there is an any unhandled exception
or fault. We can convert unhandled error into generic fault here which can be
returned to client. HandleError() method
is gets called asynchronously after
ProvideFault() is executed and error message is returned to the client. Here we
can write code to log the error in database without blocking client call.
·
We need to add a Custom Service Behavior Attribute to let WCF know that we want to
use GlobalErrorHandler whenever unhandled exception occurs. We can add this custom
behavior by implementing an interface IServiceBahavior
and implementing ApplyDispatcherBehavior()
method. Then add [GlobalErroHandlerBehavior(typeof(ClassNameImplementedIErrorHandler))] attribute
on top of service.
·
We can host WCF service by following ways:
o
Self
Hosting: Using ServiceHost class
in Console Application or Windows Form Application
o
Windows
Service: Using ServiceHost class
in Windows Service Application
o
Internet Information
Services: Hosting within IIS (Supports only http bindings)
o
Windows
Activation Service: Hosting using IIS7 with WAS support (Supports all bindings)
·
Self
Hosting: Easy to setup, Easy to debug, Supports all bindings, easy to
control service lifetime using Open() and Close() functions. This requires Host
always running, custom code required to host
·
Windows
Service: Create Windows Service Application and add same code as in self
hosting in OnStart() and OnStop() handlers. Right Click in
service design and select Add Installer which
will add a installer.cs file with Service Installer and Process Installer. We can set Start Type (Manual/ Automatic) in
Service Installer and Account (i.e.
user/ local system) in Process Installer. Use installutil -i <path of Windows service exe> command in VS
command prompt to install service. We can see services using services.msc in run window.
·
Using Windows
Service hosting we can automatically start service when the system starts
without any user login, we can configure what should happen in case of service failure
(from Recovery tab of installed service), supports all binding. Need custom
code to host service, windows service needs to install on server, difficult to
debug (need to attach process of installed service)