Simulate file with NLog (create virtual filesystem path) - c#

I use NLog (with logentries.com) for logging in my WPF app, but some external components of my app accepts only filesystem path as log output. It is possible, to create "virtual path/file" which will be associated with NLog and every line appended to this "virtual file" will be routed directly to the Nlog (and then to logentries.com)?
Currently I'm using temporary file on disk, monitor changes of this file and resends updated content to the NLog, but it's not very effective.

I think you should write a custom target for that. It's only a few lines!
[Target("MyFirst")]
public sealed class MyFirstTarget: TargetWithLayout
{
public MyFirstTarget()
{
}
protected override void Write(LogEventInfo logEvent)
{
string logMessage = this.Layout.Render(logEvent);
// TODO - write me logMessage to file
}
}
See a news post related to this.

There's a WP library we offer that can be used for sending log events to Logentries
le-windows-phone
Hope this helps!
Ardi
Logentries Support Engineer

Related

Read Settings from Dependent Project in C#

I just want to start by saying that I've done a lot of research but couldn't find an answer, hence the post.
I'm adding user settings functionality to my app which works as a plugin inside a common off the shelf program for architecture (called Autodesk Revit). The main project (let's call it MainProj) has several dependencies including a project that handles logging and usage (let's call it Loggers). I created a Settings file inside the Loggers project with the goal to have users change the logging level from Error to Debug when there are issues so I can ask them to make the change and send me the log.
The issue I'm facing is that when I change the log level directly inside the config file and re-run the command from within Revit, the change doesn't get translated into the log, as if the log level is somehow compiled during design and is never changed.
I actually tried to reproduce the problem in a simpler way and created a little console program and I'm facing the same issue. Below is the code from the Loggers project.
namespace Loggers
{
public static class Logger
{
public static string RunMe()
{
if (Properties.Settings.Default.LogMode == "Debug") { return "DEBUG"; }
else return "NOTHING";
}
}
}
I then changed the LogMode property from Debug to anything else in the config file but the console kept on returning DEBUG.
static void Main(string[] args)
{
Console.WriteLine(Logger.RunMe());
Console.Read();
}
I also tried changing the setting from user to application and editing its value in the config file and re-running the command but the outcome was the same.
Any help would be very much appreciated. I've been stuck on this for a while. Thank you.
Thanks to #BurnsBA, the link you shared had comments saying that the user.config lives in a different folder and it's not created until the user changes a setting. This made me understand that there wasn't a point in manually editing the app.config and expect the settings to work.
I then did some testing by creating a simple form with a checkbox linked to the Property I wanted to change and the user.config file gets created straight after I call the Save() method on the Properties.
private void btnOK_Click(object sender, EventArgs e)
{
if (chkDebugMode.Checked == true)
Loggers.Properties.Settings.Default.LogMode = "Debug";
else Loggers.Properties.Settings.Default.LogMode = "Error";
Loggers.Properties.Settings.Default.Save();
Close();
}

EventSource doesn't write logs in windows event viewer

I'm trying to write log in Windows event viewer. I created class and create method for catching exceptions. Here is my code :
[EventSource(Name = "Samples-EventSourceDemos-EventLog")]
public sealed class MinimalEventSource : EventSource
{
public static MinimalEventSource Log = new MinimalEventSource();
[NonEvent]
public void WriteLog(Exception exception)
{
UnhandledException(exception.Message);
}
[Event(601, Message = "Unhandled exception occurred. Details: {0}", Keywords = EventKeywords.None, Level = EventLevel.Critical)]
private void UnhandledException(string exceptionMsg)
{
this.WriteEvent(601, exceptionMsg);
}
}
static void Main(string[] args)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
throw new Exception("TestException");
}
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
{
MinimalEventSource.Log.WriteLog(e.ExceptionObject as Exception);
Process.GetCurrentProcess().Kill();
}
In Windows event viewer I couldn't find this log
I installed Microsoft.Diagnostics.Tracing.EventSource from nuget. It creates manifests after rebuilding. Here is debug folder
I decided to registr it by code :
string commandOfRegistringEventSource = "";
using (Process process = new Process())
{
ProcessStartInfo startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = commandOfRegistringEventSource
};
process.StartInfo = startInfo;
process.Start();
}
I tried execute using wevtutil.exe im <EtwManifestManFile> /rf:"<EtwManifestDllFile>" /mf:"<EtwManifestDllFile>", but it shows errors like The system cannot find the file specified.,... Please help me to write cmd command of registring EventSource. Here is manifest
C:\Users\dilshodk\source\repos\ETW loggiing\ETW loggiing\bin\Debug\ETW loggiing.Samples-EventSourceDemos-EventLog.etwManifest.dll
C:\Users\dilshodk\source\repos\ETW loggiing\ETW loggiing\bin\Debug\ETW loggiing.Samples-EventSourceDemos-EventLog.etwManifest.man
You need some more steps to get this working. First of all, you need to set the Channel property of the Event attribute like this:
[EventSource(Name = "Samples-EventSourceDemos-EventLog")]
public sealed class MinimalEventSource : EventSource
{
public static MinimalEventSource Log = new MinimalEventSource();
[NonEvent]
public void WriteLog(Exception exception)
{
UnhandledException(exception.Message);
}
[Event(601, Channel = EventChannel.Admin, Message = "Unhandled exception occurred. Details: {0}", Keywords = EventKeywords.None, Level = EventLevel.Critical)]
private void UnhandledException(string exceptionMsg)
{
this.IsEnabled().Dump();
this.WriteEvent(601, exceptionMsg);
}
}
The, second, your EventSource need to be registered. The steps are outline here:
One requirement introduced by channel support is the need to statically register the ETW provider manifest. The NuGet package supports generating the files needed for static registration as part of your build. After your build completes a new step is run that generates a pair of files for each of the event source types defined in the project:
..etwManifest.man and
..etwManifest.dll
The first file contains the ETW manifest while the second one contains the binary form of the ETW manifest plus any needed native resources (localization string tables in particular).
The tool that generates the above two files is “eventRegister.exe” and it performs two functions:
It ensures the registration files are generated for all event source types that need static registration, and
It performs a number of validation checks on all the event source types defined in the output assembly.
Deploying your component will need to include these files and perform one registration step at installation time and one un-registration step at un-installation time.
Registration:
wevtutil.exe im <EtwManifestManFile> /rf:"<EtwManifestDllFullPathName>" /mf:"<EtwManifestDllFullPathName>"
Unregistration:
wevtutil.exe um <EtwManifestManFile>
For static registration eventRegister.exe generates manifests that include all localization information. This is needed because the manifest is generated at build time, when there’s no information regarding the culture in which the final application will run.
Note you will see that in the .etwManfest.man file that the build generated, there are path names for the resource file and manifest file in this file. They are the paths that existed at build time. These paths are NOT used if you use the /rf and /mf options. Thus you should always specify the /rf: and /mf options (unless you hand modify the .etwManifest.man file to specify deployment-time file paths for the DLL).
Finally, it is important that you use FULLY qualified names for the /mf: and /rf: options. You can use environment variables THAT ARE AVAILABLE TO ALL PROCESSes (e.g. %SystemRoot% or %ProgramFiles%), but you should not use relative paths (it is not clear what they are relative to, probably System32, but don’t count on it).
The general recommendation is to copy your etwManifest.dll and .etwManifest.man to a directory under %ProgramFiles% and then use wevtutil to register them at that location.
The easiest way to create the files described above is to add this NuGet Package as it will create those files when building your project. It comes with the docs in .docx format.
I have done this in the past write to the event log Application:
using (EventLog eventLog = new EventLog("Application"))
{
eventLog.Source = "Application";
eventLog.WriteEntry("Log message test", EventLogEntryType.Information, 101, 1);
}

