I have a class in c# to help me log errors (ErrorClass).
The class has 3 methods. Log Error to: File System, Windows Event,
Email.
2 of the 3 methods require settings like "to email", or "directory path".
Settings are stored in the registry
I use dependency injection to instantiate the RegistryClass inside the ErrorClass
.
This is how I instantiate the ErrorHandle Class inside the Registry Class
ErrorHandle _ErrorHandle = new ErrorHandle();
And here is how I instantiate the Registry Class inside the ErrorHandle Class
RegistryTools _GetRegistry = new RegistryTools();
I have a class to help me retrieve values from the registry (RegistryClass)
The registry class needs to handle errors
I use dependency injection to instantiate the errorClass inside the RegistryClass
When I use dependency injection in both classes, an Endless LOOP is created when there is an error.
What is the suggested way or best practice of handling this situation:
Should I access the registry inside the ErrorClass?
Should I not ErrorHandle the RegistryClass?
Should I create a separate ErroHandle procedure for the
RegistryClass?
Don't re-invent this wheel. There is a tried and tested open source logging framework for .NET available, log4net. If you feel the need to use DI with it, you can do that too. log4net uses an XML file for configuration, which is much more accessible and less fraught with peril than dealing with the registry. It also swallows its own errors and makes them accessible via a debugging trace.
What mechanism are you using for DI? If you use setter injection there should be nothing to stop you doing something like:
var logger = new ErrorClass();
var registry = new RegistryClass();
logger.Registry = registry;
registry.Logger = logger;
Related
I am trying to determine which instance of my multi-instance UWP application should be activated based on the argument passed to it:
var instances = AppInstance.GetInstances();
if (instances.Count() != 0)
{
instances[0].RedirectActivationTo();
}
I have tried placing the code in app.xaml.cs (OnActivated) and main.xaml.cs (OnNavigatedTo) and they both throw the "The group or resource is not in the correct state to perform the requested operation." error for which there appears to be no documentation.
How can I redirect the activation to a current instance?
The AppInstance class should be used in a main method. This is mentioned in the document: The AppInstance class is intended to be used in the Main method of the app. If this class is used later, the property values may be null, and the methods may fail.
To create a main method of UWP app, you will need to disable the defaulted main method which is generated automatically first. Please right click on your project and choose properties, in the Build tab, add DISABLE_XAML_GENERATED_MAIN to the Conditional Compilation Symbols.
Then you could add a new static class to your project and add a new static main mehtod in the class.
I found a blog which have detailed steps about how to use AppInstance.RedirectActivationTo method, you could take a look at: Multiple instances support for UWP apps (Part 2): Redirection
Besides if you want to redirect to an existing instance, it will be better to register the instance first.
I have built a python library that uses C# code(which is built and stored as a dll), using pythonnet. In that library, I generate logs using the python logger.
mylibrary.py
logger = logging.getLogger('mylibrary')
logger.info('logging from my library')
The root logger is configured from the user code. For example, the handlers for the root logger is set by the user using logger's "addhandler()" method specifying the format, output file etc. Inside my library, I just log (logger.info()...) without configuring anything and the root handler set by the user takes care of writing this to the file.
usercode.py
root_logger = getLogger()
root_logger.addHandler(FileHandler('abc.log'))
root_handler.setFormat(...)
The user can control what my library can log by setting the level of the logger used by my library. The line below in usercode.py sets the logging level of my library's logger to critical so that the library can't log anything below it (logger.info() won't get into abc.log).
getLogger('mylibrary').setLevel(CRITICAL)
The problem comes now. Since I am using C# code in my library,
I want to capture the C# logs into abc.log
I also want to configure the C# log just like I did for python logs
So the the line
getLogger('mylibrary').setLevel(CRITICAL)
in usercode.py should now make sure that only the critical logs in both the python as well as C# get into abc.log
Is there a way to achieve this?
No, you cannot log from both Python and C# at the same time to the same file. The reason for this is that Python's logging (and likely the C# logging too) is not equipped for concurrent logging - even if the log file is not 'locked' by one of them, there is a chance of getting different logs mixed together due to multiple writers.
If you do not own the C# dll you're probably out of luck - unless it would allow you to configure the log file/level from a C# program, there is no magic that Python can do to fix it. However, if you control the source and can build a new dll, consider changing the C# class to allow you to pass in a delegate/lambda (assuming this is implemented in PythonNet), which will simply call back into Python's logger function.
Example:
c# code:
public class CoolImportedFeature
{
private readonly Action<string> LogCallback;
public CoolImportedFeature(string inputA, int inputB, Action<string, string> logCallback)
{
LogCallback = logCallback;
// do other constructor stuff
}
public void SomeMethod()
{
// do something
LogCallback("critical", "An error occurred");
}
}
python code:
def log_callback(log_level, message):
getattr(logger, log_level)(message)
import CoolImportedFeature
feat = CoolImportedFeature("hello", 1, log_callback)
feat.SomeMethod()
Something like that - there is no magic translation between Python's log levels and C#'s, so you will need to do some translation there (or the getattr reflection I used above).
Currently in my personal website I'm building I'm using a global static Config class to hold everything configurable I might need to change that is semi-global. So right now it looks about like this:
public static class Config
{
public static string ConnectionString = "mongodb://localhost";
//more configuration options..
public static MongoDB.Driver.MongoDatabase GetDB(){
MongoServer server = MongoServer.Create(Config.ConnectionString);
MongoDatabase db = server.GetDatabase(Config.Database);
return db;
}
public static Markdown GetMarkdown(){
var options=new MarkdownOptions(){
AutoHyperlink=true,
AutoNewlines=false,
EmptyElementSuffix=" />",
LinkEmails=false,
StrictBoldItalic=true
};
var m=new Markdown(options);
return m;
}
}
Is using a global config class like this an anti-pattern of some sort? Also, I prefer for my connection strings to be outside of web.config. I like my web.config to be as minimal as possible.
Well of the 3 members only 1 is really config, the other two are utility really.
Having configuration in compiled code is really a pain to maintain if those configs need to be changed, since it requires a rebuild, that is really the reason for configuration files.
I do things similar to this but not for settings like connection strings. If the connection string needs to change, you need to update and rebuild your project. If you stored the connection string in your web.config, a simple update allow your app to immediately use the new setting (no recompile).
Earlz ,
Regarding your second question you can do something like this, there is no need to have all the connections or configs in web.config. You can have a separate config file and point that in the web.config file as below
<connectionStrings configSource="config\yourpath\connectionStrings.config"/>
Regarding the first question , write a common method which get the values. Load all the values to a constants file and write a helper class to get those values
The anti-pattern is that you have GetMarkdown and ConnectionString together in the same class because they are both static, yet they really have no functional relationship. GetMarkdown and GetDB both look like factory methods and they should probably be in their own classes.
The Single Responsibility Principle says you should group things together that are likely change for the same reason. It's unlikely that your database connection and markdown config will change at the same time or for the same reason.
We moved our config settings to the database. Makes it easier when moving from Dev to QA to Prod. The blog entry is here.
Related to this, we put the connection string off to the side in a WebEnvironment.config. So now we can promote our code with web.config changes and not worry about the connection string. That blog post is here.
I was recently studying documentation on TraceSource. Microsift says that TraceSource is a new way and should be used instead of old Trace class.
// create single TraceSource instance to be used for logging
static TraceSource ts = new TraceSource("TraceTest");
// somewhere in the code
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
Now my question. You have large project with several assemblies where you have lots of classes. Say you wanna trace specific bit of functionality that is spread across classes. Obvious idea is that you need to create one specific TraceSource .
1) To work with Tracesource I need to create instance first. What is MS thinking about sharing this instance across various classes or assemblies? Should I create one dummy class with static singleton property? What are you doing in that case.
2) Why do I need TraceSource instance? Every propery is described in the configuration file. The old logic based on Trace class did not require some instance and provided the way to work with static methods only.
*1. Just define the TraceSource in each class where you want to use it. You can make the TraceSource static so that it shared among all instances of the class you define it in. No need to share the instance among all classes (types) that need the "same" TraceSource. Each time you decleare a new TraceSource (TraceSource ts = new TraceSource("somename"); instance, you get a new TraceSource object, but it references the same config information. So, if you create a new TraceSource in each of several classes and you use the same name for each one, you will get different instances of TraceSource, but they will all be configured the same. In short, there is no need to try to share the TraceSource instances among classes. There is also no need to create a dummy class with a static singleton. See my examples below. I have also included several more links from here on SO that describe how to work with TraceSources.
//
// In this example, tracing in classes A and B is controlled by the "TraceTest" TraceSource
// in the app.config file. Tracing in class C is controlled by the "TraceTestTwo"
// TraceSource in the app.config.
//
// In addition to using different TraceSource names, you can also use SourceSwitches
// (in the app.config). See some examples of app.config in the
// "turning-tracing-off-via-app-config" link below.
//
public class A
{
private static readonly TraceSource ts = new TraceSource("TraceTest");
public void DoSomething()
{
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
}
}
public class B
{
//
//Use the same config info for TraceTest in this class
//It's ok to use a different instance of TraceSource, but with the same name,
//in this class, the new instance will be configured based on the params in the
//app.config file.
//
private static readonly TraceSource ts = new TraceSource("TraceTest");
public void DoSomething()
{
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
}
}
public class C
{
//
//Use a different TraceSource in this class.
//
private static readonly TraceSource ts = new TraceSource("TraceTestTwo");
public void DoSomething()
{
ts.TraceEvent(TraceEventType.Warning, 2, "File Test not found");
}
}
*2. One benefit to using multiple TraceSources is that you have more granular control over your tracing. You can trace via "TraceTest" at one level (or not at all) and via "TraceTestTwo" at a different level (or, again, not at all). You can send each TraceSource to its own TraceListener or send all to the same TraceListener, or mix and match. Compare the ability to tailor the configuration of individual TraceSources to the limitation of only using the static methods on the Trace class. You can configure where the "trace" information goes (which TraceListener(s)) or the level of the "trace" information, but you cannot control the level per class or per functional area like you can when using TraceSources. Finally, one more benefit to multiple TraceSources is the "free" context information that you can get in your output. By default (or optionally, I can't remember), the TraceListener will log the name of the TraceSource that logged a message. So, you can look at that line in your output and get some idea of the class or functional area where it came from without having to put a log of contextual information in the call site. In the code examples above, the trace output from classes A and B will be tagged with "TraceTest" and the trace output from class B will be tagged with "TraceTestTwo".
Please forgive the link bombardment below, but I have posted some pretty good information (if I do say so myself!) about TraceSource and System.Diagnostics in the past.
If you are going to use TraceSource, consider using the library mentioned in this SO post for formatting your output like log4net/NLog:
Does the .Net TraceSource/TraceListener framework have something similar to log4net's Formatters?
See my answer in this post for more info on using TraceSource and some ideas on how you can improve your "TraceSource experience".
More info on TraceSource: Add Trace methods to System.Diagnostics.TraceListener
More info on TraceSource: System.Diagnostics.Debug namespace vs Other logging solutions (log4net, MS Enterprise Library, etc.)
More info on TraceSource: Turning tracing off via app.config
I want to initialize a user configuration through a user configuration file. The path for the file can be read from the registry.
The file is located in a folder with the user's name.
So I need the following functionality:
Reading a string from registry
building the path to the configuration file
Reading the file into a configuration object
Now there are several approaches to handle this:
First, I need
one "helper"-class for getting the file path (let's call it Shared)
one "container"-class for the configuration information (let's call it Configuration)
So, Shared has a function/property like UserConfigurationFile which returns the path to the configuration file.
To get the path to the file I have a function InitializeUserConfigurationFile() which is called in the constructor of Shared:
class Shared {
public Shared()
{
InitializeUserConfigurationFile();
}
void InitializeUserConfigurationFile()
{
//
// Reads username
//
//
// Reads path from Registry
//
//
// etc.
//
}
//
// etc.
//
}
Any better suggestions?
When I want to Initialize my Container I have different options:
Is it best to initialize the user configuration within the constructor?
Sth. like:
class Container
{
Shared shared = new Shared();
public Container()
{
InitializeUserConfiguration();
}
void InitializeUserConfiguration()
{
LoadConfiguration(shared.UserConfigurationFile);
}
void LoadConfiguration(string filename)
{
//
// Initializes all parameters frome filename
//
}
}
Or through two steps (through an own method LoadConfiguration())?
Sth. like:
Shared shared = new Shared();
Container container = new Container();
container.LoadConfiguration(shared.UserConfigurationFile);
Or inside the constructor of Container by delivering a filename?
Sth. like:
Shared shared = new Shared();
Container container = new Container(shared.UserConfigurationFile);
or everything in Container..?
There are so many ways...
I hope somebody knows a best-approch...
Regards,
Inno
It is better to use standard configuration classes exist in .net. Such as ApplicationSettingsBase and Configuration.
Here you can find good article series:
Unraveling the Mysteries of .NET 2.0 Configuration
Unraveling the Mysteries of .NET 2.0 Configuration
Cracking the Mysteries of .NET 2.0 Configuration
For best practices, don't use the registry, and don't reinvent the wheel.
Since you didn't mention it, have you looked at the System.Configuration namespace?
The .NET Framework constains a perfectly good configuration system that is well tested. It is also the domain of Sys Admins, who also know about config files and the accompanying tools.
So it is unclear why you are reinventing the wheel, possibly making it a little less round.
There are practical reasons to shun the Registry (distribution, backup) but also, as arbiter points out, it is not going to move to other (future) platforms. Did you notice that those namespaces are not starting with System ?