Windows Service "Timeout" instantly on startup - c#

I'm currently running in to an issue where a Windows Service I wrote is "timing out" instantly on start up. The message I get is Error 1053: The service did not respond to the start or control request in a timely fashion. I checked Event Viewer and I see that message and another A timeout was reached (30000 milliseconds) while waiting for the X service to connect. Only problem is that it's not waiting 30 seconds to time out, it's more like half a second.
My service's OnStart()
private static readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string version = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location).FileVersion;
private string incomingProdFileLocation = ConfigurationManager.AppSettings["ProdIncomingFileLocation"];
private string incomingCertFileLocation = ConfigurationManager.AppSettings["CertIncomingFileLocation"];
//private string incomingCombFileLocation = ConfigurationManager.AppSettings["CombIncomingFileLocation"];
private string processedFileLocation = ConfigurationManager.AppSettings["ProcessedFileLocation"];
private string errorFileLocation = ConfigurationManager.AppSettings["ErrorFileLocation"];
FileSystemWatcher prodWatcher = new FileSystemWatcher();
FileSystemWatcher certWatcher = new FileSystemWatcher();
//FileSystemWatcher combWatcher = new FileSystemWatcher();
protected override void OnStart(string[] args) {
log.InfoFormat("Starting up Merchant Bulk Load Service v{0}", version);
if (verifyDirectories()) {
log.InfoFormat("Initialize Prod FileSystemWatcher() at {0}", incomingProdFileLocation);
prodWatcher.Path = incomingProdFileLocation;
prodWatcher.Filter = "*.csv";
prodWatcher.Created += ProdBulkLoadFileReceived;
prodWatcher.EnableRaisingEvents = true;
log.InfoFormat("Initialize Cert FileSystemWatcher() at {0}", incomingCertFileLocation);
certWatcher.Path = incomingCertFileLocation;
certWatcher.Filter = "*.csv";
certWatcher.Created += CertBulkLoadFileReceived;
certWatcher.EnableRaisingEvents = true;
/*log.InfoFormat("Initialize Comb FileSystemWatcher() at {0}", incomingCombFileLocation);
combWatcher.Path = incomingCombFileLocation;
combWatcher.Filter = "*.csv";
combWatcher.Created += CombBulkLoadFileReceived;
combWatcher.EnableRaisingEvents = true;*/
} else {
log.ErrorFormat("verifyDirectories() returned false. Service stopping");
this.Stop();
}
}
private bool verifyDirectories() {
// verify each of the necessary directories exists before setting up any FileSystemWatcher()s
if (!Directory.Exists(incomingProdFileLocation)) {
log.ErrorFormat("Incoming production file location {0} does not exist. Please create the directory or edit the configuration file.",
incomingProdFileLocation);
return false;
}
if (!Directory.Exists(incomingCertFileLocation)) {
log.ErrorFormat("Incoming cert file location {0} does not exist. Please create the directory or edit the configuration file.",
incomingCertFileLocation);
return false;
}
/*if (!Directory.Exists(incomingCombFileLocation)) {
log.ErrorFormat("Incoming combined file location {0} does not exist. Please create the directory or edit the configuration file.",
incomingCombFileLocation);
return false;
}*/
if (!Directory.Exists(processedFileLocation)) {
log.ErrorFormat("Processed file location {0} does not exist. Please create the directory or edit the configuration file.",
processedFileLocation);
return false;
}
if (!Directory.Exists(errorFileLocation)) {
log.ErrorFormat("Error file location {0} does not exist. Please create the directory or edit the configuration file.",
errorFileLocation);
return false;
}
return true;
}
My entire service works splendidly in our development and certification environments, but won't start in our production environment, it doesn't seem like it's even getting to the OnStart() because a log is never made. Things I've checked:
Made sure service had correct permissions in the necessary directories, it does
Made sure the correct version of .NET framework that my service is targeting (4) is installed, it is
Made sure Event Viewer wasn't throwing any other types of errors that might give me a hint to what's happening, there's nothing
All of the directories for the FileSystemWatcher actually exist, they do
The directory for the log4net file exists, it does
I'm at a loss at the moment; any help would be awesome.
edit
After double checking the .NET framework again I realize I checked the wrong server for the versions. A good way to be certain is to double-click on the actual exe file for the service and see what it says. In my case it literally said "Make sure 4.0 is installed" which prompted me to check again and there I saw that 4.0 wasn't installed.

