NLog inject context information c# - c#

I'm using ASP.NET WebApi and NLog.
I want to add per-request information like a correlationId to my log messages. In the best case, the user of NLog shouldn't know anything about this. The Logger itself should be able to get the information from the http request.
With Unity i can use the "PerRequestLifetimeManager" to inject those information, but it isn't recommenden. I should rather use HttpContext.Items, but i'm not happy with System.Web and HttpContext.
Is there a possibility to set the information on the server and get them in my logger every time i want to log something, based on the request scope?

NLog has the NLog.MappedDiagnosticContext that you can use to create session type of logging variables. In ASP.Net and WebAPI, using async contexts, you might need to use NLog.MappedDiagnosticsLogicalContext
You'll also need to update the Targets' layouts to include this information:
<target layout="${longdate}|${level:uppercase=true}|${logger}|[${mdc:item=SomeVariable}]${message}" >
Here's how you'd use it:
try
{
NLog.MappedDiagnosticsLogicalContext.Set("SomeVariable", Guid.NewGuid().ToString());
//do your work
Log.Info("Some message here.");
//do more work
Log.Info("Finished!");
}
finally
{
NLog.MappedDiagnosticsLogicalContext.Remove("SomeVariable");
}
Of note, I'd like to see a better way to do this utilizing the C# using statement, like log4net supported.

Related

Checking if a WCF service is called

I have built a WCF service using C# that is running on Windows server 2016.
I need to know when this WCF was called from the client, and who called it (for example the IP)
Is there a way to do this?
I have tried to check the event viewer, and the IIS, but did not get to know how.
Thanks,
You really should use some kind of logging framework ( Log4Net, NLog, MS enterprise library logger... ),
that will allow you to log into text file, email, event log or database, and you will then be able to first of all document any error/exception thrown from your code so that you can investigate and resolve bugs, plus you can then also include information / verbose level log entries to capture, as you say, caller IP and timestamp as well as calling parameters if you like and need to do so.
Logging every request best thing you can do. If you want to know how to get client ip in WCF, method below will work for you. Then you could log that ip, request time etc.
public string GetClientIp()
{
OperationContext operationContext = OperationContext.Current;
MessageProperties messageProps = operationContext.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProps = (RemoteEndpointMessageProperty)messageProps[RemoteEndpointMessageProperty.Name];
return endpointProps.Address;
}
you can try existing Log WCF Service Calls with Parameter information logging with system.diagnostics configuration
or create custom implementation for IOperationInvoker like here Log WCF Service Calls with Parameter information

Adding middleware or alike in Azure functions v2

