C# / Webservice app on server throwing strange exception - c#

We use ADP for employee information. I had to create a small app that called some web services that ADP has to pull employee information. The app is fairly procedural..not really object orientated in a sense. Basically I go through some web services to pull general information, work information, employee status, etc.
I have most of this data writing out to a text file as a log so I can ensure that everything is working correctly. Finally got it all done, and it works perfect on my local machine. Thought I'd just copy the entire structure onto a server and use windows scheduler to schedule the exe to run nightly (once a day). When it tries to run the app it looks like it is dying when it calls the first web service. The task scheduler log says:
""ADP.job" (ADP.exe)
Started 2/11/2010 2:14:34 PM
"ADP.job" (ADP.exe)
Finished 2/11/2010 2:14:38 PM
Result: The task completed with an exit code of (e0434f4d)."
So I checked the event viewer and it says this:
EventType clr20r3, P1 adp.exe, P2 1.0.0.0, P3 4b745bb9, P4 adp, P5 1.0.0.0, P6 4b745bb9, P7 289, P8 2d, P9 system.io.filenotfoundexception, P10 NIL.
For more information, see Help and Support Center at http://go.microsoft.com/fwlink/events.asp.
I put in some console.writelines to see where it is failing...
Here is a simple example of main:
static void Main(string[] args)
{
OpenTextFile();
Console.WriteLine("About to process employee work information...");
tw.WriteLine("About to process employee work information...");
//work info service
EmpWorkInfo();
}
And inside of opentextfile:
public static void OpenTextFile()
{
//used to log data
String sLogName;
Console.WriteLine("Inside of opentextfile");
if (Directory.Exists(logPath))
{
//directory exists
}
else
{
Directory.CreateDirectory(logPath);
}
Console.WriteLine("Inside of opentextfile2");
sLogName = "log_" + DateTime.Today.ToString("MM_dd_yyyy") + ".txt";
tw = new StreamWriter(logPath + sLogName);
}
I see all the console.writelines on the server but as soon as it hits this line from main:
EmpWorkInfo();
Thats when all hell breaks lose (basically it doesn't work). The EmpWorkInfo() is simply a function to get work related information from a web service (as I said this works locally).
static void EmpWorkInfo()
{
Console.Writeline("THIS NEVER PRINTS!!!");
SQLClass s=null;
// Create the web service proxy client.
GetEmployeeWorkInfoService oService = new GetEmployeeWorkInfoService();
oService.Timeout = Int32.MaxValue;
// Serialize the UsernameToken into XML.
// Create the UsernameToken as defined in the WS-I secure profile.
UsernameToken oUsernameToken = new UsernameToken(USERNAME, SECRET);
System.Xml.XmlElement oSecurityHeaderXml =
oUsernameToken.GetXml(new System.Xml.XmlDocument());
ADP.GetEmployeeWorkInfoWebService.SecurityHeaderType oSecurityHeader = new ADP.GetEmployeeWorkInfoWebService.SecurityHeaderType();
oSecurityHeader.Any = new System.Xml.XmlElement[] { oSecurityHeaderXml };
oService.Security = oSecurityHeader;
GetEmployeeWorkInfoRequestFilter oFilter = new GetEmployeeWorkInfoRequestFilter();
//filter by thyssenkrupp company
oFilter.Companies = new String[] { COMPANY_IDENTIFIER };
GetEmployeeWorkInfoRequest oRequest = new GetEmployeeWorkInfoRequest();
oRequest.Filter = oFilter;
try
{
EmployeeWorkInfoType[] arPersonalInfo = oService.GetEmployeeWorkInfo(oRequest);
try
{
s = new SQLClass();
}
catch (Exception e)
{
throw new System.Exception(e.Message.ToString());
}
for (int i = 0; i < arPersonalInfo.Length; i++)
{
String stID = arPersonalInfo[i].EmployeeKey.Identifier.EmployeeId; //employee number
String stEmailAddress = arPersonalInfo[i].WorkInfo.EmailAddress; //employee email address (work)
String stFax = arPersonalInfo[i].WorkInfo.Fax; //employee fax number
DateTime dtHireDate = arPersonalInfo[i].WorkInfo.OriginalHireDate;
String stPhone = arPersonalInfo[i].WorkInfo.Phone; //employee phone number
String stWireless = arPersonalInfo[i].WorkInfo.Wireless; //employee wireless number
tw.WriteLine("Processing ID:" + stID + " Email Work: " + stEmailAddress + " Fax Work: " + stFax + " Hire Date: " + dtHireDate + " Phone Work: " + stPhone + " Wireless Work: " + stWireless + ".");
Console.WriteLine("Processing ID:" + stID + " Email Work: " + stEmailAddress + " Fax Work: " + stFax + " Hire Date: " + dtHireDate + " Phone Work: " + stPhone + " Wireless Work: " + stWireless + ".");
s.SetSQLCommand("dbo.ADP_uiEmployeeWorkInfo");
s.AddSQLCmdParameter("#EmployeeNumber", System.Data.SqlDbType.VarChar, stID);
s.AddSQLCmdParameter("#EmailAddress", System.Data.SqlDbType.VarChar, stEmailAddress);
s.AddSQLCmdParameter("#Fax", System.Data.SqlDbType.VarChar, stFax);
s.AddSQLCmdParameter("#HireDate", System.Data.SqlDbType.DateTime, dtHireDate);
s.AddSQLCmdParameter("#Telephone", System.Data.SqlDbType.VarChar, stPhone);
s.AddSQLCmdParameter("#Mobile", System.Data.SqlDbType.VarChar, stWireless);
s.SQLExecuteNonQuery();
Console.WriteLine("Processed ID:" + stID + " Email Work: " + stEmailAddress + " Fax Work: " + stFax + " Hire Date: " + dtHireDate + " Phone Work: " + stPhone + " Wireless Work: " + stWireless + ".");
Console.WriteLine(Environment.NewLine);
}
s.CloseSQLDB();
s.Dispose();
}
//catch any exception from adp side.
catch (Exception e)
{
throw new System.Exception(e.Message.ToString());
}
}
This functions code is irrelevant (its ugly but do not let that bother you, the code works...). My issue is I cannot even get to the first console.writeline of that function. Is there anything special I need to do when it comes to working with webservices?
Edit
Logpath is defined as simply a static string outside of main:
private static string logPath = Environment.CurrentDirectory + "\\log\\";

I suspect that your application is not able to load the types referenced in that function - EmpWorkInfo.
1) Can you run this application on the target server in a commannd window (cmd.exe) ?
2) Are you using any assemblies from ADP that are installed in the global assembly cache (GAC)? Run "gacutil -l" on your localmachine to see if you are using any assemblies from ADP that are installed in thr gac. If they are, you will need to install these into the machine on which you are running the app.

