Injecting into constructor with 2 params is not working - asp.net

I have a ASP .Net Web API controller that I want to take 2 parameters. The first one is an EF context and the second being a caching interface. If I just have the EF context the constructor gets called, but when I add the caching interface I get the error:
An error occurred when trying to create a controller of type
'MyV1Controller'. Make sure that the controller has a
parameterless public constructor.
private MyEntities dbContext;
private IAppCache cache;
public MyV1Controller(MyEntities ctx, IAppCache _cache)
{
dbContext = ctx;
cache = _cache;
}
My UnityConfig.cs
public static void RegisterTypes(IUnityContainer container)
{
// TODO: Register your types here
container.RegisterType<MyEntities, MyEntities>();
container.RegisterType<IAppCache, CachingService>();
}
I would expect that Entity now knows about both types when a request is made for MyV1Controller function it should be able to instantiate an instance since that constructor takes types it knows about but that's not the case. Any idea why?
[EDIT]
Note that I created my own class (IConfig) and registered it and add it to the constructor and it worked, but whenever I try to add the IAppCache to my constructor and make a request to the API I get the error telling me it can't construct my controller class. The only difference that I see is the IAppCache isn't in my projects namespace because it's a 3rd party class but that shouldn't matter from what I understand.
Here are the constructors for CachingService
public CachingService() : this(MemoryCache.Default) { }
public CachingService(ObjectCache cache) {
if (cache == null) throw new ArgumentNullException(nameof(cache));
ObjectCache = cache;
DefaultCacheDuration = 60*20;
}

Check the IAppCacheimplementation CachingService to make sure that the class is not throwing any exception when initialized. that parameterless exception is the default message when an error occurs while trying to create controllers. It is not a very useful exception as it does not accurately indicate what the true error was that occurred.
You mention that it is a 3rd party interface/class. It could be requesting a dependency that the container does not know about.
Referencing Unity Framework IoC with default constructor
Unity is calling the constructor with the most parameters which in this case is...
public CachingService(ObjectCache cache) { ... }
As the container know nothing about ObjectCache it will pass in null which according to the code in the constructor will throw an exception.
UPDATE:
Adding this from comments as it can prove useful to others.
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default));
Reference here Register Constructors and Parameters for more details.

Most of the DI containers while trying to resolve a type always look for a constructor with maximum number of parameters. That is the reason why CachingService(ObjectCache cache) constructor was being invoked by default. As ObjectCache instance is not registered with Unity, so the resolution fails. Once you force the type registration to invoke specific constructor, everything works.
So if you register IAppCache and force it to invoke CachingService() - parameter less constructor, it will work as expected.
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor());
Registering it this way, will force the parameter less constructor to be invoked and internally it will fall back on whatever the third part library wants to use as default. In your case it will be
CachingService() : this(MemoryCache.Default)
Another option that was mentioned in other answers is to register and pass the constructor parameter your self.
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor(MemoryCache.Default));
This will also work, but here you are taking the responsibility of supplying the cache provider. In my opinion, I would rather let the third party library handle its own defaults instead of me as a consumer taking over that responsibility.
Please take a look at How does Unity.Resolve know which constructor to use?
And few additional information for Niject
https://github.com/ninject/ninject/wiki/Injection-Patterns
If no constructors have an [Inject] attribute, Ninject will select the
one with the most parameters that Ninject understands how to resolve.

For LazyCache version 2.1.2 (maybe even earlier) the existing solution no longer works (no constructor that receives MemoryCache), but it works as simple as:
container.RegisterType<IAppCache, CachingService>(new InjectionConstructor());
This worked with .NET Framework 4.6.1, Unity Abstractions 3.1.0.

Related

Who passes the Context as a method parameter to the Constructor