Are you sure that your .net is up to date. This could happen if for instance 3.5 is on the machine and you're using 4.0.

This is an old ticket, but I just saw the same error (albeit with "90000 milliseconds" rather than 30000) on all of the Windows services we've created as part of our application (about 10 of them). .Net framework was installed and functional.
I examined the registry setting where this 90000 ms (90 second) limit was set.
In the node, HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
The value of ServicesPipeTimeout was 90000 (Decimal).
I didn't need it to be 90000 and I don't know why it was set thus, but it certainly wasn't waiting 90 seconds -- it was failing instantly.
So I modified the value to 30000 and rebooted the server.
All services begin starting or restarting successfully.

Related

Why can't I install my windows service - Specified service already exists

I wish I could put a grenade to my computer at this point. I'm so frustrated because I don't understand why my application won't install using installUtil.
I've just looked through this link now: Windows Service Install Ends in Rollback and unfortunately the kind suggestions on there don't help in my situation, the following error was generated after taking into consideration all of the answers posted by the good people of SO on that link and others.
I have looked for best practices on the web for task parallel processing patterns but there's nothing helpful so far. The latest error I get when attempting to install is as follows:
.exe assembly's progress. The file is located at
E:\xxx\MyService\Service_V2.InstallLog. Installing assembly
'E:\xxx\MyService\Service_V2.exe'. Affected parameters are:
logtoconsole = logfile = E:\xxx\MyService\Service_V2.InstallLog
assemblypath = E:\xxx\MyService\Service_V2.exe Installing service
Service V2... Service Service V2 has been successfully installed.
Creating EventLog source Service V2 in log Application... Installing
service Service V2... Creating EventLog source Service V2 in log
Application...
An exception occurred during the Install phase.
System.ComponentModel.Win32Exception: The specified service already
exists
The Rollback phase of the installation is beginning. See the contents
of the log file for the E:\xxx\MyService\Service_V2 .exe assembly's
progress. The file is located at
E:\xxx\MyService\Service_V2.InstallLog. Rolling back assembly
'E:\xxx\MyService\Service_V2.exe'. Affected parameters are:
logtoconsole = logfile = E:\xxx\MyService\Service_V2.InstallLog
assemblypath = E:\xxx\MyService\Service_V2.exe Restoring event log to
previous state for source Service V2. Restoring event log to previous
state for source Service V2. Service Service V2 is being removed from
the system... Service Service V2 was successfully removed from the
system.
The Rollback phase completed successfully.
The transacted install has completed. The installation failed, and the
rollback has been performed.
There was nothing written to the event log either.
Here is my OnStart() method:
protected override void OnStart(string[] args)
{
var tokenSource = new CancellationTokenSource();
var token = tokenSource.Token;
ErrorLogFileName = "Service_V2Errors" + DateTime.Now.ToString("yyyy-MM-dd") + ".txt";
Service_V2LogFile = "Service_V2Log" + DateTime.Now.ToString("yyyy-MM-dd") + ".log";
ErrorLogPath = ConfigurationManager.AppSettings["Errorpath"].ToString();
CheckBatchRecord = Convert.ToInt32(ConfigurationManager.AppSettings["CheckBatchTime"].ToString());
if (!Directory.Exists(ErrorLogPath))
{
Directory.CreateDirectory(ErrorLogPath);
}
LogMessage("Starting Service " + DateTime.Now.ToString());
_ErrorLog = new StreamWriter(ErrorLogPath + "//" + ErrorLogFileName, true);
_ErrorLog.WriteLine("Error, Location, AdditionalInformation", true);
_ErrorLog.Close();
var t = Task.Run(() => Service_V2Start(), token);
try
{
t.Wait();
}
catch (AggregateException e)
{
LogMessage("Exception messages:");
foreach (var ie in e.InnerExceptions)
LogMessage(ie.GetType().Name + " : " + ie.Message);
LogMessage("\nTask status: " + t.Status);
}
finally
{
tokenSource.Dispose();
}
}
I have also set the compile mode to release for the final install files compiled.
I have done an "sc delete Servie V2" and I also checked the services console and there is no such service listed there.
I have also tried the InstallUtil.exe -u command to uninstall, but I still get this nitwit error. What should I do now?
Make sure your Program.cs file looks something like this:
static class Program
{
static void Main()
{
var service = new YourServiceName();
ServiceBase.Run(service);
}
}
Inside the InitializeComponent() method make sure that the ServiceName property value is the same as the ServiceName in the ProjectInstaller.cs
this.ServiceName = "MyServiceName";//in the YourServiceName partial class
this.myServiceInstaller.ServiceName = "MyServiceName";//in the installer
Make sure you have only one installer.
In the batch files that you created to install and uninstall your service make sure that you are pointing to the correct InstallUtil.exe.
For 64 bit architectures you can use - C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe
For 32 bit architectures you can use - C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe
Sample InstallService.bat file:
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe" "PathToTheExecutables\MyServiceName.exe"
pause
Sample UninstallService.bat file:
"C:\Windows\Microsoft.NET\Framework64\v4.0.30319\installutil.exe" /u "PathToTheExecutables\MyServiceName.exe"
pause
Make sure you run cmd as Administrator :)