Does logPath have a trailing backslash? Either way, you ought to use Path.Combine, rather than the string catenation operator (+).

What happens if you comment out all the code in EmpWorkInfo() apart from the first Console.Writeline? Does it still not get written out?

Found out I need the Microsoft.Web.Services3 dll installed on the server.

Continuation on "feroze" answer;
If you want to figure out if the 'loading of dependencies' is causing you grief here, i suggest using the "FUSLOGVW.EXE" tool *(part of .Net). When you run this it will give you a little dialog window with a few options. Create a directory somewhere (like "c:\temp\fusion_logs"), set the mode of FUSLOGVW to "log bind failures only", "custom location->c:\temp\fusion_logs".
Now restart your application and check that it failed. Now look into your fusion_logs directory. This should give you sub directories with different (maybe only 1 for now) application names. Inside each directory you will find the log files. These log files contain the "failed assembly loads" and who (which calling assembly) caused them.
They might help your hunt for a working application,
Hope this helps,
Edit: Posted this after you found the cause. The fuslogvw.exe would have shown you the missing assembly.

Related

C# File.copy and Directory.CreateDirectory working on Win10 but in Win7 it appends folder to parent folder

The same code, one on windows 10, the other on windows 7.
The idea is to have a directory from a network drive replicate over to a local drive.
On windows 10, the machine I am writing it on, it works perfectly fine as intended.
On windows 7, the target machine, it 'works' but the sub folder structure is messed up.
Example,
C:\target -> the target location
C:\targetNewFolderName1 -> What its being copied to
C:\targetNewFolderName2
C:\targetNewFolderNameN
When it should be doing this below,(which it is, on windows 10, not on windows 7)
C:\target -> the target location
C:\target\NewFolderName1 -> What its being copied to
C:\target\NewFolderName2
C:\target\NewFolderNameN
Master is a network directory, #"\\server\fu\bar\target"
Slave is a local directory, #"C:\target"
These are passed to the function.
Function header, private void CheckMasterToSlave(string MasterPath, string SlavePath, string BackupPath, string[] MasterFilesList, string[] SlaveFilesList)
The below code snipit is within a foreach; foreach (string master in MasterFilesList).
log.Info(master + " doesnt exist, copying");
string directoryCheck = (SlavePath + master.Substring(MasterPath.Length)).Substring(0,
(SlavePath + master.Substring(MasterPath.Length)).LastIndexOf("\\"));
if (!Directory.Exists(directoryCheck))
{
log.Debug(directoryCheck + " Directory not present, touching.");
try
{
Directory.CreateDirectory((SlavePath +
master.Substring(MasterPath.Length)).Substring(0, (SlavePath +
master.Substring(MasterPath.Length)).LastIndexOf("\\")));
}
catch
{
log.Error(master + " directory failed to be created in slave environment.");
}
}
try
{
File.Copy(master, SlavePath + master.Substring(MasterPath.Length));
log.Info(SlavePath + master.Substring(MasterPath.Length) + " Successfully created.");
BackupFile(master.Replace(MasterPath, SlavePath), BackupPath, SlavePath);
}
catch
{
log.Error(master + " failed to copy, backup has been halted for this file.");
}
I do not understand why this works as intended on windows 10 but moving it to windows 7 causes this issue.
What would be causing this and how can I stop the new folder from appending to the parent folder in windows 7?
Use Path.Combine to build a path name from different path components instead of just using string concatenation.
Alright, I am stupid and forgot to change to release. When changes that NineBerry mentioned were made. It did work.
I still do not understand why the original did work on windows 10 but not on windows 7. Especially since the BackupFile portion does the same thing as the old 'wrong' way. But both work now.
Regardless, here is the updated bit.
log.Info(master + " doesnt exist, copying");
string[] EndDirectoryFile = master.Substring(MasterPath.Length).Split('\\');
string[] EndDirectory = new string[EndDirectoryFile.Length-1];
for (int i = 0; i < EndDirectoryFile.Length - 1; i++)
{
EndDirectory[i] = EndDirectoryFile[i];
}
string directoryCheck = Path.Combine(SlavePath, Path.Combine(EndDirectory));
if (!Directory.Exists(directoryCheck))
{
log.Debug(directoryCheck + " Directory not present, touching.");
try
{
Directory.CreateDirectory(directoryCheck);
}
catch
{
log.Error(master + " directory failed to be created in slave environment.");
}
}
try
{
File.Copy(master, SlavePath + master.Substring(MasterPath.Length));
log.Info(SlavePath + master.Substring(MasterPath.Length) + " Successfully created.");
BackupFile(master.Replace(MasterPath, SlavePath), BackupPath, SlavePath);
}
catch
{
log.Error(master + " failed to copy, backup has been halted for this file.");
}