Is it possible to initialize a ConfigurationSection from an external file?

I have a custom configuration property in my app. It looks something like this:
public class OverrideConfiguration : ConfigurationSection
{
[ConfigurationProperty(PROP_ADMIN_CONNSTR)]
public StringConfigurationElement AdminConnectionString
{
get { return base[PROP_ADMIN_CONNSTR] as StringConfigurationElement; }
set { base[PROP_ADMIN_CONNSTR] = value; }
}
// .. Various other properties, but you get the idea
}
However, what I'd like is to allow the .config file to be pointed to an external file source. Something like this:
<ServiceOverrides file="Overrides.local.config" />
Now, the built-in configSource attribute is close to what I need, but it has two major issues.
Files must exist. If the file doesn't exist, it errors out.
Files must be in the current directory or in a deeper directory. In other words, I can't point to ..\Overrides.local.config
What I want is pretty much identical to the <appSettings file="..." /> configuration element. However, that attribute seems to be something appSettings implemented, and is not part of the base ConfigurationSection class.
My Question:
Is it possible to override something in ConfigurationSection that will basically read XML data from a different location? I don't want to change any other aspect of my class or do my own XML deserialization or anything. I simply want to check if a file exists, if so, load in the XML contents from that file, otherwise load in the default XML contents.
Ok, I have a working solution. I'm not sure if it's the best approach, but it does appear to work exactly how I want.
private readonly Queue<String> externalSources = new Queue<String>();
protected override void DeserializeElement(XmlReader reader, bool serializeCollectionKey)
{
var externalFile = reader.GetAttribute("File");
if(!String.IsNullOrWhiteSpace(externalFile))
{
externalSources.Enqueue(externalFile);
}
base.DeserializeElement(reader, serializeCollectionKey);
}
protected override void PostDeserialize()
{
base.PostDeserialize();
// Override data with local stuff
if (externalSources.Count == 0) return;
string file = externalSources.Dequeue();
if (System.IO.File.Exists(file))
{
var reader = XmlReader.Create(file);
base.DeserializeSection(reader);
}
}
First, I trap the DeserializeElement event, which happens when we read the <ServiceOverrides> element. We check if it has a File attribute, and if so we add it to a queue of external sources to load.
Next, we trap the PostDeserialize event, which gets called after all the local XML is parsed. If there's an external source in the queue, we dequeue it, check if it actually exists, then create an XmlReader with the contents of that file. Now we can simply call DeserializeSection again and pass in our new reader. The ConfigurationSection class is smart enough to just overwrite or append any new data to the existing configuration. What I get at the end is an aggregation of both configuration files, where the include file wins in the event of a duplicate.
Now, what's this nonsense with the queue? Well, it seems every time you call DeserializeSection, it'll call PostDeserialize again. So, if we simply trapped PostDeserialize, check the File attribute, and call DeserializeSection again, we'd get in an infinite loop. We could just use a flag to remember if we already loaded the external file, but a queue has the added benefit of allowing the include file to load more include files (not that I'd ever want to do that, but you might).
Tips: This will probably work fairly well, and is simple to understand, but if you're using it in production code, there's a few things you could improve on. First, externalSources doesn't really need to be a queue, since these calls aren't actually recursive. You can probably just use a string, and set it to null after you're done processing that file. Second, this could cause an infinite loop in the event of a circular include chain. You could create a List<T> of previously included files, then check if the include already exists in that list before adding it to the queue.
Hope this helps someone!

