How to implement structured logging when using NLog in wrapper class - asp.net

I am having trouble figuring out how I can use the structured logging, when NLog is in a wrapper class. I have an asp.net webapp that calls my nlog wrapper class.
It works fine for regular logging ex. logger.Info("Gets to here.") but i can't get it to work for structured logging calls ex. logger.Info("This is structured logging entry #{param1}", new {Status = "processing"})
This is my Wrapper class for NLog(EventLog.LogManager):
public static void Info(params object[] args)
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
Logger.Log(LogLevel.Info, args);
//This is what I've tried to no avail.
//var ci = new CultureInfo("en-US");
//LogEventInfo le = LogEventInfo.Create(LogLevel.Info, Logger.Name, ci, args);
//le.Parameters = args;
//string test = le.FormattedMessage;
//string test1 = string.Format(le.Parameters[0].ToString(), le.Parameters[1].ToString());
//Logger.Log(typeof(LogManager), le);
}
This is my asp.net application that calls the above method:
public ActionResult Index()
{
EventLog.LogManager.Info("Test #{param1}", new { OrderId = 2, Status = "Processing" });
return View();
}
If anyone can point me in the right direction, it would be greatly appreciated. Thank you in advance.

Try changing into this:
namespace EventLog
{
public static class LogManager
{
private static readonly NLog.Logger Logger = NLog.LogManager.GetCurrentClassLogger();
public static void Info(string message, params object[] args)
{
Logger.Info(message, args);
}
}
}

Related

resultCode is 0 for all requests in Application Insights

I have a function app connected with an application insights instance.
When I look at the requests on application insights, all entries have a resultCode of 0, regardless of whether it was successful or not. How can I have the resultCode showing properly?
If I get it correctly, my function app is running at the version "3.0.14916.0".
Here is my startup:
public class Startup : FunctionsStartup
{
public override void Configure(IFunctionsHostBuilder builder)
{
builder.Services.AddLogging(loggingBuilder =>
{
var key = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
loggingBuilder.AddApplicationInsights(key);
});
builder.Services.AddSingleton(sp =>
{
var key = Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY");
return new TelemetryConfiguration(key);
});
(...)
}
}
Edit 1:
In the comments it was asked why I am adding logging in Startup. I do it because, as far as I could verify, ILogger < MyClass > only logs to AI if I add logging in Startup.
Following is an example of an injected class. Note that this class is also used in other projects.
public class CosmosDbService : ICosmosDbService
{
private readonly IDocumentClient _documentClient;
private readonly ILogger _logger;
public CosmosDbService(IDocumentClient documentClient, ILogger<CosmosDbService> logger)
{
_logger = logger;
_documentClient = documentClient;
}
public async Task<UserData> GetUserAsync()
{
try
{
// Getting user here
// (...)
}
catch (Exception ex)
{
_logger.LogError(ex, "Error fetching user.");
throw;
}
}
}
This class is injected as:
builder.Services.AddSingleton<IDocumentClient>(sp =>
{
// This does not really matter for this question
var configuration = sp.GetService<IConfiguration>();
var connectionString = configuration.GetValue<string>("COSMOS_DB_CONNECTION");
var cosmosDbConnectionString = new CosmosDbConnectionString(connectionString);
return new DocumentClient(cosmosDbConnectionString.ServiceEndpoint, cosmosDbConnectionString.AuthKey);
});
builder.Services.AddSingleton<ICosmosDbService, CosmosDbService>();
This answer from #PeterBons helped me fixing the wrong resultCode as well.
Basically I was importing the wrong package: Microsoft.Extensions.Logging.ApplicationInsights
I changed it to Microsoft.Azure.WebJobs.Logging.ApplicationInsights and removed the code in Startup. Now I got the resultCode properly filled in again.

Mocking Delegate Factories in Service Libraries with Autofac and Moq

