Does using a custom ServiceHost disable simplified configuration? - wcf

I have some one-time initialization tasks to do on service startup, and in order to do this I have defined a custom ServiceHostFactory and ServiceHost to override InitializeRuntime.
Service1.svc markup:
<%# ServiceHost Language="C#" Debug="true" Factory="service.Our_Service_Host_Factory" Service="service.Service1" CodeBehind="Service1.svc.cs" %>
Service Host definitions:
public class Our_Service_Host_Factory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new Our_Service_Host(serviceType, baseAddresses);
}
}
class Our_Service_Host : ServiceHost
{
public Our_Service_Host(Type serviceType, Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
protected override void InitializeRuntime()
{
// one time setup code
}
}
Snippet from web.config:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>
If I remove the Factory attribute on the ServiceHost markup, the WCF Test Client can successfully connect to my service. If I put it back in, it can't find the metadata endpoint with the following error:
Error: Cannot obtain Metadata from http://localhost:50154/Service1.svc If this is a Windows (R)
Communication Foundation service to which you have access, please check that you have enabled
metadata publishing at the specified address. For help enabling metadata publishing, please
refer to the MSDN documentation at http://go.microsoft.com/fwlink/?LinkId=65455.WS-Metadata
Exchange Error URI: http://localhost:50154/Service1.svc Metadata contains a reference that
cannot be resolved: 'http://localhost:50154/Service1.svc'. There was no endpoint listening at
http://localhost:50154/Service1.svc that could accept the message. This is often caused by an
incorrect address or SOAP action. See InnerException, if present, for more details. The
remote server returned an error: (404) Not Found.HTTP GET Error URI:
http://localhost:50154/Service1.svc There was an error
downloading 'http://localhost:50154/Service1.svc'. The request failed with HTTP status 404:
Not Found.
It looks like having a custom ServiceHost/ServiceHostFactory might break simplified configuration. Is this the case, or is there something I'm overlooking which would make this continue to work?

If you override InitializeRuntime(), make sure you call base.InitializeRuntime() or you may see this behavior. After calling base.InitializeRuntime() before calling my additional startup logic, my service is now being correctly routed to.

Related

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.

How do I set bindingNamespace when using fileless activation?

I'm attempting to eliminate tempuri.org from my WCF service, hosted in IIS using fileless activation. I've followed the instructions here, and I'm stuck when it comes to the bindingNamespace attribute in Web.config, because I'm using fileless activation.
My Web.config merely contains:
<serviceActivations>
<add relativeAddress="Foo.svc"
service="BigCorp.Services.Foo, BigCorp.Services"
/>
</serviceActivations>
I therefore don't have an <endpoint> node on which to set bindingNamespace.
What to do?
You can still use the <services> and hence <endpoint> nodes with WCF File-less activation. Take a look at the following example, where I even modify the default wsHttpBinding to add transport security and enable default behaviors as well; all for the file-less activation of the "Module1.DES.ExternalDataService" service.
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding messageEncoding="Mtom">
<security mode="Transport"/>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="Module1.DES.ExternalDataService">
<endpoint binding="wsHttpBinding" bindingNamespace="" contract="Module1.DES.IExternalDataService"/>
</service>
</services>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true">
<serviceActivations>
<add relativeAddress="ExternalDataService.svc" service="Module1.DES.ExternalDataService"/>
</serviceActivations>
</serviceHostingEnvironment>
</system.serviceModel>
Hope this helps.
To change the binding namespace you can use a custom factory (instead of the default one provided) where you can change all the properties of the binding:
<serviceActivations>
<add relativeAddress="Foo.svc"
service="BigCorp.Services.Foo, BigCorp.Services"
factory="BigCorp.Services.FooHostFactory, BigCorp.Services"/>
</serviceActivations>
And the factory:
public class FooHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new FooServiceHost(serviceType, baseAddresses);
}
}
public class FooServiceHost : ServiceHost
{
public FooServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
protected override void OnOpening()
{
base.OnOpening();
foreach (ServiceEndpoint endpoint in host.Description.Endpoints)
{
if (!endpoint.IsSystemEndpoint)
{
endpoint.Binding.Namespace = "http://services.bigcorp.com/foo";
}
}
}
}
In your service code, you specify:
[ServiceContract(Namespace="http://your-url")]
public interface IMyInterface { ... }
and you can also specify it for data contracts:
[DataContract(Namespace="http://your-url/data")]
public class MyData { ... }
Besides the obvious change of service/data contract namespaces, you can also set a namespace on the Binding object itself, as well as a namespace on the service description:
Binding binding = new BasicHttpBinding();
binding.Namespace = "urn:binding_ns";
ServiceHost host = new ServiceHost(typeof(MyService), address);
var endpoint = host.AddServiceEndpoint(typeof(IMyService), binding, "");
host.Description.Namespace = "urn:desc_ns";
The latter one is what controls the targetNamespace of the WSDL document itself.
In the end, I used a custom BindingNamespaceAttribute, derived from this example.
If you are using the fileless service activation feature of WCF 4.0 via the serviceActivations config element, then you can override the AddDefaultEndpoints base method in your ServiceHost implementation.
using System;
using System.ServiceModel;
using System.ServiceModel.Description;
namespace MyApp.WS.WCFServiceHost
{
public class MyHostFactory : ServiceHostFactory
{
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return new EDOServiceHost(serviceType, baseAddresses);
}
}
public class MyServiceHost : ServiceHost
{
public EDOServiceHost(Type serviceType, params Uri[] baseAddresses)
: base(serviceType, baseAddresses) { }
public override System.Collections.ObjectModel.ReadOnlyCollection<ServiceEndpoint> AddDefaultEndpoints()
{
var endpoints = base.AddDefaultEndpoints();
foreach (ServiceEndpoint endpoint in endpoints)
{
if (!endpoint.IsSystemEndpoint)
{
endpoint.Binding.Namespace = NamespaceConstants.MyNamespace;
}
}
return endpoints;
}
}
}
Or you could just use config only, the only down side to that is you violate the DRY principle slightly since you now have two points to maintain the namespace string, one in your constants and one in the config file.
In the following example im using the WCFExtrasPlus behaviour to 'flatten' the WSDL. You don't need this if your deploying to a .net 4.5 IIS7 server as you will have access to a flat WSDL anyway which is a new feature built into the 4.5 framework, I digress.
The example also assumes two service contracts and two service behaviour implementations of those contracts.
<system.serviceModel>
<services>
<service name ="MyApp.WS.ServiceBehaviour.Enquiries">
<endpoint bindingNamespace="MyApp.WS" binding="basicHttpBinding" contract="MyApp.WS.ServiceContract.IEnquiries" />
</service>
<service name ="MyApp.WS.ServiceBehaviour.CallLogging">
<endpoint bindingNamespace="MyApp.WS" binding="basicHttpBinding" contract="MyApp.WS.ServiceContract.ICallLogging" />
</service>
</services>
<serviceHostingEnvironment>
<serviceActivations>
<add relativeAddress="Enquiries.svc"
service="MyApp.WS.ServiceBehaviour.Enquiries"
/>
<add relativeAddress="CallLogging.svc"
service="MyApp.WS.ServiceBehaviour.CallLogging"
/>
</serviceActivations>
</serviceHostingEnvironment>
<extensions>
<behaviorExtensions> <!-- The namespace on the service behaviour, the service contract, the data contract and the binding must all be set to the same.-->
<add name="wsdlExtensions" type="WCFExtrasPlus.Wsdl.WsdlExtensionsConfig, WCFExtrasPlus, Version=2.3.1.8201, Culture=neutral, PublicKeyToken=f8633fc5451b43fc" />
</behaviorExtensions>
</extensions>
<behaviors>
<endpointBehaviors>
<behavior>
<wsdlExtensions singleFile="true" />
</behavior>
</endpointBehaviors>
<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"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
For reference the service contracts;
[ServiceBehavior(Namespace = NamespaceConstants.MyNamespace)]
public class CallLogging : ICallLogging
{
}
[ServiceBehavior(Namespace = NamespaceConstants.MyNamespace)]
public class Enquiries : IEnquiries
{
}
NB: A namespace does not need http:// in its name. It can be the namespace of your project if you like i.e. MyApp.MyProject.Somthing . See URN