Getting the URL of a file my app is opening via openURL:

I configured my app with a custom file type. I added the information required in the Info.plist file (Document Types and Exported UTIs). Now iOS recognizes my file type and associates it with the app. So, for example, when I open Mail, and I see my file as an attachment, I can click on it and select to open with my app.
How I can get the URL of the file from my app? I tried to use OpenUrl on UIApplication, but it does not work.
Anyone know how to do that?
SOLUTION FOUND
I state that I need a solution for Xamarin/C#, but I asked for a standard objective-c code to later translate in C#, becouse I could not find anything about that.
At the end this is the solution that worked for me:
In the AppDelegate.cs file I add this method:
public override bool OpenUrl (UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
NSNotificationCenter.DefaultCenter.PostNotification (NSNotification.FromName ("OpenMyFile", url));
return true;
}
Then in my main controller, I add this in the "ViewDidLoad" method:
NSNotificationCenter.DefaultCenter.AddObserver ("OpenMyFile", openFileVoid);
And in the same class I add a new method:
public async void openFileVoid (NSNotification notification)
{
NSUrl _filePath = (NSUrl)notification.Object;
// Do what you need with this file path
}
I hope can be useful to someone! :)
I think it has nothing to do with -[UIApplication openURL:].
As it was stated in Apple Doc :
You receive information about the file to be
opened in the application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method of your application
delegate. If your application handles custom file types, you must
implement this delegate method (instead of the
applicationDidFinishLaunching: method) and use it to initialize your
application.
The options dictionary passed to the
application:willFinishLaunchingWithOptions: or
application:didFinishLaunchingWithOptions: method contains information
about the file to be opened.
You can read about it more in the doc.