How does this log method work in a .NET application?

I am working on a .NET project using C# and I have the following doubt.
I have this method that write some error information into a .log file in a specific directory on my file system:
private static void writeErrorLog(string error)
{
string date = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string currDir = Directory.GetCurrentDirectory();
System.IO.File.AppendAllText(currDir + "\\FILE\\LOG\\Error_" + date + ".txt", error);
}
Ok this writeErrorLog() method will be called into some try catch block of my code, something like this:
try
{
currentAttachmentFileData = currentAttachmentFile.OpenBinary();
currentAttachementModel = new AttachmentModel(currentAttachment, currentAttachmentFileData);
attachmentsModelList.Add(currentAttachementModel);
}
catch (Exception ex)
{
//writeLog(2, String.Format("Unable to read the attachment, it may be corrupted {0} - {1}", fileName, ex.Message));
writeErrorLog("Errore inserimento attachment. Numero protocollo: " + recNumber
+ " Data protocollo: " + recDate
+ " Nome attachment: " + currentAttachmentFile
+ " INFO: " + ex.ToString() + " | " + ex.Message + " | " + ex.StackTrace);
}
It happens in different places of my code.
My doubt is: the file is the same, so it means that it will be added a new line to this file every time that an error occours.
Is it my reasnong correct?
The file name is string date = DateTime.Now.ToString("yyyyMMdd_HHmmss"); so it changes every second.
You should definitely add some abstraction here and hide writeErrorLog behind an interface. Behind the interface you could have your own implementation of writeErrorLog, but as others suggested I would strongly recommend using libs over your custom solution.
More on available libraries:
benchmarking-5-popular-net-logging-libraries
dotnetlogging.com

