How can I use Ninject WCF extension with a singleton service? - asp.net-mvc

I'm using Ninject 2.2.1.4 and Ninject.Extensions.Wcf 2.2.0.4.
My service is decorated with the following attribute:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
Using the above attribute, I receive the error:
"The service type provided could not be loaded as a service because it does not have a default (parameter-less) constructor. To fix the problem, add a default constructor to the type, or pass an instance of the type to the host."
If I remove the attribute Ninject works as expected.
After doing some research it's my understanding that since the service is marked as a singleton it will automatically be created with a parameter-less constructor by the ServiceHost, hence the error message. In order to resolve the issue, I have to create the service object myself, resolved using ninject, and then pass that singleton object off to the ServiceHost to use. I'm not sure how to do that.
I looked at the WCF extension source and I see that NinjectServiceHost inherits from ServiceHost, so my thought was to bind NinjectServiceHost to my instance of the service object using the overloaded constructor:
public NinjectServiceHost( object singletonInstance )
: base( singletonInstance )
{
}
I'm not sure if that's correct and if it is, how and where to properly bind it so the ServiceHost can be fed my instance.
Any suggestions? Thanks.

If you can live with a beta Version I suggest to update to 2.3.x It supports IIS hosted singleton Services. See also the examples on github

Related

Autofac DI, type not assignable to service