How to make designer generated .Net application settings portable

I've been looking at modifying the source of the Doppler podcast aggregator with the goal of being able to run the program directly from my mp3 player.
Doppler stores application settings using a Visual Studio designer generated Settings class, which by default serializes user settings to the user's home directory. I'd like to change this so that all settings would be stored in the same directory as the exe.
It seems that this would be possible by creating a custom provider class which inherits the SettingsProvider class. Has anyone created such a provider and would like to share code?
Update: I was able to get a custom settings provider nearly working by using this MSDN sample, i.e. with simple inheritance. I was initially confused as Windows Forms designer stopped working until I did this trick suggested at Codeproject:
internal sealed partial class Settings
{
private MySettingsProvider settingsprovider = new MySettingsProvider();
public Settings()
{
foreach (SettingsProperty property in this.Properties)
{
property.Provider = settingsprovider;
}
...
The program still starts with window size 0;0 though.
Anyone with any insight to this?
Why the need to assing the provider in runtime---instead of using attributes as suggested by MSDN?
Why the changes in how the default settings are passed to the application with the default settings provider vs. the custom one?
Why not use the CodeProject PortableSettingsProvider solution as is (with a few minor changes) ?
I have done so in my project (StreamRecorder.NET) with success.
Some comments on the project's page were useful:
http://www.codeproject.com/Messages/2934144/Fixed-csharp-version.aspx
http://www.codeproject.com/Messages/3285411/Re-Win-Form-Designer-breaking-with-custom-Settings.aspx
And the code I ended up with:
static void Main(string[] args)
{
if (args.Contains("-p") || args.Contains("--portable"))
{
MakePortable(Properties.Settings.Default);
MakePortable(Properties.LastUsedSettings.Default);
MakePortable(Properties.DefaultSettings.Default);
}
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm(args));
}
private static void MakePortable(ApplicationSettingsBase settings)
{
var portableSettingsProvider =
new PortableSettingsProvider(settings.GetType().Name + ".settings");
settings.Providers.Add(portableSettingsProvider);
foreach (System.Configuration.SettingsProperty prop in settings.Properties)
prop.Provider = portableSettingsProvider;
settings.Reload();
}
Lastly I made these changes to the CP project:
string _fileName;
public PortableSettingsProvider(string fileName)
{
_fileName = fileName;
}
public virtual string GetAppSettingsFilename()
{
//Used to determine the filename to store the settings
//return ApplicationName + ".settings";
return _fileName;
}
I know this question is quite old already. I just want to share my own version of a portable settings provider which I published as nuget package here.
The usage is pretty simple:
// make the default settings class portable
PortableSettingsProvider.ApplyProvider(Properties.Settings.Default);
I also explained the basic strategy of this implementation at https://www.codeproject.com/Articles/1238550/Making-Application-Settings-Portable.
Just to 'close' the question: The somewhat unsatisfactory solution I ended up with was
Create a custom settings provider, which inherits from SettingsProvider and stores the settings in a XML file
Set the Provider property of each of the setting (by selecting the entire grid in the designer) to the custom settings provider using the designer
Drawbacks: The forms designer breaks and gives an exception which basically says that the custom provider class cannot be found. The built exe however works OK. Setting the provider in the code as described in the question makes the designer work, but then for some reason, which I haven't looked closely at, the settings won't serialize.
It seems that making settings portable was all that was needed to make Doppler portable. Whether I'll start using Doppler as my main podcast aggregator or stick with my homebrew command line aggregator, I'll see.

Categories