This question already has answers here:
How do I debug Windows services in Visual Studio?
(17 answers)
Closed 6 years ago.
I have the following code to write to a log file and it works fine in my console application:
try
{
string log = "some message";
string mFileName = "some directory to the log file";
Console.WriteLine(log);
using (StreamWriter w = File.AppendText(mFileName))
{
w.WriteLine(log);
w.Dispose();
}
}
catch (Exception e)
{
Console.WriteLine("Error Log: " + e.Message);
}
But when I run the code as a service on my PC, it stops logging altogether. I've already checked and the service has same rights as me.
Please note: The service doesn't crash, it simply runs without logging.
Most likely this has something to do with user rights.
My guess is that the system user that starts the service, doesn't have the rights to write to the file location.
One solution is to start the service with the user credentials of your own account (because you have the rights.)
Another solution is to give the user (local system ,service user or IIS user for web-service) write access to the directory, or change the path of the file to a directory were the user has write access.
if you want to make sure, add a try catch block around the using, and write the exception to console, debug or messagebox. Then you will know what goes wrong.
see possible exceptions for File.AppendText on MSDN
My guess is it throws a UnauthorizedAccessException
Why not simply create the StreamWriter directly, wrap it in a try-catch, and if there is an exception, log it with System.Diagnostics.EventLog?
try
{
using (Streamwriter sw = new StreamWriter(path, true)
{
sw.WriteLine(log);
}
}
catch (Exception ex)
{
// Log exception using System.Diagnostics.EventLog
}
Related
I am a long time c# developer but brand new to QBFC. I have downloaded the samples and was actually able to add an invoice to my file with it, but I am a little confused. I have trouble connecting unless QB is up and running. I was trying to follow the code in the sample, but it is difficult. I need this app to add invoices and bills to the file even if QB is not open. They only have one file so there won't be an instance where another file is already open. Also, the environment is simple as everything runs on the same computer.
My basic questions are:
How to select the correct QB file and provide credentials to allow access?
Is there a decent simple example using QBFC? Everything I have found is using XML which seems overly complicated compared to QBFC.
I cannot seem to get QB to open automatically. I have tried the code below and I get an error that states "Could not start QuickBooks".
Any pointers are greatly appreciated.
QBSessionManager qbSession = new QBSessionManager();
qbSession.OpenConnection("", "Lumber Management System");
try
{
qbSession.BeginSession("C:\\Users\\Jerry\\Documents\\QuickBooks\\Company Files\\MRJ Tecnology, LLC", ENOpenMode.omDontCare);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + '\n' + ex.StackTrace, "Error opening QB");
}
There are a couple of things that you need in order for this to work. The first time that you request access to a company file, QuickBooks must be opened and the Admin must be logged in. The Admin will then be given a dialog to grant permission to your application to access QuickBooks. In the permission dialog, it will ask the Admin if they want to allow the application to read and modify the company file with four options:
No
Yes, prompt each time
Yes, whenever this QuickBooks company file is open
Yes, always; allow access even if QuickBooks is not running
The admin must choose the fourth option to allow your app to launch QuickBooks without running.
I would also suggest that you use OpenConnection2 instead of OpenConnection, and use a unique ID as the first parameter. You will also need to specify the connection type, which should be ENConnectionType.ctLocalQBD.
It also appears that the filename you are passing in the BeginSession call does not include the .qbw extension. Here is a basic sample:
QBSessionManager SessionManager = null;
try
{
SessionManager = new QBSessionManager();
SessionManager.OpenConnection2("UniqueAppID", "Lumber Management System", ENConnectionType.ctLocalQBD);
SessionManager.BeginSession("C:\\Users\\Jerry\\Documents\\QuickBooks\\Company Files\\MRJ Tecnology, LLC.qbw", ENOpenMode.omSingleUser);
// CODE TO SEND TO QB GOES HERE
}
catch(Exception ex)
{
MessageBox.Show("Error opening QB:" + ex.ToString());
}
finally
{
if(SessionManager != null)
{
SessionManager.EndSession();
SessionManager.CloseConnection();
}
}
i cannot create file in my windows service
and this is error
error In onstart method Access to the path 'C:\Windows\system32\BridgeServiceLog.txt' is denied.
protected override void OnStart(string[] args)
{
try
{
Logger.InitLogFile("BridgeServiceLog.txt");
Trace.WriteLine(Logger.logSwitch.TraceInfo, "Trace Started");
Trace.WriteLineIf(Logger.logSwitch.TraceInfo, "OnStart Started");
_bridgeServiceEventLog.WriteEntry("new OnStart");
if (Vytru.Platform.Bridge.Configuration.LicenseValidetor.ValidCountAndTypeDevices())
{
SharedData.InitializeBridge();
// WsInitializeBridge();
}
else
{
this.Stop();
_bridgeServiceEventLog.WriteEntry("LicenseValidetor Error");
}
_bridgeServiceEventLog.WriteEntry("end Start");
}
catch (Exception e)
{
Trace.WriteLineIf(Logger.logSwitch.TraceError, e.Message);
_bridgeServiceEventLog.WriteEntry("error In onstart method " + e.Message);
}
Trace.WriteLineIf(Logger.logSwitch.TraceInfo, "OnStart Ended");
}
The service user account probably doesn't have access to write to C:\Windows\System32 (which is the working directory of a Windows service).
Anyway, you shouldn't write to that folder. It is for the operating system - not your service.
You can use Environment.GetFolderPath to get a suitable path for writing files like log files in a way that will work any computer, not just your own computer. Here is an example.
var companyPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
"MyCompany"
);
var productPath = Path.Combine(companyPath, "MyProduct");
var logFilePath = Path.Combine(productPath, "BridgeServiceLog.txt");
You should of course use suitable values for MyCompany and MyProduct.
When running a Windows Service the default working folder is <System drive>:\Windows\System32\.
Fortunately, not everyone can just access that folder.
There are two ways about this; write your file to another folder to which you do have rights, or run your service with administrator rights.
I would recommend the first option.
The easiest solution is to go the folder where you want to save a file, right click, properties, security, add a new user IIS_Users and give permission to write.
Use LocalSystem account on ProjectInstaller
I have an ASP.NET application which requires write access on the App_Data subfolder. The MSI used to deploy the application tries to set the permissions correctly, but in spite of this, it seems the permissions are sometimes wrong. Most of the application works fine without this permission. I would prefer that the application fails to start if the permissions are wrong.
What is the best practice for ensuring that the necessary permissions are correct for the IIS user context? Ideally I want to display some simple instructions for fixing whatever is wrong. And I want the message to appear in as many incorrect configurations as possible.
The following describes what I've tried so far, until I realised there's a probably a better or standard way.
I tried putting this in Application_Start()
protected void Application_Start(Object sender, EventArgs e)
{
// Assert permissions on writeable folders are correct
var permissionsChecker = new AppDataPermissionsChecker();
permissionsChecker.AssertFolderIsWriteable(
HttpContext.Current.Server.MapPath("~/App_Data"));
// remainder of Application_Start()...
}
where AppDataPermissionsChecker is defined as follows:
public class AppDataPermissionsChecker
{
private bool CanWriteAccessToFolder(string folderPath)
{
try
{
// Attempt to get a list of security permissions from the folder.
// This will raise an exception if the path is read only or do not have access to view the permissions.
DirectorySecurity directorySecurity = Directory.GetAccessControl(folderPath);
return true;
}
catch (UnauthorizedAccessException)
{
return false;
}
}
public void AssertFolderIsWriteable(string folderPath)
{
if (!Directory.Exists(folderPath))
throw new Exception(String.Format("The {0} folder does not exist.", folderPath));
if (!CanWriteAccessToFolder(folderPath))
throw new Exception(String.Format("The ASPNET user does not have "
+ "access to the {0} folder. Please ensure the ASPNET user has "
+ "read/write/delete access on the folder. See 'The App_Data folder' "
+ "here: http://msdn.microsoft.com/en-us/library/06t2w7da.aspx'",
folderPath));
}
}
I thought this would throw an ugly exception if the rights are incorrect (which is better than nothing), but in some situations I just get an HTTP Error 503.
I found this implementation of a diagnostics page which does exactly what I was looking for (and more besides).
C# .net Framework 4.0
Is there a simple way to check if you have the rights to run a file?
Before i do this:
//e.g. Press a button
....
string exePath = "D:\something\something.exe";
Process.Start(exePath);
i would like to check if the user has the rights to run that file?
When i'm making the function call Process.Start, windows popsup with a messagebox and says that i'm not authorized to run this application and this application is "D:\something\something.dat" and NOT .exe?
How to check if you have permission to run a exe file?
EAFP: It is Easier to Ask Forgiveness than it is to get Permission.
So, you can surround your code with try/catch block:
try {
Process.Start(path);
} catch (Win32Exception ex) {
// ...
}
and you can use Win32Exception.NativeErrorCode to access the numeric representation of the error code associated with this exception.
For more information about the error codes, check out Win32 System Error Codes.
Try surrounding Proccess.Start with try catch:
//e.g. Press a button
....
string exePath = "D:\something\something.exe";
try
{
Process.Start(exePath);
} catch (Exception e) {
// No permissions or file not found?
}
that'll do the job.
I'm trying to get my .Net Windows Service to right to a custom event log. I'm using EventLogInstaller to create the event log and source when the application is installed. I read here that it takes a while for Windows to register the source so they reccomend you restart the application before trying to write to the log.
As this is a Windows Service I didn't want to have to force a computer restart or get the user to manually start the service up, so I use this code to wait for the log to exist and then start the service automatically.
while (!(EventLog.Exists("ManageIT") || EventLog.SourceExists("ManageIT Client Service")))
{
Thread.Sleep(1000);
}
System.ServiceProcess.ServiceController controller = new System.ServiceProcess.ServiceController("ManageIT.Client.Service");
controller.Start();
My problem is that events from the service are still written to the Application Log and although I can see my custom log in the Registry Editor it does not show up in the Windows 7 Event Viewer.
Any help will be much appreciated.
By default when a service is installed, the source gets associated with the Application Log.
If we change this association at a later point, the system needs a restart.
We can however prevent the association of the service with the application log, by setting autolog property to false in the service class (class which inherits from servicebase) constructor.
http://msdn.microsoft.com/en-us/library/system.serviceprocess.servicebase.autolog.aspx
Try this snippet:
edit - caveat: if the user running the code does not have administrator rights, this will throw an exception. Since this is the case (and if the user will not have these rights) best practices should be to assume the log exists, and simply write to it. see: The source was not found, but some or all event logs could not be searched
if (!EventLog.SourceExists("MyApplicationEventLog"))
{
EventSourceCreationData eventSourceData = new EventSourceCreationData("MyApplicationEventLog", "MyApplicationEventLog");
EventLog.CreateEventSource(eventSourceData);
}
using (EventLog myLogger = new EventLog("MyApplicationEventLog", ".", "MyApplicationEventLog"))
{
myLogger.WriteEntry("Error message", EventLogEntryType.Error);
myLogger.WriteEntry("Info message", EventLogEntryType.Information);
}
It sounds like you are writing to the event log like this:
EventLog.WriteEntry("Source", "Message");
This will write to the application log.
If you use the code in simons post with the creation of myLogger, you can specify the name of the Log.
I did something like this:
var logName = EventLog.LogNameFromSourceName("MyApp", Environment.MachineName);
//delete the source if it associated with the wrong Log
if (!string.IsNullOrEmpty(logName) & logName != "MyLog")
{
EventLog.DeleteEventSource("MyApp", Environment.MachineName);
}
if (!EventLog.SourceExists("MyApp"))
{
EventLog.CreateEventSource("MyApp", "MyLog");
}