Process.GetCurrentProcess().MainWindowTitle of Revit retrieves empty string ""

I am creating a plugin for Revit that registers several events within its application.
For every time an event happens, a line is writen on a txt file telling me about the event such as:
The user opened a document on Autodesk Revit 2019 (...)
I am obtaining the "Autodesk Revit 2019" (name of application) by getting the name of the MainWindowTitle of the application like so: Process.GetCurrentProcess().MainWindowTitle
public static string originalString = Process.GetCurrentProcess().MainWindowTitle;
(...)
Trace.WriteLine("O utilizador " + Environment.UserName + " abriu o " + originalString + " a " + DateTime.Now + " (ApplicationInitializedEventArgs)");
Which writes in the txt file:
O utilizador rita.aguiar abriu o a 20/09/2018 10:36:42 (ApplicationInitializedEventArgs)
As you can read, it did not write on the txt file "Autodesk Revit 2019 - [Home]" between the words "o" and "a" as I hoped for.
If I had writen Process.GetCurrentProcess().MainWindowTitle directly on the Trace.WriteLine I would have obtained "Autodesk Revit 2019 - [Home]", but I wish to write an assigned name instead.
How to successfully write "Autodesk Revit 2019 - [Home]" by assigning a name to Process.GetCurrentProcess().MainWindowTitle?
Later I would like to obtain this name by instead getting just Autodesk Revit 2019 like so:
public static string originalString = Process.GetCurrentProcess().MainWindowTitle;
public static string[] splittedString = originalString.Split("-".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
public static string AppName = splittedString[0];
Any help would be appretiated!
As I suggested answering your similar question on assigning a name to a string C# in the Revit API discussion forum, I would look at the code executing step by step in the debugger.
Then you can see for yourself exactly what is going on.
You could also add some more intermediate lines and variables for absolute clarity:
string originalString = Process
.GetCurrentProcess()
.MainWindowTitle;
string s2 = "O utilizador "
+ Environment.UserName
+ " abriu um documento no "
+ originalString + " a " + DateTime.Now;
//or use string interpolation:
//https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
string s3 = $"O utilizador {Environment.UserName} abriu um documento no {originalString} a {DateTime.Now}";
Trace.WriteLine( s2 );
Trace.WriteLine( s3 );
The debugger is good!
Invaluable, in fact.
Some of the comments on the discussion how to determine Revit demo mode show how you can access the Revit main window title.
To be able to store the Main Window Title in a name of type string I had to first declare each string outsite of the methods I am using:
string originalString;
string[] splittedString;
string AppName;
After declaring each string name I obtained the Application Name "Autodesk Revit 2019" by including each definition inside the first private method, which was created to register when the Revit application is opened. This had to be done inside a method because it is only after the application is launched that we can access the MainWindowTitle. This is the reason why I was getting an empty string "" when trying to obtain the MainWindowTitle the moment the application is starting to launch, but before it has completely launched and thus opened a Window with such Title.
private void DumpEventArgs(ApplicationInitializedEventArgs args_initialized)
{
originalString = Process.GetCurrentProcess().MainWindowTitle;
splittedString = originalString.Split(new[] { " -" }, StringSplitOptions.RemoveEmptyEntries);
AppName = splittedString[0];
//StreamWriter file = new StreamWriter("C://Users//" + Environment.UserName + "//AppData//Roaming//Autodesk//" + Environment.UserName + ".txt", append: true);
//MessageBox.Show($"O utilizador {Environment.UserName} iniciou o {AppName} a {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}");
file.WriteLine($"{Environment.UserName},{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")},{AppName},iniciar");
}
And I could use this same string later when required because it has been declared outside the method, for example here I needed to write AppName again:
private void DumpEventArgs(DocumentSavedEventArgs args_saved)
{
//StreamWriter file = new StreamWriter("C://Users//" + Environment.UserName + "//AppData//Roaming//Autodesk//" + Environment.UserName + ".txt", append: true);
//MessageBox.Show($"O utilizador {Environment.UserName} guardou um documento no {AppName} a {DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")}");
file.WriteLine($"{Environment.UserName},{DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss")},{AppName},guardar");
}
Finally AppName retrieves what I wanted: "Autodesk Revit 2019".

