how to reduce line number with passing parameter to static constructor - c#

I know parameters cant pass to static constructor. But I am using this static class with parameters hence I initialize a variable I have to duplicate lines for each useage of this class functions
here is my logger class(it uses log4net, but its not in case):
public static class Logger
{
private static ILog log {get; set;}
static Logger()
{
log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
public static void Error(object msg, string userip)
{
log4net.LogicalThreadContext.Properties["ClientIp"] = userip;
if (log.IsErrorEnabled)
{
log.Error(msg);
}
}
public static void Error(object msg, string userip, Exception ex)
{
log4net.LogicalThreadContext.Properties["ClientIp"] = userip;
if (log.IsErrorEnabled)
{
log.Error(msg, ex);
as you think I have to add custom "ClientIp" field for all kind of log methods. but I dont want to repeat
log4net.LogicalThreadContext.Properties["ClientIp"] = userip;
line for each method
I wish I can edit the constructor like this:
static Logger()
{
log4net.LogicalThreadContext.Properties["ClientIp"] = userip;
log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
but I cant pass parameter to static constructor.. any advice ?

Create an Initialize method which you will call only once: at startup. Pass in the variables you need to set only once. In all subsequent calls, you can reuse those values.

Related

Automatically passing own type to function call

I'd like to pass a value when calling a function but want to omit to actually add it as a parameter.
To be more precise I'd like to write a logger that also prints which class called the logging function but don't want to always pass a "this" as a parameter.
Example code:
class static Logger{
public static void LogMsg(string msg, object objectCalling){
Print(objectCalling.GetType().Name + ": " + msg);
}
private void Print(string msg){
// print it
}
}
class SomeClass{
private void WriteTestLog() {
Logger.LogMsg("Testing!");
}
}
This should then create an output like: "SomeClass: Testing!"
I am not sure how to tackle this maybe I am just missing sth.
There are a few attributes which might be helpful:
CallerMemberNameAttribute: the name of the calling method or property;
CallerFilePathAttribute: the file path where the calling member is in;
CallerLineNumberAttribute: the line number within the file.
As you see, there is no attribute for the class name, but with the file path you might achieve the same level of information.
How to use this? Decorate an argument in your logging method with the attribute (of course, using the correct type and default).
public static void LogMsg(string msg, [CallerMemberName] string callingMember = null)
{
Print($"{callingMember}: {msg}");
}
And just call:
LogMsg("hello!");
You can use System.Runtime.CompilerServices with it's CallerMemberNameAttribute
Here is example:
using System;
using System.Runtime.CompilerServices;
namespace ConsoleApp3
{
class Program
{
static void Main(string[] args)
{
Logger.WriteLog("Hello");
}
}
public class Logger
{
public static void WriteLog(string msg, [CallerMemberName] string methodName="")
{
Console.WriteLine("Method:{0}, Message: {1}",methodName,msg);
}
}
}
You could create an extension method to do that as well as the answers above :
void Main()
{
SomeClass x = new SomeClass();
x.WriteTestLog();
int i = 1;
i.LogMsg("abc");
}
public static class Logger
{
public static void LogMsg(this object objectCalling, string msg)
{
Print(objectCalling.GetType().Name + ": " + msg);
}
private static void Print(string msg)
{
Console.WriteLine(msg); // print it
}
}
public class SomeClass
{
public void WriteTestLog()
{
this.LogMsg("Testing!");
}
}
If you really wish to extract the caller's type you can play with the stack trace:
[MethodImpl(MethodImplOptions.NoInlining)]
public static void LogMsg(string msg)
{
var caller = new StackTrace().GetFrames()[1].GetMethod();
Console.WriteLine($"{caller.DeclaringType}.{caller.Name}: {msg}");
}
But keep in mind that extracting the caller from the stack trace is a very expensive operation. Besides despite of the NoInlining it is not guaranteed that in an optimized build the caller itself is not inlined. I do not recommend to use it in a release build or if performance matters.

Initializing a log object for all classes

I have a winforms application with lot's of classes, and in every class I need to write to a log if something goes wrong.
Today I made a logger function that I initialize in every class object for using it inside.
For example I have a main logic class that have log and one more class that's running different logic that should have a log.
Today I am using:
Initialize log object in class contractor for working with it.
passing log object to the contractor.
what will be the best architecture for initialize it one time and use it in every class (Not doing it static).
My logger class:
namespace MyLogger
{
public class Logger : IMessageLogger
{
IMessageLogger _messageLogger;
public Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
public interface IMessageLogger
{
void Log(string message);
}
public class FileLogger : IMessageLogger
{
string _filePath = Environment.CurrentDirectory;
public string filePath
{
get { return _filePath; }
set { _filePath = value; }
}
public FileLogger(string filePath)
{
_filePath = filePath;
}
public void Log(string message)
{
string strFileName = Path.Combine(_filePath, String.Format("{0}{1}.log", _filePath, DateTime.Now.ToString("yyyyMMdd")));
using (StreamWriter writer = new StreamWriter(strFileName, true))
{
writer.WriteLine(DateTime.Now.ToString("[dd/MM/yyyy hh:mm:ss]") + " -> " + message);
};
}
}
public class ConsoleLogger : IMessageLogger
{
public void Log(string message)
{
Console.WriteLine(message);
}
}
}
I believe the best way is to implement it via DependencyInjection, you should read about it online.
But if you want a quick and easy solution, simply implement a Singleton pattern for your logger, like such -
public class Logger : IMessageLogger
{
private IMessageLogger _messageLogger;
private static Logger _instance;
public static Logger Instance
{
get
{
if (_instance == null)
{
// Pick one:
_instance = new Logger(new FileLogger("SomePath"));
_instance = new Logger(new ConsoleLogger());
}
return _instance;
}
}
private Logger(IMessageLogger messageLogger)
{
_messageLogger = messageLogger;
}
public void Log(string message)
{
_messageLogger.Log(message);
}
}
And to write a log use this line -
Logger.Instance.Log("This is a log message!");
There are two sides to my answer.
The first, to get the behavior you want, make the class and methods static. This creates one instance for the lifetime of your application and you can just use FileLogger.Log wherever you need it without having to new a new FileLogger up.I am not sure why you are adverse to using a static though, so you could get the same behavior with a singleton.
The second is that you should not be writing your own logger. There are so many good, open source options available. Look at log4net, nLog or even the built in TraceSource to save yourself the effort of re-inventing the wheel.

Type Initialization Exception c#

I looked on another question similar to this but couldn't quite understand what they did to solve the problem.
I am simply passing a value into a public static int:
namespace ModNote
{
public partial class homeScreen : Form
{
public homeScreen()
{
InitializeComponent();
}
private void gamemodButton_Click(object sender, EventArgs e)
{
backgroundProgram.moduleNumber = 1;
this.Hide();
moduleScreen showForm = new moduleScreen();
showForm.Show();
}
and this is where this variable is initialized
namespace ModNote
{
#region // Setting up Variables
public class backgroundProgram
{
public static int moduleNumber;
}
#endregion
}
and here a picture of the error: http://puu.sh/opETJ/fb8152d164.png
Thankyou.
edit: initializing the string array causes this error, any problems with this array being initialized? (moduleArray)
namespace ModNote
{
#region // Setting up Variables
public class backgroundProgram
{
public static int moduleNumber;
public static string[] noteArray;
public static string[] moduleArray = new string[7]
{ File.ReadAllText(#"ModulesFile\CGP1005M.txt"),
File.ReadAllText(#"ModulesFile\CMP1005M.txt"),
File.ReadAllText(#"ModulesFile\CMP1123M.txt"),
File.ReadAllText(#"ModulesFile\CMP1124M.txt"),
File.ReadAllText(#"ModulesFile\CMP1125M.txt"),
File.ReadAllText(#"ModulesFile\CMP1127M.txt"),
File.ReadAllText(#"ModulesFile\CMP1129M.txt")
};
}
#endregion
}
If the exception is throw here:
public static string[] moduleArray = new string[7]
{ File.ReadAllText(#"ModulesFile\CGP1005M.txt"),
File.ReadAllText(#"ModulesFile\CMP1005M.txt"),
File.ReadAllText(#"ModulesFile\CMP1123M.txt"),
File.ReadAllText(#"ModulesFile\CMP1124M.txt"),
File.ReadAllText(#"ModulesFile\CMP1125M.txt"),
File.ReadAllText(#"ModulesFile\CMP1127M.txt"),
File.ReadAllText(#"ModulesFile\CMP1129M.txt")
};
Then one of those lines is throwing an exception. There are all sorts of reasons for an exception to be thrown when reading from a file - security, not found, in use, etc.
I would suggest moving that logic to the static constructor so you can debug it to find the immediate problem, then add better error handling.
Another option is to not read all of that data in the static constructor and instead create an Initialize method or something. Exceptions in static constructors are difficult to handle in general.

C# Logging design: Extension method, alternatives?

I'd like to write a logger that can be easily appended to any class in my current project. For development, it will be convenient to log messages to the console, whereas in the final release I'd like to log to a file or something. One should be able to change the behavior by editing just a few lines of code, or ideally a settings file.
What I have so far is this class structure:
public interface ILogger {
void LogMessage(String message);
// ... other logging functions (exceptions, time etc.) don't matter here
};
public interface ILoggable { };
public static class LoggingProvider {
private static ILogger logger = ConsoleLogger.handle;
public static void LogMessage(this ILoggable obj, String message) {
logger.LogMessage(message);
}
}
public sealed class NullLogger : ILogger {
// A logger that does nothing..
};
public sealed class FileLogger : ILogger {
// A logger that writes to a file..
};
public sealed class ConsoleLogger : ILogger {
#region Console Allocation
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool AllocConsole();
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool FreeConsole();
#endregion
#region Singleton implementation
private static Object cs = new Object();
private static ILogger instance = null;
private ConsoleLogger() {
AllocConsole();
}
~ConsoleLogger() {
FreeConsole();
}
public static ILogger handle {
get {
lock ( cs ) { if ( instance == null ) instance = new ConsoleLogger(); }
return instance;
}
}
#endregion
#region ILogger Member
public void LogMessage(string message) {
lock ( cs ) {
String logString = getTimeString();
logString += ( " -> \t " + message );
Console.WriteLine(logString);
}
}
#endregion
#region Helper functions
// ...
#endregion
};
Now, I can have any class I'd like to implement ILoggable, and via the Extension Method LogingProvider.LogMessage I can call this.LogMessage("...") within these classes. If it was C++, I'd just use private inheritance instead.
Is this now good or bad design? Anything I can improve? Is there a way to provide classes with logging functionality without the extension method, but with similarly few changes?
Your design seems a bit over-engineered at first sight. In this method:
public static void LogMessage(this ILoggable obj, String message) {
logger.LogMessage(message);
}
the ILoggable obj is not used at all. Why do you need it then? Why not just have:
public static void LogMessage(String message) {
logger.LogMessage(message);
}
and call it LoggingProvider.LogMessage(...)?
On a side note, take a look at Log4Net, this is the industry standard implementation of logging functionality.

Instantiating a delegate method to be used in a class library

I'm building an email-monitoring framework that I'll be using for a handful of users, so I'm building a class library to wrap everything in. I'm instantiating the configuration (sender, subject, last-received, ...) in a static class. Therefore, I have something like this.
public static class MyConfig
{
public static int Sender { get; set; }
// and so on and so forth
public static void BuildMyConfig(string theSender, string theRecipient, ...)
{
Sender = theSender;
// yada yada yada...
}
}
public class Monitoring
{
public delegate void DoSomethingWithEmail(EmailContents theContents);
public void StartMonitoring() {
//When I get an email, I call the method
DoSomethingWithEmail(theEmailWeJustGot);
}
}
Obviously, what we do with the email will be something completely different in each case. What I'm trying to is instantiate that delegate. Where would I do that? The MyConfig class and then invoke it from there as a static method? The instance of the Monitoring class?
An application would look like...
public class SpecificMonitor
{
Monitoring.BuildMyConfig("foo#bar.com", "bar#foo.com", ...);
Monitoring m = new Monitoring();
m.StartMonitoring();
//But where do I build the delegate method???
}
I've gotten compiling errors with every option I've tried so far. I've also tried overriding a method instead of using a delegate, using interfaces... but I think delegation is where it's at.
Thanks in advance!
Consistent with the rest of your design (although I do not necessarily agree that the design is great) you could allow for the callback to be set in the configuration class
public static class MyConfig
{
public static string Sender { get; set; }
public static DoSomethingWithEmail EmailReceivedCallback { get; set; }
public static void BuildMyConfig(string theSender, string theRecipient,
DoSomethingWithEmail callback)
{
Sender = theSender;
EmailReceivedCallback = callback;
}
}
// Make sure you bring the delegate outside of the Monitoring class!
public delegate void DoSomethingWithEmail(string theContents);
When an incoming email is acknowledged by your application you can now pass the email to the callback assigned to the configuration class
public class Monitoring
{
public void StartMonitoring()
{
const string receivedEmail = "New Answer on your SO Question!";
//Invoke the callback assigned to the config class
MyConfig.EmailReceivedCallback(receivedEmail);
}
}
Here is an example of usage
static void Main()
{
MyConfig.BuildMyConfig("...", "...", HandleEmail);
var monitoring = new Monitoring();
monitoring.StartMonitoring();
}
static void HandleEmail(string thecontents)
{
// Sample implementation
Console.WriteLine("Received Email: {0}",thecontents);
}
Define the constructor so that when people instantiate a Monitoring object, they must define the delegate:
public class Monitoring
{
public delegate void DoSomethingWithEmail(EmailContents theContents);
public Monitoring(Delegate DoSomethingWithEmail)
{
this.DoSomethingWithEmail = DoSomethingWithEmail;
}
public void StartMonitoring() {
//When I get an email, I call the method
DoSomethingWithEmail(theEmailWeJustGot);
}
}
Then pass in the delegate you want when you instantiate each Monitoring:
Monitoring m = new Monitoring(delegate(EmailContents theContents)
{
/* Do stuff with theContents here */
});
m.StartMonitoring();

Categories

Resources