I have a simple console application which uses Autofac as IoC container.
class Program
{
static IContainer container;
static void Main(string[] args)
{
container = Configure();
Run();
}
private static void Run()
{
using (var scope = container.BeginLifetimeScope())
{
var t = scope.Resolve<ITest1>();
var s = t.TestMethod1("");
Console.WriteLine(s);
}
}
private static IContainer Configure()
{
var builder = new ContainerBuilder();
builder.RegisterType<TestClass1>()
.As<ITest1>();
builder.RegisterType<TestClass2>()
.As<ITest2>();
return builder.Build();
}
}
The application calls the method "TestMethod1" in "TestClass1".
public interface ITest1
{
string TestMethod1(string s);
}
public class TestClass1 : ITest1
{
ITest2 f;
public TestClass1(Func<ITest2> test2Factory)
{
f = test2Factory();
}
public string TestMethod1(string s)
{
var r = string.Empty;
r = f.TestMethod2(s);
r += ":TestMethod1";
return r;
}
}
TestClass1 has a dependency on TestClass2 which declares a delegate factory for Autofac to use with the TestClass1 constructor.
public interface ITest2
{
string TestMethod2(string s);
}
public class TestClass2 : ITest2
{
public delegate TestClass2 Factory();
public virtual string TestMethod2(string s)
{
return ":TestMethod2";
}
}
This all works as expected - Autofac resolves the TestClass2 dependency, and I get the output ":TestMethod2:TestMethod1".
Now I want to mock TestClass2 using Moq and the Autofac.Extras.Moq extensions. I add the following method to the console application, and call it from the Program Main method.
private static void Test()
{
using (var mock = AutoMock.GetLoose())
{
mock.Mock<TestClass2>()
.Setup(t => t.TestMethod2(""))
.Returns(":NOT_TEST_METHOD2");
var s = mock.Create<TestClass1>();
var r = s.TestMethod1("cheese");
Console.WriteLine(r);
}
}
Now I get the output ":TestMethod1" when I expect ":NOT_TEST_METHOD2:TestMethod1". It seems the mock has not been called. This is confirmed when I step through the code.
I have also tried resolving the mock using mock.Provide(), as has been suggested elsewhere (see below). Still no luck.
var wc = Moq.Mock.Of<TestClass2>(f => f.TestMethod2("") == ":NOT_TEST_METHOD2");
Func<string, ITest2> factory = x => wc;
mock.Provide(factory);
This seems like a really simple scenario but I've not found a working answer anywhere. Can anyone see what I'm doing wrong?
Thanks for any help!
I don't use the AutoMock support, but I do know my Autofac, so I can give it a shot.
It looks like TestClass1 takes an ITest2 and not a TestClass2 in its constructor, I'm guessing if you switched to this:
mock.Mock<ITest2>()
.Setup(t => t.TestMethod2(""))
.Returns(":NOT_TEST_METHOD2");
...then it might work.
Thanks Travis. Your suggestion didn't work for me, but it made me think about the issue differently and taking a step back made me realise I was looking for a complex solution where one wasn't required. Namely, that only Moq was needed, Autofac AutoMock extensions were not. The following code worked:
private static void Test()
{
Func<ITest2> func = () =>
{
var x = new Mock<ITest2>();
x.Setup(t => t.TestMethod2("")).Returns(":NOT_TEST_METHOD2");
return x.Object;
};
var s = new TestClass1(func);
var r = s.TestMethod1("");
}
The question was answered by this post Using Moq to Mock a Func<> constructor parameter and Verify it was called twice.

execute class library dll from url browser

i'm building a class library project using c# to scale/resize images,the project only has one class with only one public static function with 2 parameters now the code is working fine and perfect so its not the issue here.
now, how can i execute this function directly from url?
ex:my project called: myDLL.dll
how to do this:
img src="/myDLL.dll?image=/images/pic1.png&width=200"
so this execute my function and pass width and image as parameters
i know how to add iis handler to execute DLL from browser..but i dont know how to make this :/myDLL.dll?image=/images/pic1.png&width=200 run my function
plz help
Yes, you can.
HTTP Handler
public class Class1 : IHttpHandler
{
public bool IsReusable => false;
public void ProcessRequest(HttpContext context)
{
Assembly ass = Assembly.LoadFile(context.Request.PhysicalPath);
Type[] assemblyTypes = ass.GetTypes();
for (int j = 0; j < assemblyTypes.Length; j++)
{
if (assemblyTypes[j].Name == "WebDLL")
{
object o = Activator.CreateInstance(assemblyTypes[j]);
MethodInfo mi = assemblyTypes[j].GetMethod("ProcessRequest");
mi.Invoke(o, new object[] { context });
}
}
}
}
DLL
public class WebDLL
{
public void ProcessRequest(HttpContext context)
{
context.Response.Write("Hello World!");
}
}
It will output Hello World!

What is the good way to execute JobSchedule with Quartz.Net and Asp.Net application?

