I'm trying to have Castle (3.0) inject constructor params into a WCF service, like this
ServiceHostBase clientServiceHost = new Castle.Facilities.WcfIntegration.DefaultServiceHostFactory()
.CreateServiceHost(typeof(IClientExchange).AssemblyQualifiedName, new Uri[0]);
However I get the following exception 'The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor.'
The service impl of type ClientExchange takes a constructor param of type IProviders
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public class ClientExchangeService : ExchangeService, IClientExchange
{
public ClientExchangeService(IProviders providers)
: base(providers) { }
}
My windsor installer looks like this:
container.AddFacility<WcfFacility>()
.Register
(
Component.For<IProviders>().Instance(Providers.DbInstance),
Component.For<IClientExchange>().ImplementedBy<ClientExchangeService>(),
);
At the moment it seems like WCF is trying to new up the service without castle providing the dependency. Tried a few alternative examples out there but many are for previous versions of castle pre 3.0. I must be missing a hook somewhere? How do I tell WCF to defer construction responsibility to castle?
I think this: how do i pass values to the constructor on my wcf service might be the answer to your problem. Or, for something more Windsor specific this might help: Dependency Injection in WCF Using Castle Windsor.
UPDATE
OK, so I think I have figured this out. First of all the problem is this attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
If you do not specify that Windsor will be able to inject the dependencies into the constructor perfectly fine - with that it cannot.
From looking at the description of that attribute here I see that you want your service to be a singleton so since that is the default for Windsor you can simply remove that attribute and it should start working for you and behave as you expect.
There are two other lifestyles that you may be interested in that are specifically for WCF:
LifestylePerWcfOperation()
LifestylePerWcfSession()
(specify them in the normal place - more information is available here)
Incidentally, you do not have to do the ServiceHostBase stuff at all, instead you can use the AsWcfService extension method like so (personally I prefer this way of doing it):
container
.AddFacility<WcfFacility>(f => f.CloseTimeout = TimeSpan.Zero)
.Register(
Component
.For<IProviders>()
.Instance(Providers.DbInstance),
Component
.For<IClientExchange>()
.ImplementedBy<ClientExchangeService>()
.AsWcfService(new DefaultServiceModel()
.AddEndpoints(WcfEndpoint
.BoundTo(new BasicHttpBinding())
.At("http://localhost:8000/ClientExchangeService"))));
Related
In my WCF project I register my interface using Castle Windsor in the global.asax:
Component.For<IStrategy>()
.ImplementedBy<MyStrategy>()
.LifestylePerWcfOperation(),
Then later on in the same file I configure NHibernate using FluentNhibernate using a provider:
FluentConfiguration configuration = Fluently.Configure()
.Database(
MsSqlConfiguration.MsSql2008.ConnectionString(myConnString)
.Provider<ConnectionProvider>())
.Mappings(m => m.FluentMappings.AddFromAssemblyOf<TenantMap>()) etc etc
However this ConnectionProvider is hosted in a common shared dll library as there are other WCF services that need to use it. I want to register this dependency as below but it doesn't work which means I have to manually new up a instance.
public ConnectionProvider()
{
// doesnt work
using (IDependencyScope scope = GlobalConfiguration.Configuration.DependencyResolver.BeginScope())
{
_myStrategy = scope.GetService<IStrategy>();
}
}
Is there anyway to make this work? Its like its lost scope as its in another assembly now. In the same assembly the DependencyScope works fine and creates an instance, but I want to keep it in a shared dll.
EDIT: The error I get is "System.Web.Http.Dependencies.EmptyResolver" on a watch on this bit of code: GlobalConfiguration.Configuration.DependencyResolver
I can see several problems with the code above:
1) You are registering IStrategy,MyStrategy with a per WcfOperation lifestyle. This means that windsor will create a strategy for each WcfOperation. On the otherhand you are trying to manually set the lifestyle of the component by using scope.GetService. For scope.GetService to work you will need a lifestyle scoped.
2) Assuming that the code for ConnectionProvider above is the constructor, it seems that the constructor is trying to get something from the container. This is in general a bad idea, and even worse when using an Ioc container like windsor. Instead pass the IStrategy to the constructor (inject it).
3) Seeing that you are calling the container a constructor here, probably means that you are not adhering to the principle that there should be only 3 calls to the container, 1 to register component, 1 to retrieve a top level component, and 1 to release the container.
I suggest you read a bit more about depedency injection and Ioc containers in general to fully understand how to work with this container.
I'm using EF6 CodeFirst and WCF 4.5 with NetTcpBinding and BasicHttpBinding. Also I'm using Castle.Windsor for DI.
I have the following architecture:
MySolution.Core (class library)
- Domain
-- (...domain classes...)
- Data
-- IRepository.cs
MySolution.BusinessLogic (class library)
- (...business logic classes...)
MySolution.Data (class library using EF6)
- Models
-- Mapping
-- MyContext.cs (MyContext : DbContext, IDbContext)
- EFRepository.cs (EFRepository : IRepository, where in constructor is injected IDbContext)
- IDbContext.cs
MySolution.Services (WCF Project hosted in IIS with http and net.tcp)
- AppCode
-- Initialization.cs (instead global.asax, to be used with netTcpBinding)
- Installers
-- BusinessLogicInstaller.cs
-- RepositoriesInstaller.cs
-- ServicesInstaller.cs
In AppCode/Initialization.cs I have:
container = new WindsorContainer();
container.AddFacility<WcfFacility>();
container.Install(
new ServicesInstaller(),
new BusinessLogicInstaller(),
new RepositoriesInstaller());
And, inside Installers/RepositoriesInstaller.cs:
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// registration for EF context
container.Register(Classes.FromAssemblyNamed("MySolution.Data")
.InNamespace("MySolution.Data.Models")
.WithService.AllInterfaces()
.LifestylePerWcfOperation());
// registration for EF repository classes
container.Register(Classes.FromAssemblyNamed("MySolution.Data")
.InNamespace("MySolution.Data")
.WithService.AllInterfaces()
.LifestyleTransient());
}
ServicesInstaller and BusinessLogicInstaller register classes with LifestyleTransient.
Obs: The WCF must offer RESTful binding in the future.
My questions are:
If I use netTcpBinding, I cannot use LifestylePerWebRequest for DbContext, right?
It's safe and correct to use LifestylePerWcfOperation for the DbContext? If yes, is OK to use with BasicHttpBinding also? I don't find information explaining in detail the PerWcfOperation.
Is my architecture OK? Maybe I misunderstand some important concept with IoC/DI?
Thanks!
Correct. In WCF, LifestylePerWebRequest only works for HTTP bindings where you have AspNetCompatibility enabled.
LifestylePerWcfOperation can be used with any WCF bindings.
Architecture looks pretty complex but whether it's OK or not depends on the scale and complexity of your application. Really impossible to answer that question sensibly without a ton more information. This sort of architecture is very decoupled and my first questions is whether it's over-engineered for the problem at hand and whether you're also at risk of having anemic domain model.
I'm using the WCF REST Template where services are implemented with just a class and registered in the Global.ascx (much like MVC controllers are).
RouteTable.Routes.Add(new ServiceRoute("Games/Games", new WebServiceHostFactory(), typeof(Games.Games)));
Games.Games has a ctor accepting a Dal.Games.IGames and I have a NinjectModule with the Bindings ready but I cant for the life of me figure out where to pass the kernel to to have it control the creation of the service classes.
My services dont have a markup (svc) file so I'm guessing that it will have something do with replacing the WebServiceHostFactory with one from Ninject. I was able to find one in the Ninject Web extension but just dropping that in didnt change anything not to mention I coulnt find anywhere to setup the kenel in that class.
Any solutions, hints or tips are greatly appreciated.
Let me preface this by saying, someone who actually knows inner workings of Ninject could probably provide a much cleaner solution. I've been wrestling with the same issue as you mentioned though.
Mostly through trial & error I determined that if you make the following code changes in the Ninject.Extensions.Wcf library, Ninject will work its magic on your service classes.
In NinjectServiceHostFactory.cs, i changed the base class and the type passed to .Get<T>
public class NinjectServiceHostFactory : WebServiceHostFactory //<-- Changed base class
{
protected override ServiceHost CreateServiceHost( Type serviceType, Uri[] baseAddresses )
{
var serviceTypeParameter = new ConstructorArgument( "serviceType", serviceType );
var baseAddressesParameter = new ConstructorArgument( "baseAddresses", baseAddresses );
return KernelContainer.Kernel.Get<NinjectServiceHost>( serviceTypeParameter, baseAddressesParameter );
}
}
In the NinjectServiceHost.cs i changed the base class to WebServiceHost.
Also, I added this reference to both:
using System.ServiceModel.Web;
I'm sure this solution breaks this extension for other WCF service types so hopefully a Ninject guru will come along and provide a real solution.
I have a service (Service1) that uses another serice (Service2). I am using Dependency injection for both services and need to inject the proxy for Service2 into Service1.
I am unsure how to deal with the fact that the proxy is not a simple class of type IService2 but a proxy inheriting from ClientBase as well. Obviously my Service1 implementation needs to open the proxy and should also close it after use or abort it if an exception occurs but if I am just injecting an instance of IService2 then I cannot do this (without casting) because the Open, Close and Abort methods are on the base class whilst my operations are on the interface.
When it comes to testing Service1, I would expect to mock just the interface but if the Service1 implementation expect Open, Close and Abort methods, then this is tricky. In the past, I have done something hacky like this but there must be a better way!
var proxyBase = _service2 as ClientBase;
if (proxyBase != null)
{
proxyBase.Open();
}
_service2.DoOperation("blah"); //the actual operation
if (proxyBase != null)
{
proxyBase.Close();
}
// repeat for Abort in exception handler(s).
What are other people doing?
Thanks
The auto generated class that you get for adding a service reference for a WCF service is implemented as a partial class. What I do is create a another partial file for that class and implement an interface that exposed those methods, and then use that interface where you would normally use the ClientBase or WCF interface
public partial class Service2 : IClientService2
{}
If IClientService2 has the Abort and Close methods that match the ClientBase methods it should be all you need.
public interface IClientService2 : IService2 // where IService2 is the WCF service interface
{
void Abort();
void Close();
}
I suggest injecting a factory to construct WCF services rather than injecting the proxy itself since when a fault occurs then the channel is no longer able to be used and you will need to construct a new proxy.
IClientService2 proxy = _service2Factory.Create();
proxy.Open();
proxy.DoOperation("blah"); //the actual operation
proxy.Close();
Your interface is poluted because of the requirements imposed by Wcf. If you were not using wcf you would not have an Open and Close method. In an ideal world the interface should look the same as if the service was in process.
Have you chosen your IoC container yet? If you haven't I would consider looking at Windsor. This will allow you to maintain a clean interface and either inject the service as an in process object or a wcf proxy.
container = new WindsorContainer().AddFacility<WcfFacility>();
container.Register(Component
.For<IClientService2>()
.ActAs(DefaultClientModel)
.On(WcfEndpoint.FromConfiguration("YourServiceNameInConfiguration")))
.LifeStyle.Transient);
The WcfFacility will do all the opening and closing of the channel for you.
I ended up using this approach which uses Castle Dynamic Proxy to intercept calls and handle WCF specifics. It works really well and allows the class where the proxy is injected to treat it like a normal class / interface. This class is then totally unit testable by mocking the service contract interface.
I'm trying to hock up WCF with dependency injection. All the examples that I have found is based on the assumptions that you either uses a .svc (ServiceHostFactory) service or uses app.config to configure the container. Other examples is also based on that the container is passed around to the classes.
I would like a solution where the container is not passed around (not tightly coupled to Unity). Where I don't uses a config file to configure the container and where I use self-hosted services.
The problem is - as I see it - that the ServiceHost is taking the type of the service implementation as a parameter so what different does it do to use the InstanceProvider?
The solution I have come up with at the moment is to register the ServiceHost (or a specialization) an register a Type with a name ( e.g. container.RegisterInstance<Type>("ServiceName", typeof(Service);).
And then container.RegisterType<UnityServiceHost>(new InjectionConstructor(new ResolvedParameter<Type>("ServiceName"))); to register the ServiceHost.
Any better solutions out there? I'm I perhaps way of in my assumptions.
Best regards,
Michael
Use Constructor Injection to wire up your service implementation, just like you would with any other class.
Here's a writeup on how to make WCF understand Constructor Injection.
The example in that answer demonstrates Poor Man's Injection, but you can extrapolate from it and set up your UnityContainer instance in the ServiceHostFactory instead of a hard-coded dependency.
You pass the container instance all the way to the custom IInstanceProvider. Now you can use the container in the GetInstance method:
public object GetInstance(InstanceContext instanceContext)
{
var serviceType = instanceContext.Host.Description.ServiceType;
return this.container.Resolve(serviceType);
}