I want to know who does call/create constructor of PageModel-derived class (in my case IndexModel).
Seems to me that by each request to a razor page, the class which is provided to the RazorPage via #model is instantiated, also wanna know who supplies the constructor parameter context, which is the EF Context:
public IndexModel(RazorPagesMovie.Models.RazorPagesMovieContext context)
{
_context = context;
}
Dependency Injection (DI) framework in ASP.NET is responsible for creating your IndexModel.
DI creates instances and provides as parameters classes that have been registered to the service provider on startup in ConfigureServices()
What happens on a request, is that
ASP.NET creates your IndexModel by asking the DI for it. This is basically the same as calling services.GetService<IndexModel>(). Your pagemodels have been registered to the DI container automatically for you
Whatever arguments your IndexModel constructor has (there can be as many as you need), will get filled in by the DI as long as they have been registered. If there are any non-registered types as arguments, an exception is thrown
In this case, if the code you listed works you have a line registering RazorPagesMovieContext somewhere on ConfigureServices().
Read more about DI in asp.net core: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-2.2
Note the section about service lifetimes as well.

Registering log4net named logger .NET Core service provider

I am struggling with finding a way to register log4net ILog within IServiceCollection services (.NET Core 2.1).
log4net LogManager provides a method that takes a Type as parameter so that it can be used when logging events. Here is an example call:
var log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
However when registering it with services at Startup method, I can use factory resolver, but still the type will be always the same. See the following excerpt:
private void SetServices(IServiceCollection services)
{
services.AddTransient(svc => CreateLog(MethodBase.GetCurrentMethod().DeclaringType)).;
}
protected ILog CreateLog(Type type)
{
return LogManager.GetLogger(type);
}
I was expecting that svc (IServiceProvider) will expose some ways to get to the type being actually resolved but there doesn't seem to be anything.
Also using reflection won't help (IMO, but I could be wrong) because ILog is activated prior to calling the resolved type ctor.
But maybe there is any extension on either MS side or log4net that would help resolving a named logger as explained on the beginning?
This is all to avoid having static members of ILog in any class that uses logging facility and use dependency injection instead.
Thanks, Radek
The way to do it is to implement and then register your own strongly typed Logger class that derives from ILogger.
.Net Core allows from to register generic type interface implementation with no type specified. In this case it would be:
services.Add(ServiceDescriptor.Singleton(typeof(ILogger<>), typeof(MyLogging.Logger<>)));
This allows all classes that require logging to use constructor injection as follows:
class A
{
public A(Ilogger<A> logger) {...}
}
Implementation of ILogger which a wrapper to log4net should be rather simple. Please let me know if you need an example.
Radek

spring-cloud with RestTemplate//Ribbon/Eureka - retry when server not available

