I want to use a Ninject.Wcf extension to create a parametrized service host instance.
For example I have a class MyWCFHandler
with the only following constructor:
pub开发者_运维问答lic MyWCFHandler(UserManager manager)
{
_manager = manager;
}
But when I write var myServiceHost = new ServiceHost(typeof(MyWCFHandler));
I have no way to pass the dependency object to a constructor.
I don't want to mess with the custom ServiceHost like offered in How do I pass values to the constructor on my wcf service?
I decided to go with the Ninject way, but not able to fully understand how to act in my situation.
Here is what I understand WCF Extension in Ninject works:
- Reference Ninject and Ninject.Extensions.WCF in my project.
Create a class that inherits Ninject module and write something like:
internal class ServiceModule : NinjectModule { public override void Load() { Bind<IUserManager>().To<UserManager>().WithConstructorParameters(myUserManagerIwantToUseInWCFHandler); } }
Add a Kernel initialized with new ServiceModule() to a KernelContainer.
Use the NinjectServiceHost like this:
var service = KernelContainer.Kernel.Get<IMyWCFHandler>(); _host = new NinjectServiceHost( service );
And there I should have my host ready to be opened.
The questions are:
How should I pass my constructor parameters into a NinjectModule? Should I create an instance of a NinjectModule right when I am ready to bind a parameter to it? How do I pass them to Get method?
Unfortunately there is not one example around to simple show the parametrized ServiceHost start. I don't even care if it is Ninject I use. Whichever solution has a good example - I am fine with it, since I am just deciding what IoC container to use.
Regarding ninject. The answer is it depends whether you want a singleton service or a new instance per request. With a singleton service you can do the following:
public class TimeServiceModule : NinjectModule
{
/// <summary>
/// Loads the module into the kernel.
/// </summary>
public override void Load()
{
this.Bind<ITimeService>().To<TimeService>();
this.Bind<ServiceHost>().ToMethod(ctx => ctx.Kernel.Get<NinjectServiceHost>(new ConstructorArgument("singletonInstance", c => c.Kernel.Get<ITimeService>())));
}
}
internal static class Program
{
private static void Main()
{
var kernel = new StandardKernel(new TimeServiceModule());
var serviceHost = kernel.Get<ServiceHost>();
serviceHost.AddServiceEndpoint(typeof(ITimeService), new NetTcpBinding(), "net.tcp://localhost/TimeService");
try
{
serviceHost.Open();
}
finally
{
serviceHost.Close();
}
}
}
Per request approach:
public interface IServiceTypeProvider
{
/// <summary>
/// Gets the service types.
/// </summary>
/// <value>The service types.</value>
IEnumerable<Type> Types { get; }
}
Func<Type, ServiceHost> serviceHostFactory
foreach (Type serviceType in this.ServiceTypeProvider.Types)
{
// I do some magic here to query base contracts because all our service implement a marker interface. But you don't need this. But then you might need to extend the type provider interface.
IEnumerable<Type> contracts = QueryBaseContracts(serviceType );
var host = this.CreateHost(serviceType);
foreach (Type contract in contracts)
{
Binding binding = this.CreateBinding();
string address = this.CreateEndpointAddress(contract);
this.AddServiceEndpoint(host, contract, binding, address);
}
host.Description.Behaviors.Add(new ServiceFacadeBehavior());
this.OpenHost(host);
this.serviceHosts.Add(host);
}
protected virtual ServiceHost CreateHost(Type serviceType )
{
return this.serviceHostFactory(serviceType );
}
public class YourWcfModule : NinjectModule
{
/// <summary>
/// Loads the module into the kernel.
/// </summary>
public override void Load()
{
this.Bind<Func<Type, ServiceHost>>().ToMethod(
ctx =>
(serviceType) =>
ctx.Kernel.Get<NinjectServiceHost>(new ConstructorArgument("serviceType", serviceType), new ConstructorArgument("baseAddresses", new Uri[] { })));
}
}
Have fun
精彩评论