Creating new event log source - c#

My application calls a library (which I do not have control) that creates a new EventLog source and uses EventLog.SourceExists. It throws System.Security.SecurityException: The source was not found, but some or all event logs could not be searched. Inaccessible logs: Security.
The app needs read access to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\eventlog\Security. How do I give Network Service permissions to registry (programmatically)?
Thanks for any pointers.

You are getting this error message because your "new Source" is not registered, and for that you need administration privileges. Try run your APP as "Administrator" in Console.
I once hacked the "registry" as well, by adding in the "Source" myself, but that's probably ill-advised.

I hit this same problem today and none of the answers for WinForms or ASPX seemed practicable for my situation (a non-installing scheduled task exe). So I did this: -
protected void prog_Load(object sender, EventArgs e)
{
boolean setupComplete = false;
try // setting an Event log entry, just to see if we can
{
logEvent = "prog started";
EventLog.WriteEntry(logSource, logEvent, EventLogEntryType.Information, 0);
setupComplete = true;
}
catch (Exception eLog1) // we can't, so try to fix
{
try
{
EventLog.CreateEventSource(logSource, logLog);
logEvent = "prog registered for Event Logging";
EventLog.WriteEntry(logSource, logEvent, EventLogEntryType.Information, 0);
}
catch (Exception eLog2) // aha! we probably lack admin rights to set the registry key
{
MessageBox.Show("prog needs admin rights the first time it runs", "prog Setup", MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
}
// run
if (setupComplete == true)
{
DoTheWork();
}
// exit
this.Close();
}

Related

How to fix NullReferenceException occurring only on some computers

I create a setup file of a winform app using VS 2017 installer. When I test this setup file on my PC, the login runs fine. So I run this setup file on other PCs.
However, when I login the app in these PCs, the app say "Object reference not set to an instance of an object", though I am sure that the username and password were correct in the db.
I have seen What is a NullReferenceException, and how do I fix it?, but I do not think it is the null exception, because the installed app did not throw above error in my PC. This error only happens when I install the app in other PCs.
I also try replacing the .exe and .config files in folder of the installed app in other PCs with the same files of the app in my PC (which work well), and the app runs ok. But then I restart those PCs, and try to login the app, the same error happens.
This is the code for login. I believe that I have checked for the null exception properly. Am I right?
private void btnLogin_Click(object sender, EventArgs e)
{
try
{
var info = UsersBiz.Login(txtUserName.Text.Trim(), txtPassWord.Text);
if (info != null && info.user.Id > 0)
{
Constants.USERINFO = info;
this.Hide();
var frm = new frmMain();
frm.Show();
if (ckbRemember.Checked)
{
ManagementInventory.Properties.Settings.Default.User = txtUserName.Text;
ManagementInventory.Properties.Settings.Default.Pass = txtPassWord.Text;
ManagementInventory.Properties.Settings.Default.Save();
}
}
else
{
MessageBox.Show("UserName or Password not correct!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The most easy way would be to use visual studio debugger on the computer where the program runs. If there is no visual studio on that computer, consider using remote debugging. See how to start debugging on a remote computer
If for security reasons remote debugging is out of the question, consider to log the exception, especially the stack trace. If you know where it occurs, simply surround it with a try-catch
try
{
// Here are the statements that cause your ArgumentNullException
}
catch (ArgumentNullException exc)
{
// log the exception
}
If your program has no logging facility, consider adding something like NLOG. Another possibility is to append it to a text file.
void WriteExceptionToTextFile(Exception exc, string fileName)
{
using (var writer = File.AppendText(fileName))
{
writer.WriteLine("Exception {0}", exc.GetType());
write.WriteLine("Stack trace" + exc.StackTrace);
... // etc
}
}
If you don't know where the exception occurs, you can't try-catch it. In that case consider to catch the unhandled exception and log it:
See: catching unhandled exception
In your forms program is a file program.cs which contains the main:
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += OnUnhandledException;
...
}
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception undhandledException = (Exception) args.ExceptionObject;
// TODO log the unhandled exception
}

Proper way to set up and use custom event log in .NET service?

I found several topics on this already, but somehow they all managed to avoid the real problem solution/assumed the obvious.
(e.g. here, here, here, here, here)
I am checking for and creating new event log + source during installation, and specifying them to be used during operation, but still somehow "EventSourceName" events end up in Application Log.
Why is that?
Here are snippets out of my code:
Installer:
namespace Service_Name
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
if (!System.Diagnostics.EventLog.SourceExists("EventSourceName"))
{
System.Diagnostics.EventLog.CreateEventSource(
"EventSourceName", "EventLogName");
}
InitializeComponent();
}
private void serviceProcessInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
}
}
}
Service:
public Service_Name()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
ServiceEventLog = new EventLog();
ServiceEventLog.Source = "EventSourceName"; // This is different from Service Name
ServiceEventLog.Log = "EventLogName"; // This is different from Service Name
..
ServiceEventLog.WriteEntry("Service Init");
Worker = new Thread(CodeWorker);
Worker.Start();
}
private void CodeWorker()
{
//.. operational code
while (true)
{
try
{
//.. operational code
ServiceEventLog.WriteEntry("<operational event data here>", (EventLogEntryType)4, 0);
}
catch (Exception Error)
{
ServiceEventLog.WriteEntry(string.Format("<error event data here>", (EventLogEntryType)1, 0);
throw;
}
//.. operational code
}
}
As it turns out, the code works perfectly as is, however there is important thing to remember when working with event log;
EventLog.CreateEventSource Method has an important footnote:
If a source has already been mapped to a log and you remap it to a new
log, you must restart the computer for the changes to take effect.
I had mapped the source prior, to another event log which was named the same as Service itself. Using same name as the service itself caused multiple other issues and I ended up fixing that by using another log name, but did not restart test system prior to doing tests on new code version.
But as Caius Jard pointed out below, parts of the code are redundant:
ServiceEventLog.Log = "EventLogName" does not need to be specified as Source is already registered to Log.
The documentation states "If you change the Log property after the Source property has been set, writing a log entry throws an exception.".
The sample code on MSDN just sets the Source property and then calls WriteEvent, it does not then set the Log beforehand or after setting Source
I recommend you remove the call to setting the Log property; I suspect your call to WriteEvent is crashing, and being in a try catch the call in the catch is also crashing. Perhaps it's not an ideal code structure to "try writing to this log and if it fails, try writing to this log" if it's the "writing to log" that is failing

How can I log unhandeled exception in AppHarbor?

I have a website on appharbor.
I know there is logentries for logs on demand.
But, how can I see all unhandled server-side exceptions?
I have found this snippet (to put int Global.ascx), but couldn't find what are all the required dlls to reference.
protected void Application_Error(object sender, EventArgs e)
{
try
{
var exception = Server.GetLastError();
var logEntry = new LogEntry
{
Date = DateTime.Now,
Message = exception.Message,
StackTrace = exception.StackTrace,
};
var datacontext = new LogDBDataContext();
datacontext.LogEntries.InsertOnSubmit(logEntry);
datacontext.SubmitChanges();
}
catch (Exception)
{
// failed to record exception
}
}
AppHarbor already logs application errors, you can inspect them by clicking "Errors" in the menu to the left of the application dashboard.
Another great option is to add Elmah to your AppHarbor application, but remember to lock down Elmah view.
Should you still want to use the snippet above, then take a look at the full sample to see what other dependencies are required.

How to wait for an Autoreset event to occur before taking any other action?

This is about the AutoResetEvent in C#. I tried to read other answers but I could not make sense and apply to my scenario. I am not writing any threading application. Just a small application to read/validate a file and update.
So I have this requirement to write some code for reading a fixed length file, validating it and then if it is valid upload it to Database.
I got everything working until I got stuck with the AutoResetEvent. So here is what is happening. Once the data is parsed/read I validate it using Flat File Checker utility in C#. So I called the functions into my application. Here is the snippet.
private AutoResetEvent do_checks = new AutoResetEvent(false);
public bool ValidationComplete = false;
This part goes in initialization code:
this._files.Validated += new EventHandler<SchemaValidatedEventArgs>(FileSetValidated);
public bool ValidateFile()
{
try
{
RunValidation();
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
log.Debug("Validation Started");
}
This is the method that is getting called asnchronusly during the validation process:
public void FileSetValidated(Object sender, SchemaValidatedEventArgs e)
{
try
{
ValidationComplete = e.Result;
if (IsDataValid)
{
log.Debug("Data is validated and found to be valid.");
}
else
{
log.Debug("Data is validated and found to be Invalid");
}
}
finally
{
do_checks.Set();
}
}
What is happening is that even before I get any value set into ValidationComplete the code is checked for Validation complete and because it is set by default to false, it returns false. The code in the FileSetValidated gets executed after that so the database update never happens.
The reason is that I cannot change the code because the Flat File Checker only accepts an AutoResetEvent as a return variable in RunChecks method.
******Here is what I did now*******
private AutoResetEvent do_checks;
public bool ValidateFile()
{
try
{
string extFilePath = surveyFile.ExtFilePath;
File.Copy(extFilePath, localTempFolder + "ExtractFile.Dat");
RunValidation();
if (!do_checks.WaitOne(TimeSpan.FromSeconds(30))) {
// throw new ApplicationException("Validation took more than expected!");
}
return true;
}
catch (Exception e)
{
log.Error("Data Validation failed because :" + e.Message);
return false;
}
}
private void RunValidation()
{
// Use Flat File Checker user interface to create Schema file.
do_checks = _files.RunChecks();
do_checks.WaitOne();
log.Debug("Validation Started");
}
Also I moved the part where data about validation gets passed on towards the beginning of the event handler so atleast that part gets executed. This helped but I am not sure if it is correct.
I have never worked with that lib, so I just downloaded it and looked into the code.
First of all, as "500 - Internal Server Error" already mentioned, it seems that part of the code is missing, at least "try" in the FileSetValidated method. I don't see any place where you are waiting for the event via WaitOne.
You don't need to create do_checks by yourself, because _files.RunChecks() creates AutoResetEven for this particular file's processing. So if you are using the same field for that event - you will get issue if you will need to process few files at the same time. So keep separate event for each file, in any case I don't see reason to keep that references as members if you don't want to stop processing in the middle (if you will call do_checks.Set() during processing, it will cancel processing without finishing it).
As I see in the lib code, you should not call do_checks.Set() in the FileSetValidated method, because it will be set, once processing will be done, so you can just write:
var do_checks = _files.RunChecks();
do_checks.WaitOne();
Feel free to share if that helped.
UPDATE:
I am not able to check that lib now to undestand why do_checks is set after starting processing, but I can suggest you to use your initial code with next RunValidation method:
private void RunValidation()
{
do_checks.Reset(); //reset state
_files.RunChecks(); //don't store event from the lib
log.Debug("Validation Started");
do_checks.WaitOne(); //Wait for FileSetValidated to set this event
}
Before exiting the ValidateFile function you need to wait for the validation to complete (wait on the AutoResetEvent) and return the validation result.
Try something like this:
public bool ValidateFile()
{
//try
{
RunValidation();
//Allocate enough time for the validation to occur but make sure
// the application doesn't block if the _files.Validated event doesn't get fired
if(!do_checks.WaitOne(TimeSpan.FromSeconds(10)))
{
throw ApplicationException("Validation took more than expected!");
}
return ValidationComplete;
}
//I would not catch the exception since having an error doesn't mean that the file
//is invalid. Catch it upper in the call stack and inform the user that the validation
//could not be performed because of the error
//catch (Exception e)
//{
// log.Error("Data Validation failed because :" + e.Message);
// return false;
//}
}

Receiving "...has already been registered..." from EventLog.CreateEventSource even though I'm checking !EventLog.SourceExists

My following code fails with "...has already been registered as a source on the local computer" even though I'm doing checks first:
lock ( eventLock )
{
string eventLog = Constants.EventLogPL;
string eventSrc = Constants.EventSrcPL;
if (!EventLog.Exists(eventLog))
{
if (!EventLog.SourceExists(eventSrc))
{
try
{
EventLog.CreateEventSource(eventSrc, eventLog);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
}
}
}
I'd have thought my call to !EventLog.SourceExists would have been enough to prevent my error!
I'm on 2010 .NET 4 and Windows 7 64 compiling to any CPU.
Edit: Updated code to get Constant's to locals to check they don't change, and use locking to make sure only one thread can test and create. Code still fails with the same error.
Found the problem after digging in to Sysinternals' Process Monitor a little more:
Calling EventLog.Exists("MyLog");
Logs Name not found, as expected in:
KLM\System\CurrentControlSet\services\eventlog\MyLog
Calling EventLog.SourceExists("MySource");
Checks several places, name not found in as expected:
HKLM\System\CurrentControlSet\services\eventlog\Application\MySource
HKLM\System\CurrentControlSet\services\eventlog\HardwareEvents\MySource
HKLM\System\CurrentControlSet\services\eventlog\Internet Explorer\MySource
HKLM\System\CurrentControlSet\services\eventlog\Key Management Service\MySource
HKLM\System\CurrentControlSet\services\eventlog\Media Center\MySource
HKLM\System\CurrentControlSet\services\eventlog\ODiag\MySource
HKLM\System\CurrentControlSet\services\eventlog\OSession\MySource
HKLM\System\CurrentControlSet\services\eventlog\Security\MySource
HKLM\System\CurrentControlSet\services\eventlog\System\MySource
HKLM\System\CurrentControlSet\services\eventlog\VisualSVNServer\MySource
HKLM\System\CurrentControlSet\services\eventlog\Windows PowerShell\MySource
HKLM\System\CurrentControlSet\services\eventlog\Application\MySource
HKLM\System\CurrentControlSet\services\eventlog\HardwareEvents\MySource
HKLM\System\CurrentControlSet\services\eventlog\Internet Explorer\MySource
HKLM\System\CurrentControlSet\services\eventlog\Key Management Service\MySource
HKLM\System\CurrentControlSet\services\eventlog\Media Center\MySource
HKLM\System\CurrentControlSet\services\eventlog\ODiag\MySource
HKLM\System\CurrentControlSet\services\eventlog\OSession\MySource
HKLM\System\CurrentControlSet\services\eventlog\Security\MySource
HKLM\System\CurrentControlSet\services\eventlog\System\MySource
HKLM\System\CurrentControlSet\services\eventlog\VisualSVNServer\MySource
HKLM\System\CurrentControlSet\services\eventlog\Windows PowerShell\MySource
HKLM\System\CurrentControlSet\services\eventlog\MyLog
However, calling EventLog.CreateEventSource("MySource", "MyLog");
Finds MyLog in the following registry location and errors:
HKLM\System\CurrentControlSet\services\eventlog\Application\MyLog
Removing "HKLM\System\CurrentControlSet\services\eventlog\Application\MyLog" and re-running fixed my problem!
Looks like the .Exists don't look in all the places .CreateEvent does!
//0 for false, 1 for true.
private static int usingResource = 0;
if (!EventLog.SourceExists(Constants.EventSrcPL))
{
//0 indicates that the method is not in use.
if (0 == Interlocked.Exchange(ref usingResource, 1))
{
if (!EventLog.SourceExists(Constants.EventSrcPL))
{
try
{
EventLog.CreateEventSource(Constants.EventSrcPL, Constants.EventLogPL);
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
//Release the lock
Interlocked.Exchange(ref usingResource, 0);
}
}
}
}
else
{
usingResource = 0;
}
Does not solve the issue when the source is created by a different application in the exact time you are accessing the event log.
Edited: made modifications that account for the delayed creation of a EventSource.

Categories

Resources