SharePoint Event Reciever Works On One Machine/computer/user

So we have created an updated version of a WSP for SharePoint 2010 due to our migration/update from 2007 to 2010.
The WSP is a event handler/reciever for ItemAdded() and we have it working as intended. Issue is that the operation seems to only work for one computer/machine and no others.
When the Item is Added to a list the WSP creates a Folder in Shared Documents library, creates a wiki page, then updates the new List Item with links to the Shared Doc and Wiki.
When triggered by Machine #1 and User #1 all operations work, when Machine #2(M2) and user #2(U2) or M3 and U3 non of the tasks take place when a new Item is created.
User #2 can log in on M1 and create a new item and all operations work. But if U1 uses M2 or M3 to create an item the events don't trigger. Machine #1 is able to trigger the event as many times as they want but no other computer is able to.
If you were able to follow is it something with the code or some sort of cache setting on the local machine or the SP server, or something else? Any help is appreciated.
Update: All machines are on the same network. Non of the machines are the server but various personal laptops. Development was done on a separate machine. All are accessing via the same URL. All users have same access. This is on our test site currently which would be switched to being production once migration/upgrade takes place.
Before current .WSP deployment we noticed the same issue but it was reverse, Machine #2 did all the updates but Machine #1 and #3 couldn't. Only thing we can think of was that those machines were the first to trigger the event after deployment.
I'm Not doing the .WSP install but our IT guy is(won't let us have access :/ but I understand) but below is the install commands he is running.
Add-SPSolution -LiteralPath "OurPath/ourFile.wsp"
Install-SPSolution -Identity ourIdentity -WebApplication http://myhost.com/ -GACDeployment
Below is the main part of the code
public class CreateWikiAndFolder : Microsoft.SharePoint.SPItemEventReceiver
{
public override void ItemAdded(SPItemEventProperties properties)
{
try
{
//this.DisableEventFiring();
base.EventFiringEnabled = false;
string sUrlOfWikiPage = string.Empty;
string sUrlOfNewFolder = string.Empty;
string sSubsiteRUL = string.Empty;
string sCurrentItemTitle = properties.ListItem["Title"].ToString();
string sWikiListName = "TR Wikis";
string sDocLibName = "Shared Documents";
string sTRListID = "TR Status";
if (sTRListID.ToUpper().Equals(properties.ListTitle.ToString().ToUpper()))
{
//Create the Folder
sUrlOfNewFolder = CreateFolder(properties.ListItem.Web, sDocLibName, sCurrentItemTitle);
//Create the Wiki
string ItemDispFormUrl = String.Concat(properties.ListItem.Web.Url, "/", properties.ListItem.ParentList.Forms[PAGETYPE.PAGE_DISPLAYFORM].Url, "?ID=", properties.ListItem.ID.ToString());
sUrlOfWikiPage = CreateWiki(properties.ListItem.Web, sWikiListName, sCurrentItemTitle, ItemDispFormUrl, sUrlOfNewFolder);
//Update the current TR Item
SPWeb myWeb = properties.ListItem.Web;
myWeb.AllowUnsafeUpdates = true;
SPListItem myListItem = properties.ListItem;
SPFieldUrlValue shareFolderURLValue = new SPFieldUrlValue();
shareFolderURLValue.Description = "Shared Folder";
shareFolderURLValue.Url = sUrlOfNewFolder ;
myListItem["SharedFolder"] = shareFolderURLValue;
myListItem.Update();
myWeb.AllowUnsafeUpdates = false;
}
base.EventFiringEnabled = true;
}
catch (Exception e)
{
//Currently throwing nothing
}
}
}
It could be a hardcoded path/url, however there is not enough information to identify the problem, I would be glad to update my answer with a more detailed theory if you provide more details or if you share some of your code.
Figured out the issue. I didn't include them with the above file code. But we were StreamWriting to a text file on the server to help us with debugging. Issue was with that, When user 1 was logged on their machine and the log files didn't exist, they would get generated. Now no other users then had read/write access to those files and so it errored out at our debug files for anyone else. But that Windows user could run it as much as they wanted as they were the owner of the file :/