I have a trouble with my ASp.net application, I have tested several solutions but I don't see any issue on it. Thanks by advance for your advice.
I have installed and running Quartz.Net as a Windows Service. Quartz.Net is in the same folder as my API in order to execute jobs in it.
Below my global.asax Application_Start
public static ISchedulerFactory schedFact;
public static IScheduler scheduler;
protected void Application_Start()
{
NameValueCollection properties = new NameValueCollection();
properties["quartz.scheduler.instanceName"] = "ServerScheduler";
properties["quartz.scheduler.proxy"] = "true";
properties["quartz.threadPool.threadCount"] = "10";
properties["quartz.scheduler.proxy.address"] = "tcp://localhost:555/QuartzScheduler";
schedFact = new StdSchedulerFactory(properties);
scheduler = schedFact.GetScheduler();
scheduler.Start();
MyAPI.Services.ScheduleTasks.JobScheduler.StartGenerateContract();
}
Here the class where my jobs are scrippted:
public class ScheduleTasks
{
public static Dictionary<string, string> report;
public class JobScheduler
{
public static void StartGenerateContract()
{
try
{
MailService.SendMail("StartGenerateContract", "Scheduletask",
new Exception(DateTime.Now.ToString()));
IJobDetail job_generate = JobBuilder.Create<GenerateAndSendContract>()
.WithIdentity("generateContractJob", "group1")
.Build();
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger_contracts", "group1")
.ForJob("generateContractJob", "group1")
.StartNow()
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(01, 00))
.Build();
MyAPI.MvcApplication.scheduler.ScheduleJob(job_generate, trigger);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
}
}
Then my job that is in the same file and class ScheduleTasks
public class GenerateAndSendContract : IJob
{
public void Execute(IJobExecutionContext context)
{
try
{
MailService.SendMail("GenerateAndSendContract", "Scheduletask");
//my working code...
}
catch (Exception e)
{
MailService.SendErrorMail("GenerateAndSendContract", "ScheduleTasks", e);
}
}
}
My scheduleTask is perfectly executed because I receive the first email (StartGenerateContract), with the good interval. But the job is not executed cause the code in the class generateandsendcontract is not fired (no break point, no mail GenerateAndSendContract send).
Anything wrong in my code? Thank you for your help.
When creating the scheduler on the MVC app side, you just need these properties:
properties["quartz.scheduler.instanceName"] = "RemoteClient";
properties["quartz.scheduler.proxy"] = "true";
properties["quartz.threadPool.threadCount"] = "0";
properties["quartz.scheduler.proxy.address"] = address;
You also don't need to call the Start method on the scheduler that is acting as the client.

Couldn't get Ninject-Interception via Attributes to work, what did I do wrong?

I'm trying build out our logging framework using EntLib Logging and use attribute to indicate which class/method should be logged. So I think Interception would be a good choice. I'm a super noob to Ninject and Interception and I's following the tutorial at Innovatian Software on how to use interception via attributes. But when I run the app, BeforeInvoke and AfterInvoke was never called. Help Please, Thank You!
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Castle.Core;
using Ninject;
using Ninject.Extensions.Interception;
using Ninject.Extensions.Interception.Attributes;
using Ninject.Extensions.Interception.Request;
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Bind<ObjectWithMethodInterceptor>().ToSelf();
var test= kernel.Get<ObjectWithMethodInterceptor>();
test.Foo();
test.Bar();
Console.ReadLine();
}
}
public class TraceLogAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<TimingInterceptor>();
}
}
public class TimingInterceptor : SimpleInterceptor
{
readonly Stopwatch _stopwatch = new Stopwatch();
protected override void BeforeInvoke(IInvocation invocation)
{
Console.WriteLine("Before Invoke");
_stopwatch.Start();
}
protected override void AfterInvoke(IInvocation invocation)
{
Console.WriteLine("After Invoke");
_stopwatch.Stop();
string message = string.Format("Execution of {0} took {1}.",
invocation.Request.Method,
_stopwatch.Elapsed);
Console.WriteLine(message);
_stopwatch.Reset();
}
}
public class ObjectWithMethodInterceptor
{
[TraceLog] // intercepted
public virtual void Foo()
{
Console.WriteLine("Foo - User Code");
}
// not intercepted
public virtual void Bar()
{
Console.WriteLine("Bar - User Code");
}
}
I figured it out, I missed the part where I've to disable auto module loading and manually load the DynamicProxy2Module to the kernel. Here's the change to the code:
//var kernel = new StandardKernel(); //Automatic Module Loading doesn't work
var kernel = new StandardKernel(new NinjectSettings() { LoadExtensions = false }, new DynamicProxy2Module());
Hope this help someone else.

Resources