I simply cannot figure this out. Using Autofac with .Net core 2.0 and trying to resolve some simple dependencies. Feel like I've tried everything so my current code doesn't reflect everything I've tried.
Here is one of the exceptions I'm getting from Autofac
None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type
'Elucidate.Core.Application.ValuesController' can be invoked with the available services and parameters: Cannot resolve parameter 'Elucidate.Core.Data.Repository.IRepository'1[Elucidate.Core.Model.User.IUser]rep' of constructor 'Void .ctor(Elucidate.Core.Data.Repository.IRepository`
Here is where I'm trying to get the dependency injected
public ValuesController(IRepository<IUser> rep)
Here is how I'm registering the types in an autofac module
builder.RegisterType<User>().As<IUser>();
builder.RegisterType<CoreUserStore<User>>();
builder.RegisterType(typeof(Repository<User>)).As<Repository<IUser>>();
builder.RegisterType<EntityFrameworkModelContext<User>>(); //.As<IModelContext>();
What am I doing wrong? I'm new to autofac, used to Unity which seems to be extinct.
The ValuesController constructor is expecting IRepository<IUser> and you haven't wired the correct type in Autofac.
You need to register the concrete repository type as the implemented interface, note the .As<IRepository...:
builder.RegisterType(typeof(Repository<User>)).As<IRepository<IUser>>();
Or alternatively "ask" for the concrete type in the constructor.
public ValuesController(Repository<IUser> rep)
The first is probably the preferred approach. You can also do:
builder.RegisterType<Repository<User>>().AsImplementedInterfaces();
Which will register the concrete type as all implemented interfaces.

Maintaining a single instance of a concrete class with unity

When using unity, if i attempt to inject a concrete type that i havent explicitly registered with the container, unity will attempt to locate the current type and will instantiate a new one for me, before injecting it into the class that depends upon it.
How can i ensure that only a single instance of this type is used? Do i need to explicitly register an instance with the container beforehand?
From MSDN:
You can use the Unity container to generate instances of any object that has a public constructor (in other words, objects that you can create using the new operator), without registering a mapping for that type with the container. When you call the Resolve method and specify the default instance of a type that is not registered, the container simply calls the constructor for that type and returns the result.
So simply put, yes, you have to register a mapping for your type to be able to use it as singleton in your app. You can achieve it using RegisterInstance method or RegisterType and providing the ContainerControlledLifetimeManager as the lifetime manager.

WCF Client calling a Java Web Service : XmlSerializer cannot find Derived types

This seems like a fundamental Web Services problem. However an elegant solution is elusive based on some research I have been able to do. I guess I am missing something here
I am using a WCF client to connect to a External web service of which I have no control. The external WS is java based. There are a bunch of assemblies which are provided to call the methods in web service. These assemblies have base classes and derived classes. The web service methods can take Base class as param whereas from the WCF Client I instantiate a Derived class and pass it to the method.
To simulate this scenario, I created a small project with one ClassLibrary which has a BaseClass and a DerivedClass with one method.
Then I create an asmx web service and add a HelloWorld method inside it. I add a reference to the ClassLibrary. This method takes a BaseClass type param.
Then I create a Service Reference to the ASMX web service. In the proxy class, I add a XmlSerializerFormatAttribute to the method if it is already not there.
From the WCF client, I call the ASMX web method
BaseClass bc = new Derived();
ServiceReference1.TestService ts = new WCFTest.ServiceReference1.TestService();
lbl1.Text = (c1.HelloWorld(bc));
The call fails with error
The type ClassLib.Derived was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
The only way I could call this web service method was by adding XmlInclude attribute to the BaseClass in the ClassLibrary.
In my scenario, this library is a dll provided by an external vendor. I cannot add attributes to its classes. I have looked a DataContractSerializer and KnownTypes and XmlSerializer ctor. However those solutions do not seem to be applicable in my scenario.
How can I make XMLSerializer see the Derived classes in the assemblies I have referencing in the WCF Client? Is there an elegant solution?
Thanks,
Hem
Including your own type mapping for an XmlSerializerOperationBehavior may just work, but I haven't tried this (see GetXmlMappings).
http://msdn.microsoft.com/en-us/library/system.servicemodel.description.xmlserializeroperationbehavior.aspx
Alternatively, forcing use of the DataContractSerializer via a DataContractSerializerOperationBehavior (as opposed to the XmlSerializerOperationBehavior it's using now) may work too, if you specify your own known types
http://msdn.microsoft.com/en-us/library/ms576751%28v=vs.85%29.aspx
Finally, as a last resort, you can force use of the DataContractSerializer using the DataContractSerializerOperationBehavior, then specify your own DataContractSurrogate to force use of the XmlSerializer where you can pass custom types to its constructor (which circumvents the requirement for the XmlInclude attribute).
http://msdn.microsoft.com/en-us/library/ms751540.aspx
Hope that helps.

How to set a default constructor argument to null with StructureMap?

A class has a unique constructor taking IMyInterface as its argument. If I define a concrete type of IMyInterface and registers it to StructureMap then there is no issue and my class can be instanciated with this concrete type.
However, in some cases, no concrete type will be registered. In that case, I would like to receive null for the IMyInterface parameter. Instead I get an exception:
StructureMap Exception Code: 202
No Default Instance defined for PluginFamily IMyInterface.
Is it possible to define a default value for a missing plugin?
Context: my class, which is a service, uses the Spark view engine and defines some default namespaces. The service uses a ISparkNamespacesProvider (IMyInterface) to add aditional namespaces. The client app may register such a provider or not. That's why the constructor of the service will receive either a provider or none.
Taken from here:
For<IService>().Use<MyService>()
.Ctor<IMyInterface>("nameOfParameter").Is(null);
But You should think about why Your class is dependent on IMyInterface. If it's optional - that's a code smell. Maybe You should refactor it out as method argument for method that needs it or as settable property.
There shouldn't be need for switching between concrete implementation and null. When composing dependency graph at composition root, You should know exactly what will be Your dependencies w/o .If(isSomething()).Use<MyService>().Ctor<IMyInterface>(null).
You might want to check out this tekpub presentation and this book (look for so called MEAP access) about DI and IOC.
One way to accomplish what You want is using so called 'poor man dependency injection'. That is - to define second constructor:
public MyClass():this(null){...}
But I wouldn't recommend that.
StructureMap now supports this case via UseIfNone https://structuremap.github.io/registration/fallback-services/

Construtor/Setter Injection using IoC in HttpHandler, is it possible?

I've ran into a rather hairy problem. There is probably a simple solution to this but I can't find it!
I have a custom HttpHandler that I want to process a request, log certain info then enter the details in the database. I'm using NUnit and Castle Windsor.
So I have two interfaces; one for logging the other for data entry, which are constructor injected. I quickly found out that there is no way to call the constructor as the default parameterless constructor is always called instead.
So I thought I would use Setter injection and let Castle windsor sort it out. This actually works as when I use container.Resolve<CustomHttpHandler>(); I can check that the logger is not null. (In Application_Start in Global.asax.cs)
The problem is although Castle Windsor can create the instance the http application is not using it??? I think??
Basically the whole reason for doing it this way was to be able to test the logger and data repository code in isolation via mocking and unit testing.
Any ideas how I can go about solving this problem?
Thanks!
Not possible, at least not directly. IHttpHandler objects are instantiated by the ASP.NET runtime and it doesn't allow Windsor to get involved in its creation. You can either:
Pull dependencies, by using the container as a service locator.
Set up a base handler that creates, injects and delegates to your own handlers (see how Spring does it)
Use the container as a service locator for another service that handles the entire request (as saret explained)
What you could do is have the HttpHandler call out to another object that actually handles the request. so in your HttpHandler's ProcessRequest method you would do something like this:
public void ProcessRequest(HttpContext context)
{
var myHandlerObject = container.Resolve<HandlerObject>();
myHandlerObject.ProcessRequest(context or some state/info that is required)
}

Resources