Overwrite restricted application file?

I'm trying to manually patch my application. The application makes use of a Service which i make sure to stop and uninstall prior to attempting any overwriting of the application dll's.
The issue is that i can't overwrite, or even delete some of the dll files which are the core of the application, these dll files are used by the service i uninstalled first.
I use the following method to pass in the new file-path in order to replace the old DLL which is located inside the root directory of the application in C:\Program Files\AppName\
public static bool CopyFile(string newFile, string oldFile)
{
var newfile = new FileInfo(newFile);
var oldfile = new FileInfo(oldFile);
var f2 = new FileIOPermission(FileIOPermissionAccess.AllAccess, oldFile);
f2.AddPathList(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, newFile);
try
{
f2.Demand();
}
catch (SecurityException s)
{
Console.WriteLine(s.Message);
}
for (int x = 0; x < 100; x++)
{
try
{
File.Delete(oldfile.FullName);
newfile.CopyTo(oldfile.FullName, true);
return true;
}
catch
{
Thread.Sleep(200);
}
}
return false;
}
I just wish to provide a new file and remove the old one, replace it, overwrite it.... The application
Note: The application i run to do the patching runs as administrator.
Any idea?
I was able to fix this issue by making use of a "middle man" in other words, another application which downloads another executable and passes command line arguments to it.
Originally, my service would download an executable (call it Installer.exe). Installer.exe would then attempt to stop the service and patch the content, this did not work.
I now have the service running, it downloads "Installer.exe".
Installer.exe will load up and download PatchPayload.exe.
PatchPayload.exe runs and kills off the Service, uninstalls it and then download all required patch content from a centralized server and patch the service core files individually then install the service and run it again.

WMEncoder Throws COMException (0x80004005) Unspecified Error