I managed to successfully get my RestTemplate client discover remote service using Eureka and forward calls to it using Ribbon as described in the documentation.
Basically, it was just a matter of adding the following annotations of my Application class and let the magic of Spring-Boot do the rest:
#Configuration
#ComponentScan
#EnableAutoConfiguration
#EnableDiscoveryClient
(PS: you noticed I'm using spring-cloud:1.0.0-SNAPSHOT-BUILD and not 1.0.0.M3 - but this doesn't seem to affect my problem).
When two service instances are started, the rest-template client successfully load balance requests between the two. However, the client won't fallback to the second instance if the first is stopped before the Eureka load balancer notices, instead an exception is thrown.
Hence my question: is there a way to configure the RestTemplate/Ribbon/Eureka stack to automatically retry the call to another instance if the one selected the first place is not available? Zuul proxy and feign clients do this "out of the box" so I believe the library holds the necessary features...
Any idea/hint?
Thx,
/Bertrand
The RestTemplate support on its own does not know how to do any retrying (whereas the Feign client and the proxy support in Spring Cloud does, as you noticed). I think this is probably a good things because it gives you the option to add it yourself. For instance, using Spring Retry you can do it in a simple declarative style:
#Retryable
public Object doSomething() {
// use your RestTemplate here
}
(and add #EnableRetry to your #Configuration). It makes a nice combination with #HystrixCommand (from Spring Cloud / Javanica):
#HystrixCommand
#Retryable
public Object doSomething() {
// use your RestTemplate here
}
In this form, every failure counts towards the circuit breaker metrics (maybe we could change that, or maybe it makes sense to leave it like that), even if the retry is successful.
I couldn't get it to work with both #HystrixCommand and #Retryable, regardless of order of annotations on #Configuration class or on #Retryable method due to order of interceptors. I solved this by creating another class with the matching set of methods and had the #HystrixCommand annotated methods delegate to the corresponding #Retryable method in the second class. You could probably have the two classes implement the same interface. This is kind of a pain in the butt, but until order can be configured, this is all I could come up with. Still waiting on a real solution from Dave Syer and the spring cloud guys.
public class HystrixWrapper {
#Autowired
private RetryableWrapper retryableWrapper;
#HystrixCommand
public Response doSomething(...) {
return retryableWrapper.doSomething(...);
}
}
public class RetryableWrapper {
#Autowired
private RestTemplate restTemplate;
#Retryable
public Response doSomething(...) {
// do something with restTemplate;
}
}

Configuring dependency injection with ASP.NET Web API 2.1

I'm creating an ASP.NET Web API 2.1 site and as I want to inject dependencies directly into the controllers, I've created my own implementation of IDependencyResolver so that StructureMap will handle that for me.
public class StructureMapDependencyResolver : IDependencyResolver
{
public IDependencyScope BeginScope()
{
return this;
}
public object GetService(Type serviceType)
{
return ObjectFactory.GetInstance(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return ObjectFactory.GetAllInstances(serviceType).Cast<object>();
}
public void Dispose()
{
}
}
I've then told Web API to use this class by adding this line to the Application_Start method in Global.asax
GlobalConfiguration.Configuration.DependencyResolver = new StructureMapDependencyResolver();
That compiled but when I tried to access any of the API methods in a browser I got an error like this
No Default Instance defined for PluginFamily System.Web.Http.Hosting.IHostBufferPolicySelector, System.Web.Http
That one was relatively easy to solve as I added a line to my StructureMap configuration
this.For<IHostBufferPolicySelector>().Use<WebHostBufferPolicySelector>();
However then I got other similar errors for other System.Web.Http classes and while I could resolve some of them I am stuck on how to deal with 3 of them, namely ITraceManager, IExceptionHandler and IContentNegotiator.
The issue is that TraceManager which seems to be the default implementation of ITraceManager is an internal class and so I can't reference it in my StructureMap configuration.
So am I going about this completely the wrong way or is there some other way to inject these internal classes?
I'd like to give you a suggestion and explanation why not to go this way, and how to do it differently (I'd even say better and properly).
The full and complete explanation of the inappropriate IDependencyResolver design could be found here: Dependency Injection and Lifetime Management with ASP.NET Web API by Mark Seemann
Let me cite these essential parts:
The problem with IDependencyResolver
The main problem with IDependencyResolver is that it's essentially a Service Locator. There are many problems with the Service Locator anti-pattern, but most of them I've already described elsewhere on this blog (and in my book). One disadvantage of Service Locator that I haven't yet written so much about is that within each call to GetService there's no context at all. This is a general problem with the Service Locator anti-pattern, not just with IDependencyResolver.
And also:
...dependency graph need to know something about the context. What was the request URL? What was the base address (host name etc.) requested? How can you share dependency instances within a single request? To answer such questions, you must know about the context, and IDependencyResolver doesn't provide this information.
In short, IDependencyResolver isn't the right hook to compose dependency graphs. **Fortunately, the ASP.NET Web API has a better extensibility point for this purpose. **
ServiceActivator
So, the answer in this scenario would be the ServiceActivator. Please take a look at this answer:
WebAPI + APIController with structureMap
An example of the ServiceActivator:
public class ServiceActivator : IHttpControllerActivator
{
public ServiceActivator(HttpConfiguration configuration) {}
public IHttpController Create(HttpRequestMessage request
, HttpControllerDescriptor controllerDescriptor, Type controllerType)
{
var controller = ObjectFactory.GetInstance(controllerType) as IHttpController;
return controller;
}
}
All we can do with StructureMap, is in place. The key features of the Web API framework are still in place... we do not have to hack them. And we are also rather using DI/IoC then Service locator
Just try using UnityHierarchicalDependencyResolver instead of the other one. It worked for me. This is for future reference if somebody would like to use Unity

Write Junit tests for Spring MVC application which internally relies upon ContextLoader.getCurrentWebApplicationContext()

I'm trying to write integration tests for a controller in our spring mvc application. The controller invokes a service class which in turn invokes a dao to read/write data from the repository. The DAO needs to lookup some configuration. The configuration bean is defined in WEB-INF/applicationContext.xml.
I'm using something like this:
Configuration config =(Configuration)ContextLoader.getCurrentWebApplicationContext().getBean("config");
private String namespace = config.getProperty("someproperty");
The properties are stored in zookeeper so I'm not using spring's property management artifacts.
The problem is that while running the JUnit test ContextLoader.getCurrentWebApplicationContext() always returns null.
I have so far looked at the following approaches:
1. Ted Young's approach ( just google search for spring mvc integration tests ted young)
2. https://github.com/SpringSource/spring-test-mvc
3. this site.. questions/8464919/unit-testing-a-servlet-that-depends-on-springs-webapplicationcontextutils-getre
4. Use Selenium/JWebunit
5. http://confluence.highsource.org/display/Hifaces20/Hifaces20+Testing+package+-+testing%2C+tracing+and+debugging+web+applications+with+Jetty
1 doesn't resolve this issue. WebApplicationContext stays null
2 states that support for WebApplicationContext will be available in spring 3.2
3. I don't understand this. Where do I get the testApplicationContext and the getServletContext() from?
4. I do not want to go this way as this is completely blackbox testing.
5. I'm currently looking at 5. But this requires starting up a servlet container. Is there no other alternative?
I will appreciate any help you can provide.
Thanks
PixalSoft
#Ted Young SO didn't allow me to finish what I was saying.With loader=MockWebApplicationContextLoader,isn't it supposed to be available as the default contextloader exactly as the Spring ContextLoader behaves when the webapp is initialized by a servletcontainer?Is there something special I need to do get a handle on the MockWebApplicationContextLoader?Injecting the config object works for singleton objects. But all can't be singleton. Passing a config object in every constructor sounds too tedious. For now, I have created a class which has a static config object, autowired via a setter method. I will take a look at ApplicationContextAware.Many thx
You have to manually add the WebApplication context to ContextLoderListner.
This will work.
#ContextConfiguration(locations = "classpath:module-test-beans.xml")
#WebAppConfiguration
public class SampleTest extends AbstractTestNGSpringContextTests {
#Autowired
private WebApplicationContext wac;
#BeforeClass
public void setUp() throws ServletException {
MockServletContext sc = new MockServletContext("");
ServletContextListener listener = new ContextLoaderListener(wac);
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
}
#Test
public void testMe() {
Assert.assertFalse(ContextLoader.getCurrentWebApplicationContext() == null);
}
}
Add the following code at the beginning of your junit test:
MockServletContext sc = new MockServletContext("");
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml"); // <== Customize with your paths
ServletContextListener listener = new ContextLoaderListener();
ServletContextEvent event = new ServletContextEvent(sc);
listener.contextInitialized(event);
If you need to add more than one xml for the context path just put them in the same string separated with spaces, like this:
sc.addInitParameter(ContextLoader.CONFIG_LOCATION_PARAM,
"/applicationContext-test.xml /applicationContext-other.xml");
The reason why ContextLoader.getCurrentWebApplicationContext is returning null is because, when you use my MockWebApplicationContextLoader, you are neither using a web application context nor that particular ContextLoader implementation.
Since your repository is managed by Spring, why do not you simply inject the config object into the repository? Injecting the config object is the most appropriate way to get access to it. You can then initialize your namespace property in a method annotated with #PostConstruct.
Alternatively, your DOA could implement ApplicationContextAware to receive a copy of the application context during construction.
store your property file in your classpath.
now access that property in your controller class like this:
/*to access your filename.properties file */
properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("filename.properties"));
String sServerLocation = properties.getProperty("key");
now you can access your property file.
I am sure it will work.

Resources