WCF - how to set "enableWebScript" dynamically?

I'm working on my first WCF service, which will support several Ajax calls. I have an endpoint configured this way:
<service behaviorConfiguration="ServiceBehavior" name="AQM">
<endpoint address="" behaviorConfiguration="web" binding="webHttpBinding" bindingConfiguration="Binding1" contract="IAQM" />
</service>
and my behavior configuration:
<endpointBehaviors>
<behavior name="web">
<webHttp />
<enableWebScript />
</behavior>
</endpointBehaviors>
I need to create my own error handling so that I can format some specific information back to the client (see here http://zamd.net/2008/07/08/error-handling-with-webhttpbinding-for-ajaxjson/). My WebServiceHostFactory looks like this:
public class MyServiceFactory : WebServiceHostFactory
{
public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
{
var sh = new ServiceHost(typeof(AQM), baseAddresses);
sh.Description.Endpoints[0].Behaviors.Add(new WebHttpBehaviorEx());
return sh;
}
protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
{
return base.CreateServiceHost(serviceType, baseAddresses);
}
}
public class WebHttpBehaviorEx : WebHttpBehavior
{
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());
}
However, after I created my own error handler, it seems it overrides the "enableWebScript" setting I had in my config above, which I think makes sense because now I'm creating my very own behavior dynamically which doesn't have any of the config settings above.
I read that this setting should be used with WCF/Ajax for security purposes (see here http://www.asp.net/ajaxlibrary/Using%20JSON%20Syntax%20with%20Ajax.ashx). So my question is, how can I set the the "enableWebScript" setting on my dynamically created behavior? Or is it not possible?
Update (6/1/2011): I'm also looking to dynamically change the behavior to use Windows credentials for authentication. In the config file it's done like this:
<bindings>
<webHttpBinding>
<binding name="Binding1">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="Windows" />
</security>
</binding>
</webHttpBinding>
</bindings>
This is another setting I need to make programmatically since it seems to ignore the config setting.
For me it worked after adding the following constructor in WebHttpBehaviorEx
public WebHttpBehaviorEx()
{
DefaultBodyStyle = WebMessageBodyStyle.Wrapped;
DefaultOutgoingRequestFormat = WebMessageFormat.Json;
DefaultOutgoingResponseFormat = WebMessageFormat.Json;
}
There is a class WebScriptEnablingBehavior that you should be able to create in instance of programmatically and add it to the Behaviors collection of your endpoint. I've never tried it, and don't know how exactly that would work having multiple behaviors defined on a single endpoint, but I think that's basically what you're doing in your declarative configuration. Unfortunately WebScriptEnablingBehavior (which inherits from WebHttpBehavior) is sealed, so you can't just inherit from it.
Update: (from here)
The WebScriptEnablingBehavior is a "profile" of the WebHttpBehavior functionality designed specifically for interop with ASP.NET AJAX clients. It adds in some AJAX-isms like the ability to automatically generate ASP.NET AJAX client proxies.
I'm not sure you actually need to use <enableWebScript/>, like Carlos said, it sounds like it's only needed when you're using ASP.NET AJAX.

WCF, MVC2, obtaining access to auto generated WSDL and working through default endpoint not found issues

I’m trying to run a very basic web service on the same IIS7 website that runs a MVC2 application. This is presenting a couple of different issues, and I believe it has to do with my system.serviceModel, but obviously I don’t know for sure (or I would fix it).
On the server side I can run my service just fine, the help operation works like a charm. I can execute the default WCF operation GetData and supply a value through the FireFox address bar.
http://localhost/services/service1/getdata?value=3 (example)
The first problem I’m having is that when I navigate to the base service URI it will display the message below. While this isn’t the end of the world because I can still execute code by manipulating the address; I do expect something else to be displayed. I expect the standard new web service message explaining that by appending “?wsdl” to the address you will receive the auto generated WSDL. I cannot access my auto generated WSDL.
“Endpoint not found. Please see the
service help page for constructing
valid requests to the service.”
Problem number two is in regard to client applications connecting to my web service. I created a console application in separate Visual Studio solution and added a web service reference to Service1. In the Visual Studio tool I can see and use the two methods that exist in my service, but when I run the code I get the following exception.
InvalidOperationException Could not
find default endpoint element that
references contract
'ServiceReference1.IService1' in the
ServiceModel client configuration
section. This might be because no
configuration file was found for your
application, or because no endpoint
element matching this contract could
be found in the client element.
Before I post my code (I’m sure readers are tired of reading about my struggles) I do want to mention that I’ve been able to run a WCF Service Library and Console application in the same solution flawlessly. There seems to be very few resources explaining WCF, WCF configuration, and working with MVC. I’ve read through several articles and either they were out-of-date or they were so simplistic they were nearly useless (e.g. click button receive web service named “Service1”).
To summarize; why am I not able to access the auto generated WSDL and how can I successfully connect my client and use the web service? Now the best part; the code.
Global.asax
//Services section
routes.Add(new ServiceRoute("services/service1", new WebServiceHostFactory(), typeof(Service1)));
Web.Config
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
<standardEndpoints>
<webHttpEndpoint>
<standardEndpoint name="DefaultEndpoint" helpEnabled="true" automaticFormatSelectionEnabled="true" />
</webHttpEndpoint>
<mexEndpoint />
</standardEndpoints>
<services>
<service name="Project.Services.Service1" behaviorConfiguration="MetadataBehavior">
<!-- Service Endpoints -->
<!-- Unless fully qualified, address is relative to base address supplied above -->
<endpoint endpointConfiguration="DefaultEndpoint" kind="webHttpEndpoint" binding="webHttpBinding" contract="Project.Services.IService1" />
<!-- Metadata Endpoints -->
<!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. -->
<!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MetadataBehavior">
<!-- To avoid disclosing metadata information,
set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="false" /> <!-- httpGetEnabled="true" does not solve the problem either -->
<!-- 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>
IService1
[ServiceContract]
public interface IService1
{
[OperationContract]
[WebInvoke(Method = "GET")]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
// TODO: Add your service operations here
}
Service1
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
{
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
Client Program
class Program
{
static void Main(string[] args) {
Service1Client client = new Service1Client();
client.GetData(2);
}
}
Thanks for the help! The problem was inside of my Global.asax.cs.
Original:
routes.Add(new ServiceRoute("services/service1", new WebServiceHostFactory(), typeof(Service1)));
New:
routes.Add(new ServiceRoute("services/service1", new ServiceHostFactory(), typeof(Service1)));
The difference was chaing the host factory from "WebServiceHostFactory" to "ServiceHostFactory".
The second part of my question regarding client connections is because configuration settings are not being generated. I have to manually type them for each client. Yikes!
To avoid manually typing client configuration I had to change my endpoint
Original
<endpoint endpointConfiguration="DefaultEndpoint" kind="webHttpEndpoint" binding="webHttpBinding" contract="Project.Services.IService1" />
New
<endpoint binding="wsHttpBinding" contract="Project.Services.IService1" />
After making this change the service and client are working flawlessly.
A quick answer to one of your questions:
To summarize; why am I not able to
access the auto generated WSDL
<serviceMetadata httpGetEnabled="false" />
...needs to be
<serviceMetadata httpGetEnabled="true" />
...in order to be able to retrieve the WSDL over http. You have to tell WCF to generate service metadata, and you've told it not to.

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>