So I'm running this code
public static void ConvertToWma(string inFile, string outFile, string profileName)
{
// Create a WMEncoder object.
WMEncoder encoder = new WMEncoder();
ManualResetEvent stopped = new ManualResetEvent(false);
encoder.OnStateChange += delegate(WMENC_ENCODER_STATE enumState)
{
if (enumState == WMENC_ENCODER_STATE.WMENC_ENCODER_STOPPED)
stopped.Set();
};
// Retrieve the source group collection.
IWMEncSourceGroupCollection srcGrpColl = encoder.SourceGroupCollection;
// Add a source group to the collection.
IWMEncSourceGroup srcGrp = srcGrpColl.Add("SG_1");
// Add an audio source to the source group.
IWMEncSource srcAud = srcGrp.AddSource(WMENC_SOURCE_TYPE.WMENC_AUDIO);
srcAud.SetInput(inFile, "", "");
// Specify a file object in which to save encoded content.
IWMEncFile file = encoder.File;
file.LocalFileName = outFile;
// Choose a profile from the collection.
IWMEncProfileCollection proColl = encoder.ProfileCollection;
proColl.ProfileDirectory = AssemblyInformation.GetExecutingAssemblyDirectory();
proColl.Refresh();
IWMEncProfile pro;
for (int i = 0; i < proColl.Count; i++)
{
pro = proColl.Item(i);
if (pro.Name == profileName)
{
srcGrp.set_Profile(pro);
break;
}
}
// Start the encoding process.
// Wait until the encoding process stops before exiting the application.
encoder.SynchronizeOperation = false;
encoder.PrepareToEncode(true);
encoder.Start();
stopped.WaitOne();
}
And I get a COMException (0x80004005) when encoder.PrepareToEncode gets executed.
Some notes:
1) The process is spawned by an ASP.NET web service so it runs as NETWORK SERVICE
2) inFile and outFile are absolute local paths and their extensions are correct, in addition inFile definitely exists (this has been a source of problems in the past)
3) The program works when I run it as myself but doesn't work in the ASP.NET context.
This says to me its a security permission issue so in addition I've granted Full Control to the directory containing the program AND the directories containing the audio files to NETWORK SERVICE. So I really don't have any idea what more I can do on the security front. Any help?
Running WM Encoder SDK based app in windows service is not supported. It uses hidden windows for various reasons, and there isn't a desktop window in service. DRM would certainly fail with no user profile. Besides, even when you make your service talk to WME instance on a user's desktop, Microsoft only supports 4 concurrent requests per machine because the global lock in WME (I know, not pretty programming, but WME is old). For more scalable solutions, consider Windows Media Format SDK.
You may want to move your WM Encoder based app to Expression Encoder SDK as WM Encoder's support is ending.

What is the Fastest way to read event log on remote machine?

