I have a ServiceStack host which depends on an external class which has a constructor of the form
public class MyClass(ILogger<MyClass) {}
but when I call
container.AddSingleton<ISearchEngine, ElasticSearchEngine>();
ServiceStack is not resolving ILogger, what can I do to get this to work?
ServiceStack.Logging abstraction uses .NET Core's logging provider implementation where you'll end up with the same logging implementation using ServiceStack's logging abstraction:
public class MyClass
{
public ILog Log = LogManager.GetLogger(typeof(MyClass));
}
Alternatively you can register your dependency with ASP.NET Core's IOC to access their ILogger<T> abstraction directly:
builder.Services.AddSingleton<ISearchEngine, ElasticSearchEngine>();
Related
What is the difference between ILogger<T> and ILogger? Below are two ways the Sample class using ILogger, which one is the best and why!
Method 1
public class Sample
{
private readonly ILogger<Sample> _logger;
public Sample(ILogger<Sample> logger)
{
_logger = logger;
}
public void DoSomething()
{
_logger.LogInformation("The answer is {number}", 42);
}
}
Method 2
public class Sample
{
private readonly ILogger _logger;
public Sample(ILogger logger)
{
_logger = logger;
}
public void DoSomething()
{
_logger.LogInformation("The answer is {number}", 42);
}
}
As per usage of ILogger in your .net core which is depends of your requirements.
ILogger
ILogger is a logger that your code can use to write log messages.
There are three core methods:
IsEnabled tests whether a log level is enabled on that logger;
Log is the core logging method that is used to write log messages;
BeginScope defines a logging scope.
There’s a bunch of logging extension methods that build on that core; the common methods like LogInformation are just wrappers around Log, with the appropriate arguments.
Internally, an ILogger has a “name” (also called a “category”). The idea is that each ILogger instance is used by a different component of the application.
ILogger is a base interface that provides the core logging functionality, but it is seldom used directly. There are some exceptions (e.g., Azure Functions will pass you an ILogger), but most of the time your code will log to an ILogger<T>.
ILogger
ILogger<T> is a logger that is named after a type T. All logs sent to an ILogger<T> (with the default implementation) will have a logger name/category of typeof(T).FullName. ILogger<T> is derived from ILogger and adds no new functionality.
If you’re using dependency injection, an instance of ILogger<T> is usually injected into your type T. So, each time you have a constructor that takes an ILogger<T>, you are defining a “component” for your application.
Majar usage of difference
If you want to log your data as Typed log (serilog, etc., ) you can use ILogger< T> or you want to use untyped logs you can simply use ILogger
ASP.NET Core apps, encourage you to use standard Serilog interfaces like Log, ILogger, and LogContext if they meet your needs.
Alternatively, your app can consume the ILogger interface from the framework via dependency injection. Serilog implements this interface, so the results are identical for practical purposes.
The ILoggerFactory logger factory instance is the boostrapper of the logging system: It is used to attach logger providers and create logger instances - either typed (ILogger<T>) or untyped (ILogger). These logger instances will log to all registered logger providers.
Refer Ilogger best practices & Usage of logging
This is a question about how ASP.NET MVC is working. Now I am trying to understand how the controller pass data from database. And I cannot see where "context" comes from to the args[0] of the constructor in a scaffoled controller.
For example, when you scaffolds a controller from a model called "item", you get ItemsController. The constructor of StaffsConroller goe like;
public ItemsController(DbContext context)
{
_context = context
}
The variable "_context" is declared in ItemsController. But where is "context" instanced?
If you use Entity Framework or configure dependency injection in Startup.cs, then DbContext is created by Dependency Injection. You can research consturctor injection.
ASP.NET Core applications are configured using dependency injection.
EF Core can be added to this configuration using AddDbContext in the
ConfigureServices method of Startup.cs. For example:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddDbContext<ApplicationDbContext>(
options => options.UseSqlServer("name=ConnectionStrings:DefaultConnection"));
}
For more details you can visit these links: DbContext in dependency injection for ASP.NET Core, Dependency injection in the controller
DbContext is Injected into the constructor via Dependency Injection.
When the ItemsController is created (usually every time a new HTTP request arrives at a route mapped to an ItemsController action) the ASP.NET engine knows that ItemsController needs a DbContext and it instantiates a new DbContext there.
See more here: https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-model?view=aspnetcore-5.0&tabs=visual-studio#dependency-injection-in-the-controller
ServiceStack uses a dialect of Funq (no support for metadata), where Kephas uses one of MEF/Autofac (requires metadata support). My question has two parts:
How to make ServiceStack and Kephas use one DI container, if this is possible?
Depending on the answer above: how to make ServiceStack services (like IClientCache) available to Kephas components, knowing that such services may not be annotated with [AppServiceContract]?
You can make ASP.NET and Kephas use one container by choosing to work with Autofac. However, as #mythz pointed out, you will need to provide the Autofac IoC Adapter to the ServiceStack. I don't think you will have any problems with ASP.NET in doing so, as Autofac is the first recommendation of the ASP.NET Core team.
For ASP.NET Core, reference the Kephas.AspNetCore package and inherit from the StartupBase class if you need to be all setup. However, if you need to be in control, have a look at https://github.com/kephas-software/kephas/blob/master/src/Kephas.AspNetCore/StartupBase.cs and write your own Startup class. Another resource that you might find useful is the Kephas.ServiceStack integration package.
Then, additionally to annotating service contracts and service implementations, Kephas allows you to provide service definitions by implementing the IAppServiceInfoProvider interface. These classes are automatically discovered, so this is pretty much everything you have to do.
public class ServiceStackAppServiceInfoProvider : IAppServiceInfoProvider
{
public IEnumerable<(Type contractType, IAppServiceInfo appServiceInfo)> GetAppServiceInfos(IList<Type> candidateTypes, ICompositionRegistrationContext registrationContext)
{
yield return (typeof(IUserAuthRepository),
new AppServiceInfo(
typeof(IUserAuthRepository),
AppServiceLifetime.Singleton));
yield return (typeof(ICacheClient),
new AppServiceInfo(
typeof(ICacheClient),
ctx => new MemoryCacheClient(),
AppServiceLifetime.Singleton));
}
}
Note in the above example that for IUserAuthRepository there is no implementation provided. This indicates Kephas to auto-discover the implementation in the types registered for composition. Alternatively, feel free to use an instance or a factory in the registration, if you need to be deterministic.
I've never heard of Kephas before, but if you're referring to this Kephas Framework on GitHub it says it uses ASP.NET Core in which case it's best if you get them to both use ASP.NET Core's IOC which you can do by either registering your dependencies in ConfigureServices in your App's Startup:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//...
}
}
Or alternatively in ServiceStack's latest v5.6 release for Modular Startup change your ASP.NET Core Startup class to inherit from ModularStartup, e.g:
public class Startup : ModularStartup
{
public Startup(IConfiguration configuration) : base(configuration){}
public new void ConfigureServices(IServiceCollection services)
{
//...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...
}
}
In which case you'll be able to Register ASP.NET Core dependencies in AppHost by registering them in your AppHost's Configure(IServiceCollection) where they can be resolved through both ASP.NET Core's IOC + ServiceStack's IOC, e.g:
public class AppHost : AppHostBase
{
public override void Configure(IServiceCollection services)
{
services.AddSingleton<IRedisClientsManager>(
new RedisManagerPool(Configuration.GetConnectionString("redis")));
}
public override void Configure(Container container)
{
var redisManager = container.Resolve<IRedisClientsManager>();
//...
}
}
I followed Alexander Duemont's blog, trying to implement a Java Spring Boot application that consumes Cloud Foundry Destination. The Destination has a custom OData V2 behind it, coming from an On-Premise ERP system. For local dev, when I perform the Maven build, the Integration-Tests module registers failure due to dependency injection
This is part of my Controller
#RestController
#RequestMapping("/resources")
public class ClassificationsController {
private static final Logger logger = CloudLoggerFactory.getLogger(ClassificationsController.class);
private final ClassificationService service;
public ClassificationsController(#Nonnull final ClassificationService service) {
this.service = service;
}
…..
}
The #Nonnull final ClassificationService Service causes org.springframework.beans.factory.UnsatisfiedDependencyException
I cannot use Spring stereotype annotations on generated Service classes (Fluent) to create Beans!
This question is more likely related to Spring Boot configuration.
I'm assuming ClassificationService is an interface and the implementing class exists in the same package.
Please make sure...
... to add the implementing class of ClassificationService to your component scan / test runtime. Feel free to share the integration test code to setup the test environment. Maybe the additional class reference is missing.
... to correctly annotate the respective Application class of your Spring Boot project. For example, assuming your ClassificationService resides in org.example.services.classification, while the rest of your application uses org.example.app. Your basic Application class would look like this, when following the Cloud SDK guide:
#SpringBootApplication
#ComponentScan({"com.sap.cloud.sdk", "org.example.services.classification", "org.example.app"})
#ServletComponentScan({"com.sap.cloud.sdk", "org.example.app"})
public class Application extends SpringBootServletInitializer
{
#Override
protected SpringApplicationBuilder configure( final SpringApplicationBuilder application )
{
return application.sources(Application.class);
}
public static void main( final String[] args )
{
SpringApplication.run(Application.class, args);
}
}
... to annotate the implementing class of ClassificationService with javax.inject.Named. In case you have multiple implementations of the same interface, make sure to give the not-used class a custom (unique) value for the #Named annotation.
... to look for exceptions (Class not found) in the application log during startup.
Using ninject, I'm able to create an abstract factory using the following syntax from the application's composition root:
kernel.Bind<IBarFactory>().ToFactory();
Does ServiceStack's default IoC container similar functionality? I'd like to implement an abstract factory in one of my service classes in order to create repositories as needed.
One suggestion I've heard was to use:
HostContext.Container.Resolve<[InsertDependancyHere]>()
but I'd like to avoid creating access to the container outside of the composition root (the Apphost.cs file).
As far as i could tell, ServiceStack's Funq IoC implementation does not include this Abstract Factory implementation, like Ninject's Abstract Factory support (or Castle Windsor's Typed Factory Facility, which i used to use).
You can still avoid Service Locator anti-pattern by creating a concrete Factory implementation and injecting that to your classes.
public class BarFactory : IBarFactory
{
// constructor inject dependencies to the factory - no service locator
public BarFactory() { ... }
// create objects from factory
public IBar GetBar() { ... }
}
Your other classes can inject IBarFactory and call it directly.
Func is bare-bones by design, so will not have all the same features. ServiceStack added some features, but mostly having to do with autowiring registration.
If you can't create a concrete implementation for your factories, this other SO answer may show you how to do it yourself.