I need to add correlationId to my logging context and I did it on my MVC project by adding CorrelationId nuget to the project and setting up its middleware, but I could not do the same in Azure functions.
I have loaded the ICorrelationContextAccessor using Dependency injection and then set my correlationId like this:
[FunctionName("func1")]
public async Task Run([ServiceBusTrigger("mytopic", "MySubscription", Connection = "ServiceBusConnectionString")]Message message)
{
_correlationContextAccessor.CorrelationContext = _correlationContextFactory.Create(message.CorrelationId, "X-Correlation-ID");
_logger.LogInformation($"C# ServiceBus topic trigger function processed message: {message.MessageId}, {Encoding.UTF8.GetString(message.Body)}");
It works fine and I see my correlationId in the log line below and in my services in the function. The only part that I am missing is that I have logs regarding the start and finish of the function that still has no correlationId, which kind of make sense becaue when the function wants to log that it has received the message the correlationId is not set.
The short version is that you can't effect the logging code that runs before your function using the built in bindings.
You won't be able to change that first "C# Timer trigger function processed message" as the message hasn't been read at that point-- it would be the same as trying to get the correlation ID set in your MVC project before reading the incoming HTTP request.
You could add logging as soon as the message is first received by creating a custom binding. I would encourage you to consider carefully whether or not it is worth building and maintaining a custom binding to get your logging setup a few lines sooner.

Application Insights - Custom TrackRequest is creating duplicate messages

I want to be able to add custom properties to a request telemetry. I am able to do this with code such as:
public void LogRequest(IDictionary<string,string> properties)
{
var client = new TelemetryClient();
var request = new RequestTelemetry();
foreach(var prop in properties)
{
request.Properties.Add(prop );
}
client.TrackRequest(request);
}
This code works in the sense that it creates a request telemetry with all of the custom properties I wanted, however the application insights SDK is also creating a duplicate request telemetry (without my custom properties). So it's sending its own request telemetry and the one that I created.
While trying to do some research I found this:
https://github.com/Azure/Azure-Functions/wiki/App-Insights-Early-Preview
Custom telemetry
You can bring the .NET App Insights SDK in and create your own TelemetryClient. There isn’t any conflicts, but there is some advice:
Don’t create TrackRequest or use the StartOperation methods if you don’t want duplicate requests – we do this automatically.
So my question is, is there anyway to send in my own custom request telemetry without the sdk automatically creating a duplicate message?
Also I would like to avoid using TrackEvent. Most of the information I need is already in the request object so I would prefer to use TrackRequest.
This is what I have in my application insights config in the track request section:
<TelemetryModules>
<Add Type="Microsoft.ApplicationInsights.Web.RequestTrackingTelemetryModule, Microsoft.AI.Web">
<Handlers>
<Add>System.Web.Handlers.TransferRequestHandler</Add>
<Add>Microsoft.VisualStudio.Web.PageInspector.Runtime.Tracing.RequestDataHttpHandler</Add>
<Add>System.Web.StaticFileHandler</Add>
<Add>System.Web.Handlers.AssemblyResourceLoader</Add>
<Add>System.Web.Optimization.BundleHandler</Add>
<Add>System.Web.Script.Services.ScriptHandlerFactory</Add>
<Add>System.Web.Handlers.TraceHandler</Add>
<Add>System.Web.Services.Discovery.DiscoveryRequestHandler</Add>
<Add>System.Web.HttpDebugHandler</Add>
</Handlers>
</Add>
</TelemetryModules>
The reason is that AI SDK automatically track requests for you, and therefore you get dups (the one w/o your properties is the one created automatically).
As PeterBons suggested, using Telemetry Initializer you can add the properties to the auto-generated request.

Accessing Session via ICacheClient during unit testing ServiceStack Service

We've got a ServiceStack 3.9.x service that we're trying to unit test end-to-end (via an in-process service host and accessing it via C# native clients), and we're running into a snag where it seems that the session is not accessible via the means we typically use to access it when running this way.
We typically access the current session (using servicestack's built-in system and custom AuthSession and providers, which all works fine running in IIS against an AppHost derived from AppHostBase) using this:
EndpointHost.AppHost.TryResolve<ICacheClient>().SessionAs<SsoUserSession>();
However, when trying to access this in unit testing (against an AppHost derived from AppHostHttpListenerBase), we get an exception thrown trying to get at the session: "Only ASP.NET Requests accessible via Singletons are supported" which appears to be a hard-coded error in the SessionFeature.
So the question is this: can one access sessions via the cache provider when unit testing via a service host derived from AppHostHttpListenerBase? And if so, how?
I've run into this before too.
The way I handle it is create create something like an extension method to get the session from the cache client that just calls the base, but before calling the base..check the IoC container for the session first. If it's there, just use that instead, and I just inject the session I want to use when testing.
This is used somewhere in servicestack but I can't seem to find the method that does it...anyway an extension method could look something like this
public static MyTypedSession GetMyTypedSession(this ICacheClient cache)
{
var typedSession = ServiceStackHost.Instance.Container.TryResolve<MyTypedSession>();
if (typedSession != default(MyTypedSession))
return typedSession;
return cache.SessionAs<MyTypedSession>();
}
Then instead of calling SessionAs in your code to get the typed session, you would just call GetMyTypedSession, and it would work fine for testing, so long as you Register your fake MyTypedSession
Here's some c# psuedo test method
public void SomeTestMethod()
{
var session = new MyTypedSession { IsAuthenticated = true; };
//get your container and register the session
container.Register(session);
var someValue = TestCodeThatUsesASession();
Assert(someValue);
}
I'm unsure what kinda delay looking in the IoC container everytime you need a session is though.
Sorta strange to add that code just for testing but oh well, works for me and save me time :).

Can i create OwinMiddleware per request instead creating a global object

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

Categories