Iterate through all sinks and enrichers registered in Serilog - serilog

How can I iterate through all sinks (ILogEventSink objects) or enrichers (ILogEventEnricher objects), respective, registered in Serilog?
I'm using Serilog.AspNetCore.
Thanks.
So, my naive idea is:
In Emit operation I must call a third party service that require current HttpContext to be set.
It seems Emit operation runs on background thread that has not got HttpContext assigned. So in Emit operation, I want to resolve IHttpContextAccesor service and set its HttpContext property. Then I can call a third party service requiring HttpContext to be set and all will be fine.
The current httpContext instance I will get is in my custom middleware and just here is the place where I want to inject httpContext instance into the Sink instance (to its [ThreadStatic] field) to accomplish scenario described above.
Another way is recreating all Serilog (and its Sink) in a middleware on each http request and pass httpContext to its constructor as a parameter. Expensive.

Serilog doesn't support this scenario.

Related

asp.net 5 DI: Using scoped service outside request

We have a IOrderManager service which uses some other services registered in DI via AddScoped().
Now we need to use that service in the OnMessage handler for some queue which, obviously, is raised outside any request pipeline.
So when we try to get our service using something like
var orderManager = ServiceProvider.GetRequiredService<IOrderManager>();
we got "Can't access disposed object ..." exception.
Question: is it possible to "tell" DI that we are inside some "fake request" processing to avoid disposing services registered as "scoped"?
If your IOrderManager is outside request scope, you can create your custom scope per-message like this:
using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var myService = serviceScope.ServiceProvider.GetRequiredService<MyService>();
}
If you're using scoped services within IOrderManager, IOrderManager needs to also be scoped.
If you don't do this, when the IOrderManager instance is first created, it will "capture" the scoped dependencies from the current request.
Any future usage of IOrderManager will continue to use the old scoped dependencies and not dependencies from the current request scope.
Next, the only reason you should use scoped dependencies is if they somehow maintain state across a single request and need to isolate that state from other requests.
If your IOrderManager doesn't actually need information that is scoped to a request, it shouldn't be scoped and shouldn't use dependencies that are also scoped.
Put another way, if you think it should be usable outside of an active request, it by definition is not scoped does not require scoped dependencies.

Getting a scoped component from a IDocumentStoreListener

I have an ASP.NET 5 app using RavenDB, and I'm trying to create an attribute that will create a "Changeset" document with the keys of all the documents that were stored by the action.
For that purpose, I created an ActionFilterAttribute instantiated via ServiceFilterAttribute, which is registered as Scoped, that sets a flag on another Scoped component, let's call it ChangesetAccessor, which holds the list of changes.
The IDocumentStore is obviously a Singleton, and the listener (IDocumentStoreListener implementation) is manually instantiated. It needs access to the current ChangesetAccessor, so I thought giving it a reference to the IServiceProvider so it can call GetService<ChangesetAccessor> as needed would be enough, but it is receiving a different instance.
How can I get the ChangesetAccessor for the "current request" from my listener?
You can actually access RequestServices off of the HttpContext to get scoped instances. It's kind of backwards, and really will depend on Microsoft.AspNet to do it, but it will work for your situation; interestingly, IHttpContextAccessor is a singleton, too, though it gives you a scoped value.
// injected:
IHttpContextAccessor httpContextAccessor;
// in your method:
httpContextAccessor.HttpContext.RequestServices.GetService<ChangesetAccessor>()

Injecting HttpContext in Ninject 2

In my asp.net mvc application I'm using Ninject as a DI framework.
My HttpAccountService is used by my controllers to get info from and to cookies.
For this I need the HttpContext.Current in the HttpAccountService.
As this is a dependency I injected it throught the constructor as such:
kernel.Bind<IAccountService>()
.To<HttpAccountService>()
.InRequestScope()
.WithConstructorArgument("context", HttpContext.Current);
Sadly this always binds to the same context which makes that after the first request finishes this context becomes outdated.
How should I correctly inject my HttpContext?
WithConstructorArgument has an overload that takes a Func<NinjectContext,T>, i.e., you can use:
... .WithConstructorArgument("context",ninjectContext=>HttpContext.Current);
which will call the provided 'callback' lambda within the request processing and obtain the correct value at that point in time [as opposed to you calling the other overload and supplying a constant value which gets computed at Bind<> time].
(If you're not trying to Mock the context, I assume you'll consider using it inline)

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)
}

Castle Windsor RemoveComponent False

I am calling Kernel.RemoveComponent on my Windsor container and it is returning false. I know the component is present (I have verified by calling GetHandler with the same key and it returns the expected info)...so why can't I remove my component from the container? How can I troubleshoot this?
I have a bunch of authentication and authorization that happens in independent handlers and components in my WCF services before the OperationContext is established (OpertaionContext.Current is still null). During this period, I need access to the request message from the request context. I'd like to store the RequestContext instance in my container with a per-thread lifetime. Upon each new request, I need to overwrite this instance so I don't retrieve the wrong request message. Is this simply not a good task for Windsor? If I can't remove the component before re-registering each new RequestContext, then all of the RequestContexts will never get disposed, right?
Thanks!
RemoveComponent will not remove the component if there are other components depending on it. Why are you removing the component instead of not putting it in the container in the first place?

Resources