Porting winform application to run on raspberry PI

I have a c# winform application that I want to port to run on my new Raspberry PI 3. I'm in moaning mode because I thought that my app would just run. That is not the case at all. My winform app uses quart. net, the aforge library and common .net libraries such as system.configuration.
I though I would start with my logging class as someone had mentioned that non UI code should be easy to convert if anything needed changing at all.
This looks like I'm going to have to reinvent the wheel. To be specific for startes have a look at the function below. Any code that uses system.configuration will not work.
Is there any easier way of getting my app to work or do I have to literally convert almost all my code. Is the aforge library even going to work on the PI?
Is quart.net going to work?
Right now I feel like giving up and buying a small windows PC that runs "proper" windows.
C# Winform Code
class Logging
{
public void Write_To_Log_File(String Message, String Procedure, String Error_Code, String Error_String)
{
try
{
// If the log file is bigger than allowed size then archive
if (File.Exists(#ConfigurationManager.AppSettings["LogSavePath"]))
{
FileInfo file = new FileInfo(#ConfigurationManager.AppSettings["LogSavePath"]);
if (file.Length > Convert.ToInt32(ConfigurationManager.AppSettings["FileLogSizeLimit"]))
{
// Rename the file
File.Move(#ConfigurationManager.AppSettings["LogSavePath"], #ConfigurationManager.AppSettings["LogSavePath"] + string.Format("{0:yyyy-MM-dd_hh-mm-ss-tt}", DateTime.Now) + ".csv");
}
}
// If log file does not exist then create it and add the headers
if (File.Exists(#ConfigurationManager.AppSettings["LogSavePath"]))
{
}
else
{
// Create the file
System.IO.File.Create("LogSavePath");
// Add data
string[] Headers = { "Time" + "," + "_Message" + "," + "Procedure" + "," + "Error_Code" + "," + "Error_String" };
System.IO.File.AppendAllLines(#ConfigurationManager.AppSettings["LogSavePath"], Headers);
}
if (File.Exists(#ConfigurationManager.AppSettings["LogSavePath"]))
{
string[] Log = { DateTime.Now.ToString() + "," + Message + "," + Procedure + "," + Error_Code + "," + Error_String };
System.IO.File.AppendAllLines(#ConfigurationManager.AppSettings["LogSavePath"], Log);
}
}
catch
{
}
}
}
Microsoft launched a Windows 10 IoT Core Porting Tool for this purpose. This can assist you in migrating from Win32 apps and libraries to Windows 10 IoT Core apps. More details here: https://developer.microsoft.com/en-us/windows/iot/win10/tools/iotapiportingtool

SharpSVN Repo-Browser

Viewing the repository data of TortoiseSVN is done by right click on a file -> TortiseSVN -> Repo-Browser.
I would like to get this data using SharpSVN, in order to retrieve the name of lock owner.
Is it possible? How? Where does this data being saved?
I've tried to get a lock owner name using the following code, however, I get the lock infirmation just in case I'm on the machine where the lock was done from. If I'm another user, I cannot get the lock information.
using (SvnClient client = new SvnClient())
{
client.GetInfo(#"path\to\working\copy\file.xml", out info);
SvnLockInfo lc = info.Lock;
if (lc != null)
{
MessageBox.Show("Owner: " + lc.Owner + "\n" +
"Creation time: " + lc.CreationTime + "\n" +
"Comment: " + lc.Comment + "\n" +
"Expiration time: " + lc.ExpirationTime);
}
}
Even when I set the target as the repository URI- instead of path to the local working copy I get the same result:
Uri target = client.GetUriFromWorkingCopy(#"path\to\working\copy\file.xml");
client.GetInfo(target, out info);
The way I can see the lock owner name from another working copy is, as mentioned, by right click on file -> repo-browser.
Any ideas how to perform it programmatically?

Categories

Resources