I am trying to create a hosted ASP.net Blazor application and trying to get a logger into my controller.
I have this:
public MyController(ILogger logger) {
_logger = logger;
// more initialization
}
But when I run it, I get:
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.Logging.ILogger' while attempting to activate 'MyApp.Server.Controllers.MyController'.
As there are a lot of log messages scrolling by, I guess Blazor already initializes a logger.
How do I access this?
The non-generic ILogger is not registered with the service collection. Instead, you are supposed to inject a generic ILogger<T>. The generic type argument T is used to set up the category name that is linked with the logger instance. It allows you to easily see where a log call came from.
Usually, you specify the type that you are using the logger with as the generic type argument. So in your case, you would use ILogger<MyController>:
public MyController(ILogger<MyController> logger)
{
_logger = logger;
}
Note that there is nothing special to server-side Blazor about this behavior. This is standard ASP.NET Core and the controller is also a normal ASP.NET Core controller.
Related
I am new to ASP.net core. Having a web API connect to database using EntityFramework core. The controller take request, do some analysis, and send the response as below
public class CentoDataController : ControllerBase
{
private readonly CentoWebDBContext _context;
private HPOSubSimHolder _hpoSubSimHolder;
public CentoDataController(CentoWebDBContext context)
{
_context = context;
_hpoSubSimHolder = new HPOSubSimHolder(hpofile);
}
[HttpGet("{id}")]
public ActionResult<CentoData> GetCentoData(string id)
{
IQueryable<CentoData> r = AnalysisMethod(id, _hpoSubSimHolder);
return r;
}
The code works, but _hpoSubSimHolder will be reloaded once a new request comes in. I guess I shouldn't share controller between requests. But how can I avoid reloading _hpoSubSimHolder ?
I can see that you're using .net core dependency injection
If you want that service to be shared across requests, think of making it a Singleton.
You can choose between AddScoped, AddTransient and AddSingleton when registering dependencies.
In your startup.cs class:
public void ConfigureServices(IServiceCollection services)
{
// some code
services.AddSingleton<HPOSubSimHolder>(new HPOSubSimHolder());
}
Singleton means only a single instance will ever be created. That instance is shared between all components that require it. The same instance is thus used always.
Scoped means an instance is created once per scope. A scope is created on every request to the application, thus any components registered as Scoped will be created once per request.
Transient The services created using transient lifetime will be created each time they are requested. This lifetime works best for lightweight services.
(Source)
Controllers are always instantiated per request. To control lifetime of any resources or dependencies the controller should use, you can use the build in Dependency Injection (DI).
Most examples setup DI in your startup.cs ConfigureServices method.
The DI container allows 3 different lifetime states, in your case I guess you can try to add the HPOSubSimHolder as singleton.
I have no idea what HPOSubSimHolder is and what the implementation details are, hence its hard to tell if that'll work for you.
But it would be the "normal" way of setting this up ;)
I have some services that were initially designed to be called from my ASP.NET Core 2.1 web application. They have dependencies injected to their constructors using Microsoft.Extensions.DependencyInjection package stuff. Some of them have a dependency of ILogger logger.
public GroupService(ILogger<GroupService> logger)
{
...
}
I am building a service provider within the function so that they can still work as expected however I'm wondering what I should do about the logger dependencies. An Azure Function (V2) gets an ILogger injected into it by default but that can't be used in the DI container to create the additional loggers that the services require.
Is there a LoggerFactory registered somewhere "under the covers" that I can get access to to be used in my DI container? I think that would allow me to add additional loggers that log to the functions output window or am I completely misunderstanding how logging in a function would work?
Do I just need to set up a new LoggerFactory and make that log to the ApplicationInsights instance used by the functions project?
Using the most recent Azure Function runtime, you can now have the runtime inject your dependencies through constructors.
You can now remove the static keywords from your Azure Function and have the runtime.
Here is how you can set this up:
[assembly: WebJobsStartup(typeof(StartUp))]
public class StartUp : IWebJobsStartup
{
public void Configure(IWebJobsBuilder webJobsBuilder)
{
// Enables logging and sets the minimum level of logs.
webJobsBuilder.Services.AddLogging(loggingBuilder =>
{
loggingBuilder.SetMinimumLevel(LogLevel.Debug);
});
// Registers your services.
webJobsBuilder.Services.AddTransient<IGroupService, GroupService>();
}
}
In my project I use Serilog and ASP.Net Core. The initialization part looks like that:
var provider = services.BuildServiceProvider();
var logFactory = provider.GetRequiredService<ILoggerFactory>();
logFactory.AddSerilog().AddConsole();
return provider;
This will add Serilog to the logging pipeline.
I want to add to the logger an ability to say whether there was logs with type 'Warning' or not in order to make some result message. For example it could be a method that returns simple bool saying about that.
How should I do it in a correct way? Can I somehow override current Core behavior by changing the way the logger handles 'Warning' logs in order to save somewhere the fact that LogWarning method has been called? Or should I implement my own logger (ILogger) as well as ILoggerFactory and ILoggerProvider with needed functionality? But then how can I save Serilog part in that scenario?
A new asp.net mvc project using owin, webapi, mvc and DI (SimpleInjector) runs fine if I remove the DI lib from the project. However, once introduced, the app blows up when registering the OWIN components for DI. The OWIN startup configuration is being hit and runs without error, but when it comes time to register the dependencies (listed below) I receive the following error:
An exception of type 'System.InvalidOperationException' occurred in Microsoft.Owin.Host.SystemWeb.dll but was not handled in user code
Additional information: No owin.Environment item was found in the context.
SimpleInjector Registration Code:
container.RegisterPerWebRequest<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>());
container.RegisterPerWebRequest<HttpContextBase>(() => new HttpContextWrapper(HttpContext.Current));
// app fails on call to line below...
container.RegisterPerWebRequest(() => container.GetInstance<HttpContextBase>().GetOwinContext());
container.RegisterPerWebRequest(() => container.GetInstance<IOwinContext>().Authentication);
container.RegisterPerWebRequest<DbContext, ApplicationDbContext>();
Update - Full Stack Trace
at
System.Web.HttpContextBaseExtensions.GetOwinContext(HttpContextBase
context) at
WebApplication1.App_Start.SimpleInjectorInitializer.<>c__DisplayClass6.b__2()
in
b:\temp\WebApplication1\WebApplication1\App_Start\SimpleInjectorInitializer.cs:line
41 at lambda_method(Closure ) at
SimpleInjector.Scope.CreateAndCacheInstance[TService,TImplementation](ScopedRegistration2
registration) at
SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration2
registration) at
SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration2
registration, Scope scope) at
SimpleInjector.Advanced.Internal.LazyScopedRegistration2.GetInstance(Scope
scope) at lambda_method(Closure ) at
SimpleInjector.InstanceProducer.GetInstance()
I think the exception is thrown when you call Verify(). Probably at that line, but only when the delegate is called.
Simple Injector allows making registrations in any order and will therefore not verify the existence and correctness of a registration’s dependencies. This verification is done the very first time an instance is requested, or can be triggered by calling .Verify() at the end of the registration process.
I suspect you're registrering the OwinContext only because you need it for getting the IAuthenticationManager.
The problem you face is that the OwinContext is only available when there is a HttpContext. This context is not available at the time the application is build in the composition root. What you need is a delegate which checks the stage of the application and returns a component that matches this stage. You could that by registering the IAuthenticationManager as:
container.RegisterPerWebRequest<IAuthenticationManager>(() =>
AdvancedExtensions.IsVerifying(container)
? new OwinContext(new Dictionary<string, object>()).Authentication
: HttpContext.Current.GetOwinContext().Authentication);
The delegate will return the Owin controlled IAuthenticationManager when the code runs at 'normal runtime stage' and there is a HttpContext.
But when making an explicit call the Verify() (which is highly advisable to do!) at the end of registration process there is no HttpContext. Therefore we will create a new OwinContext during verifying the container and return the Authentication component from this newly created OwinContext. But only if the container is indeed verifying!
A full and detailed description can be read here as already mentioned in the comments.
Although the question is different, the answer is the same as my answer here.
The problem is that you are injecting HttpContextWrapper into your application and attempting to use its members during application initialization, but at that point in the application lifecycle, HttpContext is not yet available. HttpContext contains runtime state, and it does not make sense to initialize an application within one specific user's context.
To get around this problem, you should use one or more Abstract Factories to access HttpContext at runtime (when it is available) rather than at application initialization, and inject the factories into your services with DI.
Using Ric .Net's answer might work, too, but it will throw an exception every time the application is initialized.
The answer of 'Ric .Net' has pointed me in right direction, but to allow changes to new SimpleInjector, have to change the code as below (as RegisterPerWebRequest is obselete):
container.Register<IAuthenticationManager>(() => AdvancedExtensions.IsVerifying(container)
? new OwinContext(new Dictionary<string, object>()).Authentication
: HttpContext.Current.GetOwinContext().Authentication, Lifestyle.Scoped);
Also, have to add below two registrations to the container, to allow 'container.Verify()' to work correctly:
container.Register<ApplicationUserManager>(Lifestyle.Scoped);
container.Register<ApplicationSignInManager>(Lifestyle.Scoped);
I'm working on the webapi project & now we are migrating to Owin/Katana hosting. I have few doubts regarding.
Quest ) Can i create OwinMiddleware per request instead creating a global object?
I'm able to create owinMiddleware but not able to create them per request. I wanted to create them per request so that i can insert a new object in owinMiddleware as dependency. I'm already using unity in webapi so wanted some solution aligned with unity.
I found few links :-
http://alexmg.com/owin-support-for-the-web-api-2-and-mvc-5-integrations-in-autofac/
http://www.tugberkugurlu.com/archive/owin-dependencies--an-ioc-container-adapter-into-owin-pipeline
but not able to adjust a new IoC with old unity. Can anybody suggest any solution
I found a way by which we could achive this :-
app.Use((IOwinContext context, Func<Task> next) =>
{
ILogger logger = {Resolve dependency using Unity};
CustomOwinMiddleware middleware = new CustomOwinMiddleware(context,next, logger);
return middleware.Invoke();
});
By this way I'm able to generate my middle ware per request. Is it the right way to do this ?
I would recommend using a single middleware instance for all requests that can be injected with unity if you so choose. I would then create a lifetimemanager within the invoke method of that middleware and inject whatever functions you want as delegates rather than calling invoke on another middleware. If you need the OwinContext in those functions you can just pass them as parameters.
See this blog post here for more information:
http://codetoast.org/orchard/blog/using-unity-owin-and-web-api-to-organize-log-entries-by-request