I am working on an application which reads eventlogs(Application) from remote machines. I am making use of EventLog class in .net and then iterating on the Log entries but this is very slow. In some cases, some machines have 40000+ log entries and it takes hours to iterate through the entries.
what is the best way to accomplish this task? Are there any other classes in .net which are faster or in any other technology?
Man, I feel your pain. We had the exact same issue in our app.
Your solution has a branch depending on what server version you're running on and what server version your "target" machine is running on.
If you're both on Vista or Windows Server 2008, you're in luck. You should look at System.Diagnostics.Eventing.Reader.EventLogQuery and System.Diagnostics.Eventing.Reader.EventLogReader. These are new in .net 3.5.
Basically, you can build a query in XML and ship it over to run on the remote computer. Maybe you're just searching for events of a specific type, or maybe just new events from a specific point in time. The search runs on the remote machine, and then you just get back the matching events. The new classes are much faster than the old .net 2.0 way, but again, they are only supported on Vista or Windows Server 2008.
For our app when the target is NOT on Vista/Win2008, we downloaded the raw .evt file from the remote system, and then parsed the file using its binary format. There are several sources of data about the event log format for .evt files (pre-Vista), including link text and an article I recall on codeproject.com that had some c# code.
Vista and Windows Server 2008 machines use a new .evtx format that is a new format, so you can't use the same binary parsing approach across all versions. But the new EventLogQuery and EventLogReader classes are so fast that you won't have to. It's now perfectly speedy to just use the built-in classes.
Event Log Reader is horribly slow... too slow. WTF Microsoft?
Use LogParser 2.2 - Search for C# and LogParser on the Internet (or you can use the log parser commands from the command line). I don't want to duplicate the work already contributed by others.
I pull the log from the remote system by having the log exported as an EVTX file. I then copy the file from the remote system. This process is really quick - even with a network that spans the planet (I had issues with having the log exported to a network resource). Once you have it local, you can do your searches and processing.
There are multiple reasons for having the EVTX - I won't get into the reasons why we do this.
The following is a working example of the code to save a copy of the log as an EVTX:
(Notes: "device" is the network host name or IP. "LogName" is the name of the log desired: "System", "Security", or "Application". outputPathOnRemoteSystem is the path on the remote computer, such as "c:\temp\%hostname%.%LogName%.%YYYYMMDD_HH.MM%.evtx".)
static public bool DumpLog(string device, string LogName, string outputPathOnRemoteSystem, out string errMessage)
{
bool wasExported = false;
string errorMessage = "";
try
{
System.Diagnostics.Eventing.Reader.EventLogSession els = new System.Diagnostics.Eventing.Reader.EventLogSession(device);
els.ExportLogAndMessages(LogName, PathType.LogName, "*", outputPathOnRemoteSystem);
wasExported = true;
}
catch (UnauthorizedAccessException e)
{
errorMessage = "Unauthorized - Access Denied: " + e.Message;
}
catch (EventLogNotFoundException e)
{
errorMessage = "Event Log Not Found: " + e.Message;
}
catch (EventLogException e)
{
errorMessage = "Export Failed: " + e.Message + ", Log: " + LogName + ", Device: " + device;
}
errMessage = errorMessage;
return wasExported;
}
A good Explanation/Example can be found on MSDN.
EventLogSession session = new EventLogSession(Environment.MachineName);
// [System/Level=2] filters out the errors
// Where "Log" is the log you want to get data from.
EventLogQuery query = new EventLogQuery("Log", PathType.LogName, "*[System/Level=2]");
EventLogReader reader = new EventLogReader(query);
for (EventRecord eventInstance = reader.ReadEvent();
null != eventInstance;
eventInstance = reader.ReadEvent())
{
// Output or save your event data here.
}
When waiting 5-20 minutes with the old code this one does it in less than 10 seconds.
Maybe WMI can help you:
WMI with C#
Have you tried using the remoting features in powershell 2.0? They allow you to execute cmdlets (like ones to read event logs) on remote machines and return the results (as objects, of course) to the calling session.
You could place a Program at those machines that save the log to file and sends it to your webapplication i think that would be alot faster as you can do the looping local but im not sure how to do it so i cant ive you any code :(
I recently did such thing via WCF callback interface however my clients interacted with the server through WCF and adding a WCF Callback was easy in my project, full code with examples is available here
Just had the same issue and want to share my solution. It makes a search through application, system and security eventlogs from 260 seconds (using EventLog) about a 100 times faster (using EventLogQuery).
And this in a way where it is possible to check if the event message contains a pattern or any other check without the requirement of FormatDescription().
My trick is to use the same mechanism as PowerShells Get-WinEvent does and then pass it through the result check.
Here is my code to find all events within last 4 days where the event message contains a filter pattern.
string[] eventLogSources = {"Application", "System", "Security"};
var messagePattern = "*Your Message Search Pattern*";
var timeStamp = DateTime.Now.AddDays(-4);
var matchingEvents = new List<EventRecord>();
foreach (var eventLogSource in eventLogSources)
{
var i = 0;
var query = string.Format("*[System[TimeCreated[#SystemTime >= '{0}']]]",
timeStamp.ToUniversalTime().ToString("o"));
var elq = new EventLogQuery(eventLogSource, PathType.LogName, query);
var elr = new EventLogReader(elq);
EventRecord entryEventRecord;
while ((entryEventRecord = elr.ReadEvent()) != null)
{
if ((entryEventRecord.Properties)
.FirstOrDefault(x => (x.Value.ToString()).Contains(messagePattern)) != null)
{
matchingEvents.Add(entryEventRecord);
i++;
}
}
}
Maybe that the remote computers could do a little bit of computing. So this way your server would only deal with relevant information. It would be a kind of cluster using the remote computer to do some light filtering and the server would the the analysis part.

Categories

Resources