netTcpRelayBinding WCF service hosted in Windows Service - Standard practices - wcf

I am writing netTcpRelayBinding WCF service hosted in Windows Service. I feel my code is naive due to lack of experience in windows service development. This get called from Windows-Azure. Could you please help me review the code, and how I can improvise it:-
we are using NLOG for logging.
My service throws exception (mentioned at end of question).
How should I :-
1. Define windows service dependency(Should it start before machine get
connected to internet).
2. How it should be more fault tolerance, how can it start after some time interval.
namespace XYC.Service.WinServiceHost
{
public partial class XYCService : ServiceBase
{
private ServiceHost serviceHost = null;
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public One23InsightService()
{
// Name the Windows Service
ServiceName = "XYCService ";
const string logName = "Application";
InitializeComponent();
if (!System.Diagnostics.EventLog.SourceExists(ServiceName))
{
System.Diagnostics.EventLog.CreateEventSource(ServiceName, logName);
}
EnLog.Source = ServiceName;
EnLog.Log = logName;
}
protected override void OnStart(string[] args)
{
if (serviceHost != null)
{
serviceHost.Close();
}
EnLog.WriteEntry(ServiceName + " Inside OnStart...");
try
{
serviceHost = new ServiceHost(typeof(InsightSrcDataService));
serviceHost.Faulted += HostFaulted;
serviceHost.UnknownMessageReceived += HostUnknownMessageReceived;
serviceHost.Open();
LogServiceInfo(serviceHost);
if (serviceHost.State != CommunicationState.Faulted)
{
EnLog.WriteEntry(ServiceName + " started successfully.");
EnLog.WriteEntry(ServiceName + " Automapping of entities are done successfully.");
}
}
catch (Exception ex)
{
string msg = ServiceName + " failed to start. Exception Message:-" + ex.Message + (ex.InnerException != null ? ex.InnerException.Message : string.Empty);
EnLog.WriteEntry(msg);
Logger.LogException(NLog.LogLevel.Error, msg, ex);
}
}
private void LogServiceInfo(ServiceHost host)
{
EnLog.WriteEntry(host.Description.ServiceType + "is up and running with these endpoints :");
foreach (ServiceEndpoint se in host.Description.Endpoints)
{
EnLog.WriteEntry(se.Address.ToString());
}
}
private void HostUnknownMessageReceived(object sender, UnknownMessageReceivedEventArgs e)
{
EnLog.WriteEntry(ServiceName + " Inside UnknownMessageReceived.");
}
private void HostFaulted(object sender, EventArgs e)
{
EnLog.WriteEntry(ServiceName + " - Host Faulted.");
}
protected override void OnStop()
{
if (serviceHost == null) return;
serviceHost.Close();
serviceHost = null;
}
}
}
Configuration
<system.serviceModel>
<services>
<service name="XYC.Service.WCFNetTCPContract.DataService">
<endpoint
name="SrcWeb"
address="sb://data.servicebus.windows.net/App/long-guid"
binding="netTcpRelayBinding"
contract="XYC.Service.Interface.IService"
bindingConfiguration="Hybrid"
behaviorConfiguration="sbTokenProvider" />
<endpoint
name="AdminServiceEndpoint"
address="sb://serviceaddress.servicebus.windows.net/Admin/long-guid"
binding="netTcpRelayBinding"
contract="One234C.Service.AdminInterface.IOne23AdminService"
bindingConfiguration="Hybrid"
behaviorConfiguration="sbTokenProvider" />
</service>
</services>
<bindings>
<netTcpRelayBinding>
<binding name="Hybrid" connectionMode="Hybrid" maxReceivedMessageSize="500000">
<security mode="None" />
</binding>
</netTcpRelayBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="False" httpsGetEnabled="False" />
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="False" />
</behavior>
</serviceBehaviors>
<endpointBehaviors>
<behavior name="sbTokenProvider">
<transportClientEndpointBehavior>
<tokenProvider>
<sharedSecret issuerName="owner" issuerSecret="xyc" />
</tokenProvider>
</transportClientEndpointBehavior>
</behavior>
</endpointBehaviors>
</behaviors>
<extensions>
</extensions>
</system.serviceModel>
This sometimes throw following exception (I guess it is lacking Windows service dependency, I want this service to start after machine get connected to internet & sql server service is started).
System.TimeoutException: The open operation did not complete within
the allotted timeout of 00:00:00. The time allotted to this
operation may have been a portion of a longer timeout. --->
System.TimeoutException: Open timed out after 00:00:00 while
establishing a transport session to
net.tcp://xxx.servicebus.windows.net:9351/Src/guid/. The time
allotted to this operation may have been a portion of a longer
timeout. ---> System.TimeoutException: Connecting to via
net.tcp://xxx.servicebus.windows.net:9351/Src/guid/ timed out after
00:00:00. Connection attempts were made to 0 of 1 available
addresses (). Check the RemoteAddress of your channel and verify
that the DNS records for this endpoint correspond to valid IP
Addresses. The time allotted to this operation may have been a
portion of a longer timeout. at
System.ServiceModel.Channels.SocketConnectionInitiator.CreateTimeoutException(Uri
uri, TimeSpan timeout, IPAddress[] addresses, Int32
invalidAddressCount, SocketException innerException) at
System.ArgumentException: issuerSecret is invalid. Parameter name:
issuerSecret at
Microsoft.ServiceBus.SharedSecretTokenProvider.DecodeSecret(String
issuerSecret) at
Microsoft.ServiceBus.SharedSecretTokenProvider..ctor(String
issuerName, String issuerSecret) at
Microsoft.ServiceBus.Configuration.TokenProviderElement.CreateTokenProvider()
at
Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement.CreateBehavior()
at
System.ServiceModel.Description.ConfigLoader.LoadBehaviors[T](ServiceModelExtensionCollectionElement1
behaviorElement, KeyedByTypeCollection1 behaviors, Boolean
commonBehaviors) at
System.ServiceModel.Description.ConfigLoader.LoadServiceDescription(ServiceHostBase
host, ServiceDescription description, ServiceElement serviceElement,
Action`1 addBaseAddress, Boolean skipHost) at
System.ServiceModel.ServiceHostBase.LoadConfigurationSectionInternal(ConfigLoader
configLoader, ServiceDescription description, ServiceElement
serviceSection) at
System.ServiceModel.ServiceHost.ApplyConfiguration() at
System.ServiceModel.ServiceHostBase.InitializeDescription(UriSchemeKeyedCollection
baseAddresses) at System.ServiceModel.ServiceHost..ctor(Type
serviceType, Uri[] baseAddresses) at
One234C.Service.WinServiceHost.One23InsightService.OnStart(String[]
args) issuerSecret is invalid.

Well the second error means that the issuer key for the namespace you are using is incorrect. You may need to check to make sure you are using the correct key.

Looks like a bug in implementation of the the NetTCPRelaybinding. I am having same issue as well. I relay section of the Servicebus, I can see the service being displayed but the relaytype is None.

Related

How to avoid cert validation on every service call with a WCF custom binding and a custom validator

I have a WCF servcie set up with custom binding and a custom cert validator.
THe cert validator is defined as follows. It will be expanded later, but is just doing a basic verification currently.
public class MyX509CertificateValidator : X509CertificateValidator
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(MyX509CertificateValidator));
public MyX509CertificateValidator()
{
Logger.Info("certval - Constructor ");
}
public override void Validate(X509Certificate2 certificate)
{
Logger.Info("certval - Validate(). Calling Cert.validate()");
bool verifyResult = certificate.Verify();
Logger.Info("verify result: " + verifyResult);
if (!verifyResult)
{
throw new SecurityTokenValidationException("cert had some bad juju");
}
}
}
My web.config is set up as follows. The goal is to use Transport security and use sessions. I want the cert to be validated once, when the session is being created. However, I can see through logging in the cert validator, that the validation takes place for every service call that a client makes, when using an existing open WCF client proxy.
I've verified that my WCF service instance is created once per session (logging in the constructor is being called once per session). But, the cert validator is being called every single service calls. How can I get the cert validator to be called only at the start of a session?
Given that it appears to be using sessions, I assumed that the cert verification would be sesssion-full, and invoked just once per session. I've perused the WCF configuration documentation on MSDN and do not see a way to further customize reliableSession tag, or anything related to Security to do what I wish.
Here's the web.config and the service definition
[ServiceBehavior(AutomaticSessionShutdown = true,
InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class WcfBasicService : IWcfBasicService
{
...
<system.serviceModel>
<bindings>
<customBinding>
<binding name="reliableSessionOverHttps">
<reliableSession/>
<security authenticationMode="CertificateOverTransport"/>
<httpsTransport />
</binding>
</customBinding>
</bindings>
<services>
<service name="WcfServiceLibrary1.WcfBasicService">
<endpoint address="" binding="customBinding" contract="WcfServiceLibrary1.IWcfBasicService" name="mainEndpoint"
bindingConfiguration="reliableSessionOverHttps">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="Custom" customCertificateValidatorType="WcfServiceLibrary1.MyX509CertificateValidator, WcfServiceLibrary1" />
</clientCertificate>
</serviceCredentials>
<!-- To avoid disclosing metadata information,
set the values below to false before deployment -->
<serviceMetadata httpGetEnabled="True" httpsGetEnabled="True" />
<!-- To receive exception details in faults for debugging purposes,
set the value below to true. Set to false before deployment
to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
AFAIK there is no any good WCF configuration solution for that, but you may implement some sort of cache inside Validate method, using Thumbprint property of the certificate (Thumbprint is actually hash of the certificate body):
public class MyX509CertificateValidator : X509CertificateValidator
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(MyX509CertificateValidator));
private string lastValidCertTumbprint = null;
public MyX509CertificateValidator()
{
Logger.Info("certval - Constructor ");
}
public override void Validate(X509Certificate2 certificate)
{
if ((lastValidCertTumbprint != null) && (certificate.Tumbprint == lastValidCertTumbprint))
{
return; // Fast track
}
Logger.Info("certval - Validate(). Calling Cert.validate()");
bool verifyResult = certificate.Verify();
Logger.Info("verify result: " + verifyResult);
if (!verifyResult)
{
throw new SecurityTokenValidationException("cert had some bad juju");
}
// The cert valid, save this fact into fast track cache
lastValidCertTumbprint = certificate.Tumbprint;
}
}
I assume that session duration is far less then certificate lifetime and in case certificate(s) revoked, you have other means to terminate the sessions :)
To made things better, you may add some sort of timestamp of the last validation call and re-validate certificate if reasonable timeout (say, 30min) expired:
public class MyX509CertificateValidator : X509CertificateValidator
{
private static readonly ILog Logger = LogManager.GetLogger(typeof(MyX509CertificateValidator));
private string lastValidCertTumbprint = null;
private Stopwatch lastValidCertTimeMarker = new Stopwatch();
private const int VALIDATION_CACHE_LIFETIME = 30*60*1000; // in ms // 30min
public MyX509CertificateValidator()
{
Logger.Info("certval - Constructor ");
}
public override void Validate(X509Certificate2 certificate)
{
if ((lastValidCertTumbprint != null)
&& (certificate.Tumbprint == lastValidCertTumbprint)
&& (lastValidCertTimeMarker.ElapsedMilliseconds < VALIDATION_CACHE_LIFETIME))
{
return; // Fast track
}
lastValidCertTumbprint = null;
Logger.Info("certval - Validate(). Calling Cert.validate()");
bool verifyResult = certificate.Verify();
Logger.Info("verify result: " + verifyResult);
if (!verifyResult)
{
throw new SecurityTokenValidationException("cert had some bad juju");
}
// The cert valid, save this fact into fast track cache and save timestamp
lastValidCertTumbprint = certificate.Tumbprint;
lastValidCertTimeMarker.Reset();
lastValidCertTimeMarker.Start();
}
}

wcf CustomWebHttpBehavior works only on the first endpoint

I have a wcf (.net 4.5) with one service and multiple interfaces\end points.
This service is declared as follows:
<service name="MyService.Service1">
<endpoint address="Try1" behaviorConfiguration="restfulBehvaiour"
binding="webHttpBinding" contract="MyService.IService1" />
<endpoint address="Try2" behaviorConfiguration="restfulBehvaiour"
binding="webHttpBinding" contract="MyService.ITry" />
</service>
...
<behavior name="restfulBehvaiour">
<webHttp helpEnabled="true" />
</behavior>
I am trying to return any exception as json. I have followd the tutorial on http://zamd.net/2008/07/08/error-handling-with-webhttpbinding-for-ajaxjson/
In short:
1) On the svc file, added this (it implements both interfaces)
<%# ServiceHost Language="C#" Debug="true" Service="MyService.Service1" CodeBehind="Service1.svc.cs" Factory="MyService.CustomWebServiceHostFactory"%>
2) where CustomWebServiceHostFactory is
public class CustomWebServiceHostFactory : System.ServiceModel.Activation.WebServiceHostFactory
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var sh = new ServiceHost(typeof(Service1), baseAddresses);
sh.Description.Endpoints[0].Behaviors.Add(new CustomWebHttpBehavior());
return sh;
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return base.CreateServiceHost(serviceType, baseAddresses);
}
3) and the custom CustomWebHttpHandler is
protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// clear default error handlers.
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Clear();
// add our own error handler.
endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(new ErrorHandlerEx());
}
4) and the ErrorHandlerEx is some class that handles the exceptions (returns json object).
this all work great for the first end point (Try1), but the second one (Try2) is being ignored and not going threw the CustomWebServiceHostFactry.
If I switch the order of the endpoints in web.config, the first one always works and the seconds exceptions are being handled by the default wcf handlers.
How can I fix this behaviour, so that every end point will work as the above tutorial suggests?
You only implement the behavior on one endpoint (the first one) in your custom service host.
sh.Description.Endpoints[0].Behaviors.Add(new CustomWebHttpBehavior());
Endpoints[0] is the first endpoint in the collection. You need to add it to both (or all if you have more than 2) endpoints for the service. I recommend a foreach loop:
foreach (ServiceEndpoint endpoint in sh.Description.Endpoints)
{
endpoint.Behaviors.Add(new CustomWebHttpBehavior());
}
This should resolve the issue of the behavior only being applied to the first endpoint.

WCF Exception : ServiceHost only supports class service types -- when run from windows service

i am new in wcf. i am facing this error ServiceHost only supports class service types.
here i will say i am doing & running my win service & wcf together.
i added windows service project and also add few reference like System.ServiceModel for wcf in win service project. when i am trying to run wcf service from win service then i am getting error called ServiceHost only supports class service types
i search & got many answer like
ServiceHost host = new ServiceHost(
typeof(subservice.ISubService), new Uri("someuri"));
If this is your usage, change it to use the implemented service class type of ISubService
ServiceHost host = new ServiceHost(
typeof(subservice.SubService), new Uri("someuri"));
If configuring the service in .svc then:
<%#ServiceHost Service="subservice.SubService"%>
Also in you config file, change service name to the service instead of the service contract as:
<services>
<service name="subservice.SubService">
...
other search result also said very similar things to get rid of this problem.
i have no svc file for my wcf service. i have just one file where i have contract and service classes. i also have config file.
here i am giving the brief of my service code
namespace SageDataImportWCF
{
[ServiceContract]
public interface ISagePart
{
[OperationContract]
string SageInsertionProcess(string SQLConnectionString, string CountryCode);
// TODO: Add your service operations here
}
public class SagePartInsertion : ISagePart
{
public string SageInsertionProcess(string SQLConnectionString, string CountryCode)
{
}
}
}
here i am giving the code by which i am trying to run from win service
namespace SageDataImportWCF
{
public partial class SageDateInsertionService : ServiceBase
{
#region Local Variables
ServiceHost serviceHost;
#endregion
#region Constructor
public SageDateInsertionService()
{
InitializeComponent();
serviceHost = null;
ServiceName = "Sage DataInsertion Service";
}
#endregion
protected override void OnStart(string[] args)
{
string strAdrHTTP = "http://192.168.6.2:11000/SagePartInsertion";
if (serviceHost != null)
{
serviceHost.Close();
}
serviceHost = new ServiceHost(typeof(SageDataImportWCF.SagePartInsertion));
serviceHost.AddServiceEndpoint(typeof(SageDataImportWCF.ISagePart), new BasicHttpBinding(), strAdrHTTP);
ServiceMetadataBehavior behaviour = new ServiceMetadataBehavior();
behaviour.HttpGetEnabled = true;
serviceHost.Description.Behaviors.Add(behaviour);
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null)
{
serviceHost.Close();
serviceHost = null;
}
}
}
}
here is my config entry for wcf service
<configuration>
<system.serviceModel>
<services>
<service name="SageDataImportWCF.SagePartInsertion" behaviorConfiguration="SageBehavior">
<endpoint address="http://localhost:9001/SagePartInsertion" contract="SageDataImportWCF.ISagePart" binding="basicHttpBinding"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="SageBehavior">
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
here i have pasted all the relevant code and i like to request some one please have a look at my code and tell me why i am getting the error message like ServiceHost only supports class service types when try to run it from windows service. did i miss anything in code ?
should i have a separate project for wcf class library and another separate project for windows service because i have one project there i have files for wcf & windows service both.
so looking for suggestion like what i need to rectify in code as a result win service can start the wcf service. please help.
Check the definition of the service in the Markup:
Right click on the SagePartInsertion.svc file and select "View Markup".
Make sure the service is the implementation of the interface, like this:
<%# ServiceHost Language="C#" Debug="true" Service="SageDataImportWCF.SagePartInsertion" CodeBehind="SagePartInsertion.svc.cs" %>
In the past it failed because I was referencing the interface.

Pass login information with each WCF Webservice call?

Hi,
I have set a WCF up as a webservice(percall), this webservice will getting request from a wide range of systems. Now we need somekind of way to identify the client.
Its possible to build a CustomUserNamePasswordValidation but this demands a secured(SLL) communication. In our case we do not need the security and the solution needs to be as easy as possible to setup.
So the question is how to send client identifikation(username/password) on each call?
I could place the identifikation data in the header but Im not sure how this can be tested with example soupUI? And Im not sure if all systems that will be communicate can handle this without complications?
Any sugestions?
Please note: I do only want to do 1 call, so no login service method should have to be used.
WCF do not suport sending user credentials unsecured. To solve this you could use the clear username binding or adding the credentials manually in the heador of the message(this is simple with WCF)
Define a binding in the web.config like :
<basicHttpBinding>
<binding name="BasicAuthBinding">
<security mode="Message">
<message clientCredentialType="UserName"/>
</security>
</binding>
</basicHttpBinding>
Then define a service behaviour like :
<behavior name="Namespace.TestBehaviour">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="Namespace.ServiceSecurity.UserAuthenticator, Namespace" />
</serviceCredentials>
<serviceAuthorization>
<authorizationPolicies>
<add policyType="Namespace.ServiceSecurity.MyAuthorizationPolicy, Namespace" />
</authorizationPolicies>
</serviceAuthorization>
</behavior>
Then provide the custom authentication and authorization classes as follows :
public class MyAuthorizationPolicy: IAuthorizationPolicy
{
public bool Evaluate(EvaluationContext evaluationContext, ref object state)
{
IList<IIdentity> identities = (IList<IIdentity>) evaluationContext.Properties["Identities"];
foreach (IIdentity identity in identities)
{
if (identity.IsAuthenticated &&
identity.AuthenticationType == "UserAuthenticator")
{
evaluationContext.Properties["Principal"] = identity.Name;
return true;
}
}
if (!evaluationContext.Properties.ContainsKey("Principal"))
{
evaluationContext.Properties["Principal"] = "";
}
return false;
}
public ClaimSet Issuer
{
get { throw new NotImplementedException(); }
}
}
authentication as follows :
public class UserAuthenticator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//authenticate me however you want
//then set whatever you want
}
}
If you need further security, change basicHttpBinding to a wsHttpBinding and use a certificate
EDIT : Almost forgot, use the defined service behaviour and binding in your service interface definition in web.config.
In the code :
public class WCF_Project_Authentification : UserNamePasswordValidator
{
#region UserNamePasswordValidator Interface Member
public override void Validate(string userName, string password)
{
if (userName != "Jeanc" || password != "fortin")
{
throw new FaultException("Authentification failed");
}
}
#endregion
}
In the config :
<behaviors>
<serviceBehaviors>
<behavior name="Service_Behavior">
<serviceMetadata httpGetEnabled="False" httpsGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True"/>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WcfService.Authentification.WCF_Project_Authentification, WcfService"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
And in the client code :
proxy.ClientCredentials.UserName.UserName = "Jeanc";
proxy.ClientCredentials.UserName.Password = "fortin";

Easy way to startup NHibernate in a WCF project

I'd like to use an NHibernate startup module for my WCF project like the one I use for my ASP.NET MVC projects. Jeffery Palermo outlines the startup module that I use in his post ASP.NET MVC HttpModule Registration. Essentially the code boils down to adding a startup module in the web.config that looks like this:
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="StartupModule" type="Infrastructure.NHibernateModule, Infrastructure, Version=1.0.0.0, Culture=neutral" />
</modules>
</system.webServer>
This is not working when I try to run the service with the WCF Test Client or directly against the endpoint with SoapUI. What are my options for a simple startup mechanism for NHibernate in a WCF project?
You can resolve the issue by using a Message Inspector. On your NHibernateModule implement IDispatchMessageInspector. This will allow you to open your NHibernate session as each request is received and close it right before your reply is sent out.
Palermo's demo indicates that you will have extended IHttpModule. If that is the case, you will add two methods for the IDispatchMessageInspector interface:
public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext)
{
context_BeginRequest(null, null);
return null;
}
and
public void BeforeSendReply(ref Message reply, object correlationState)
{
context_EndRequest(null, null);
}
This will implement the new interface using your old code. You will also need to implement the IServiceBehavior interface. This will allow you to use the module on a behavior extension in your web.config. The IServiceBehavior requires three methods, only one will actually do anything:
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
foreach (EndpointDispatcher ed in cd.Endpoints)
{
ed.DispatchRuntime.MessageInspectors.Add(this);
}
}
}
This will add your new inspector to each of the endpoints.
You will then have to add a BehaviorExtensionElement. This BehaviorExtensionElement should return the type and a new instance of your NHibernateModule. This will allow you to create a new behavior that returns the NHibernateModule in your web.config.
public class NHibernateWcfBehaviorExtension : BehaviorExtensionElement
{
public override Type BehaviorType
{
get { return typeof(NHibernateModule); }
}
protected override object CreateBehavior()
{
return new NHibernateModule();
}
}
Now you have all the pieces in order, you can use them in your web.config. To apply them to all services your web.config should look like the following.
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="true"/>
<NHibernateSessionStarter />
</behavior>
</serviceBehaviors>
</behaviors>
<extensions>
<behaviorExtensions>
<add name="NHibernateSessionStarter" type="Infrastructure.NHibernateWcfBehaviorExtension, Infrastructure, Version=1.0.0.0, Culture=neutral" />
</behaviorExtensions>
</extensions>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
</system.serviceModel>