Visual studio c# code produce difference result without using debugger - c#

When I try to debug my code with debugger with F11 (Step Into), my code produced the expected result. When I try to run the code without debugger(without break point), the looping in my code produced unexpected result; to be specific, the looping part only loop for 1 times and terminated, I am confused here, anyone have any idea about this? Below is the loop I mentioned which produced unexpected result.
public bool CopyFileAndFolder(string sourceFolder, string replacePath)
{
bool result = false;
try
{
foreach (string extractPath in Directory.GetDirectories(sourceFolder, "*", SearchOption.AllDirectories))
{
string destFolder = extractPath.Replace(sourceFolder, replacePath);
if (!Directory.Exists(destFolder))
Directory.CreateDirectory(destFolder);
}
foreach (string extractFile in Directory.GetFiles(sourceFolder, "*.*", SearchOption.AllDirectories))
{
string destFile = extractFile.Replace(sourceFolder, replacePath);
File.Copy(extractFile, destFile, true);
}
result = true;
}
catch (Exception)
{
result = false;
}
return result;
}
The complete code, i called the method above with this method:
private bool StartFileRollBackProcess()
{
bool result = false;
string backupFolder = Path.Combine(ConfigurationManager.AppSettings["BackupPath"], completeVersionNumber);
string destBackUpFolder = Directory.GetParent(iisConf.PhysicalPath).FullName;
try
{
DirectoryInfo folderToBeDelete = new DirectoryInfo(destBackUpFolder);
folderToBeDelete.Delete(true);
if (Directory.Exists(backupFolder))
{
Directory.CreateDirectory(destBackUpFolder);
result = CopyFileAndFolder(backupFolder, destBackUpFolder);
if (result)
{
ErrorMsg = "Copy process Failed,Your File has rolled back to previous version";
IsErrorDetected = true;
}
else
{
ErrorMsg = "copy got error";
IsErrorDetected = true;
}
}
}
catch (Exception)
{
ErrorMsg = "Error during roll up process";
IsErrorDetected = true;
}
return result;
}

Related

C#: Add a new check without affecting existing checks

I hope I can explain my scenario the best I can.
I have code that when the "Load" button is clicked, all file names (if any) located in a predefined network directory path, are loaded to a text-area.
Currently there can be .txt, .xml files.
Contents could look like:
first_file_found.xml
second_file_found.xml
third_file_found.txt
Also, in the code there is another function "isCoValid" that performs an additional validation of the contents of these files, based on return value (true/false) of this function, the "Process" button is enabled:
if (IsFlatFile(fileName) || IsXMLFile(fileName))
{
if (isCoValid(fileName))
{
btnProcess.Enabled = true;
}
else
{
btnProcess.Enabled = false;
break;
}
}
Now I have to add a .csv file type, but this file does not required to perform the isCoValid function.
The text-area contents now look like:
first_file_found.xml
second_file_found.xml
third_file_found.txt
fourht_file_found.csv
My request for help is to ask how can the check to find out if there is a CSV file can be done, and also controlling the enabling of the "Process" button, but still respect the existing check for .txt, and .xml and the validation of contents?
I might have xml and text files, that aren't valid, but I still need to be able to process the .csv. file.
I did change it like this:
if (IsFlatFile(fileName) || IsXMLFile(fileName))
{
if (isCoValid(fileName))
{
btnProcess.Enabled = true;
}
else
{
btnProcess.Enabled = false;
break;
}
}
if (IsCSVFile(fileName))
{
btnProcess.Enabled = true;
}
But I am sure this is not correct and I would like to ask for some help if possible.
I hope I explained my problem with some clarity and straightforwardness, if not, please let me know and I can try to provide more information.
Thank you,
Erasmo
Additional Code Requested
public bool IsFlatFile(string FileName)
bool ReturnValue = false;
if (FileName.ToUpper().Right(4) == ".TXT")
{
if ((FileName.Substring(0, 2).ToUpper() == "MN") ||
(FileName.Substring(0, 2).ToUpper() == "CH"))
{
ReturnValue = true;
}
}
return ReturnValue;
}
public bool IsXMLFile(string FileName)
bool ReturnValue = false;
if (FileName.ToUpper().Right(4) == ".XML")
{
if ((FileName.Substring(0, 2).ToUpper() == "TR") ||
(FileName.Substring(0, 2).ToUpper() == "SK"))
{
ReturnValue = true;
}
}
return ReturnValue;
}
protected bool isCoValid(string fName)
{
bool retCode = false;
Parameters parms;
var reader = new AppSettingsReader();
Application app = new Application();
Package package = null;
try
{
package = app.LoadPackage(packagePath + "ValidateContents.dtsx", null);
parms = package.Parameters;
parms["ID"].Value = "";
parms["ImportFileName"].Value = fName;
parms["UserID"].Value = userName;
DTSExecResult results = package.Execute();
if (results == Microsoft.SqlServer.Dts.Runtime.DTSExecResult.Failure)
{
foreach (Microsoft.SqlServer.Dts.Runtime.DtsError local_DtsError in package.Errors)
{
retCode = false;
resultText = resultText + "DTSX Package Execution results: " + local_DtsError.Description.ToString() + Environment.NewLine;
}
}
else
{
resultText = resultText + "Successful Process Completion." + Environment.NewLine + Environment.NewLine;
string sqlStr = "SELECT TOP 1 * FROM Validation WHERE Type = 'VALCO' AND CAST(CreatedDate AS DATE) = CAST(GETDATE() AS DATE)";
DataTable dt = new DataTable();
dt = GetDataSet(sqlStr);
if (dt.Rows.Count > 0)
{
foreach (DataRow row in dt.Rows)
{
if (row["Status"].ToString() == "Valid")
{
retCode = true;
resultText = "Output: Valid" + Environment.NewLine + "Press the 'Process' button to proceed.";
}
else
{
retCode = false;
resultText = "Output: " + row["Status"].ToString() + Environment.NewLine + "Validation Fail: " + row["Error"].ToString();
}
}
}
else
{
resultText = "Unable to read Validation Table for this file.";
retCode = false;
}
}
}
catch (Exception)
{
throw;
}
return retCode;
}
Your code will look like so:
if (IsFlatFile(fileName) || IsXMLFile(fileName) || IsCSVFile(fileName))
{
btnProcess.Enabled = isCoValid(fileName);
if (!btnProcess.Enabled) break;
}
public static bool IsCSVFile(string FileName) =>
Path.GetExtension(FileName).Equals(".csv", StringComparison.OrdinalIgnoreCase);
when you write your own IsCSVFile() method and update isCoValid() method to fit your needs.
Sorry, but I can't guess what happens inside classes that are used in isCoValid() method.

Throw exception in test method using MSTest

I'm using MSTest to write test cases for my application.
I have a method where files are moved from one directory to another directory. Now when I run code coverage, it shows that the catch block is not covered in code coverage.
This is my code as below.
class Class1
{
public virtual bool MoveFiles( string fileName)
{
bool retVal = false;
try
{
string sourcePath = "PathSource";
string destinationPath = "DestPath";
if (Directory.Exists(sourcePath) && Directory.Exists(destinationPath))
{
string finalPath = sourcePath + "\\" + fileName ;
if (Directory.Exists(finalPath))
{
File.Move(finalPath, destinationPath);
retVal = true;
}
}
}
catch (Exception ex)
{
LogMessage("Exception Details: " + ex.Message);
retVal = false;
}
return retVal;
}
}
The test method for the above code is this.
[TestMethod()]
public void MoveFilesTest()
{
string filename = "test";
Class1 serviceObj = new Class1();
var result = serviceObj.MoveFiles(filename);
Assert.IsTrue(result);
}
When I run my code coverage, it shows only the try block is covered and not the catch block. So in order to do that, I need to write another test method and generate an exception and test method will look something like this.
[TestMethod()]
public void MoveFilesTest_Exception()
{
string filename = "test";
Class1 serviceObj = new Class1();
ExceptionAssert.Throws<Exception>(() => serviceObj.MoveFiles(filename));
}
Can anyone help to create an exception for this code as I couldn't do that or at least guide me how to do it?
Many thanks!
You can use the Expected Exception Attribute in your tests to indicate that an exception is expected during execution.
The following code will test for invalid characters in the filename and should raise an ArgumentException since > is an invalid character in filenames:
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void InvalidCharacterInFileNameTest()
{
string filename = "test>";
Class1 serviceObj = new Class1();
serviceObj.MoveFiles(filename);
}
Update:
Since the Directory.Exists() 'supresses' any exception that might occur, you also need to change the code in your function to throw an exception if the source file does not exist or is invalid.
This is just an example to show how it can be implemented but your code could look similar to this:
public virtual bool MoveFiles(string fileName)
{
bool retVal = false;
try
{
string sourcePath = "PathSource";
string destinationPath = "DestPath";
if (Directory.Exists(sourcePath) && Directory.Exists(destinationPath))
{
string finalPath = sourcePath + "\\" + fileName;
if (Directory.Exists(finalPath))
{
File.Move(finalPath, destinationPath);
retVal = true;
}
else
{
throw new ArgumentException("Source file does not exists");
}
}
}
catch (Exception ex)
{
LogMessage("Exception Details: " + ex.Message);
retVal = false;
}
return retVal;
}

How can i make the method to return a List of files only and not also directories?

In constructor. filePathList is List
filePathList = SearchAccessibleFilesNoDistinct(rootDirectory, null).ToList();
And the SearchAccessibleFilesNoDistinct method
IEnumerable<string> SearchAccessibleFilesNoDistinct(string root, List<string> files)
{
if (files == null)
files = new List<string>();
if (Directory.Exists(root))
{
foreach (var file in Directory.EnumerateFiles(root))
{
string ext = Path.GetExtension(file);
if (!files.Contains(file) && ext == textBox2.Text)
{
files.Add(file);
}
}
foreach (var subDir in Directory.EnumerateDirectories(root))
{
try
{
SearchAccessibleFilesNoDistinct(subDir, files);
files.Add(subDir);
}
catch (UnauthorizedAccessException ex)
{
// ...
}
}
}
return files;
}
Then i make loop over the List filePathList
foreach (string file in filePathList)
{
try
{
_busy.WaitOne();
if (worker.CancellationPending == true)
{
e.Cancel = true;
return;
}
bool reportedFile = false;
for (int i = 0; i < textToSearch.Length; i++)
{
if (File.ReadAllText(file).IndexOf(textToSearch[i], StringComparison.InvariantCultureIgnoreCase) >= 0)
{
resultsoftextfound.Add(file + " " + textToSearch[i]);
if (!reportedFile)
{
numberoffiles++;
MyProgress myp = new MyProgress();
myp.Report1 = file;
myp.Report2 = numberoffiles.ToString();
myp.Report3 = textToSearch[i];
backgroundWorker1.ReportProgress(0, myp);
reportedFile = true;
}
}
}
numberofdirs++;
label1.Invoke((MethodInvoker)delegate
{
label1.Text = numberofdirs.ToString();
label1.Visible = true;
});
}
catch (Exception)
{
restrictedFiles.Add(file);
numberofrestrictedFiles ++;
label11.Invoke((MethodInvoker)delegate
{
label11.Text = numberofrestrictedFiles.ToString();
label11.Visible = true;
});
continue;
}
The problem is that in the catch part the restrictedFiles is just directories not files. Since filePathList contain files and directories and when it's trying to search in a directory it's getting to the catch. It's not a restricted file it's just directory and not file at all.
That's why i think the method SearchAccessibleFilesNoDistinct should return only files without directories as items.
For example in filePathList i see in index 0:
c:\temp
And in index 1
c:\temp\help.txt
The first item in index 0 will go to the catch as restricted file and the second item will not.
You have this loop to search search the subdirectories:
foreach (var subDir in Directory.EnumerateDirectories(root))
{
try
{
SearchAccessibleFilesNoDistinct(subDir, files);
files.Add(subDir); <--- remove this line
}
catch (UnauthorizedAccessException ex)
{
// ...
}
}
Remove the line that adds the subdirectory to the list of files. I've marked it in the code above.
Is it you looking for:
Directory.GetFiles(rootDir,"*.*", SearchOption.AllDirectories);
? Change . to mask form textbox only.

What is the best and efficient method to search all connected drives?

I need to search all connected drives (logical as well as physical) for a specific file type (e.g. mp4). I know that I can write a recursive function to do so. But I am looking for a most efficient way as this may be a time and CPU consuming operation.
Finally I made it work. The code is as below:
static List<string> SearchFiles(string pattern)
{
var result = new List<string>();
foreach (string drive in Directory.GetLogicalDrives())
{
Console.WriteLine("searching " + drive);
var files = FindAccessableFiles(drive, pattern, true);
Console.WriteLine(files.Count().ToString() + " files found.");
result.AddRange(files);
}
return result;
}
private static IEnumerable<String> FindAccessableFiles(string path, string file_pattern, bool recurse)
{
Console.WriteLine(path);
var list = new List<string>();
var required_extension = "mp4";
if (File.Exists(path))
{
yield return path;
yield break;
}
if (!Directory.Exists(path))
{
yield break;
}
if (null == file_pattern)
file_pattern = "*." + required_extension;
var top_directory = new DirectoryInfo(path);
// Enumerate the files just in the top directory.
IEnumerator<FileInfo> files;
try
{
files = top_directory.EnumerateFiles(file_pattern).GetEnumerator();
}
catch (Exception ex)
{
files = null;
}
while (true)
{
FileInfo file = null;
try
{
if (files != null && files.MoveNext())
file = files.Current;
else
break;
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
yield return file.FullName;
}
if (!recurse)
yield break;
IEnumerator<DirectoryInfo> dirs;
try
{
dirs = top_directory.EnumerateDirectories("*").GetEnumerator();
}
catch (Exception ex)
{
dirs = null;
}
while (true)
{
DirectoryInfo dir = null;
try
{
if (dirs != null && dirs.MoveNext())
dir = dirs.Current;
else
break;
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var subpath in FindAccessableFiles(dir.FullName, file_pattern, recurse))
yield return subpath;
}
}
You can utilize the dir command for this, and the let the filesystem do what it's good at.
static string[] SearchFiles(params string[] patterns)
{
var searchPatterns = DriveInfo.GetDrives()
.Where(d => d.IsReady && d.DriveType != DriveType.NoRootDirectory)
.SelectMany(d => patterns.Select(p => d.RootDirectory + p));
using (var process = new Process())
{
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
process.StartInfo.Arguments = "/C dir " + String.Join(" ", searchPatterns) + " /s/b";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
string strOutput = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return strOutput.Split(Environment.NewLine.ToArray());
}
}
and use it like:
var files = SearchFiles("*.jpg", "*.mp?", "*.mpeg");
Since this operation might take sometime, you could use a BackgroundWorker for running it in a background thread.
Also, since the output might be quite large, you might consider outputing to a file (e.g. by adding > out.txt after /s/b) and processing the file, instead of returning an array of strings.
EDIT:
You could improve performance by searching drives in parallel.
static List<string> SearchFiles(params string[] patterns)
{
var result = new List<string>();
var drives = DriveInfo.GetDrives();
Parallel.ForEach(drives, drive =>
{
if (!drive.IsReady || drive.DriveType == DriveType.NoRootDirectory)
return;
var searchPatterns = patterns.Select(p => drive.RootDirectory + p);
using (var process = new Process())
{
process.StartInfo.FileName = Path.Combine(Environment.SystemDirectory, "cmd.exe");
process.StartInfo.Arguments = "/C dir " + String.Join(" ", searchPatterns) + " /s/b";
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.CreateNoWindow = true;
process.Start();
string strOutput = process.StandardOutput.ReadToEnd();
process.WaitForExit();
result.AddRange(strOutput.Split(Environment.NewLine.ToArray(), StringSplitOptions.RemoveEmptyEntries));
}
});
return result;
}

Process.Start Catch all FileName/Arguments code

I have some code that I wanted to improve. It uses Process.Start and should be able to handle any input any argument, and still work.
I don't think I have covered all the bases. Can anyone suggest a better/more thorough approach?
ToMaybeUri is an extension method that tries to create a Uri.
ToValidMailToArgument is an extension method that adds "attachments="
IsValidEmail is an extension method that does a RegEx on the email address.
public static void RunProcess(string fileName, string Params)
{
var useProcessStart = true;
var validFile = false;
var validDir = false;
var validEmail = false;
var validURL = false;
var proc = new Process();
var info = new ProcessStartInfo(fileName);
info.UseShellExecute = true;
info.Arguments = Params;
//try catches here in case the syntax of the string has invalid characters for dir/file
try
{
var di = new DirectoryInfo(fileName);
validDir = di == null ? false : di.ExistsNow();
}
catch (Exception ex) { }
try
{
var fi = new FileInfo(fileName);
validFile = fi == null ? false : fi.Exists();
}
catch (Exception ex) { }
if (Params == "")
{
if (validFile)
{
if (Path.GetExtension(fileName).ToUpper() == ".CHM")
{
var helpProvider1 = new HelpProvider();
helpProvider1.HelpNamespace = fileName;
Help.ShowHelp(Application.OpenForms[0], helpProvider1.HelpNamespace);
MessageBox.Show(msg);
return;
}
}
else if (validDir)
{
//skip
}
else if (fileName.IsValidEmail())
{
validEmail = true;
info.FileName = "mailto:" + info.FileName;
info.Arguments = "";
}
else if (fileName.IsValidUrl())
{
validURL = true;
info.FileName = fileName.ToMaybeUri().Value.ToString();
info.Arguments = "";
}
else
{
MessageBox.Show(fileName + " does not exist.");
}
}
else
{
//and has params
if (Path.GetExtension(fileName).ToUpper() == ".PDF" && Params.ToLower().StartsWith("p"))
{
int pageNum = 0;
string pageNumString = Grazer.Utilities.Strings.Right(Params, Params.Length - 1);
int.TryParse(pageNumString, out pageNum);
//PDFLocation = "/A \"page=" + pageNum + "=OpenActions\" \"" + ssGlobals.ssStartDir + "\\Example.pdf\""
string app = GrRegistry.GetApplicationFromExtension(".PDF");
if (Path.GetFileNameWithoutExtension(app).ToUpper() == "ACROBAT" || Path.GetFileNameWithoutExtension(app).ToUpper() == "ACRORD32")
{
string PDFLocation = String.Format("/A \"page={0}=OpenActions\" \"{1}\"", pageNum, Path.GetFullPath(fileName));
info = new ProcessStartInfo(app);
info.Arguments = PDFLocation;
}
}
else if (fileName.IsValidEmail())
{
validFile = false;
try
{
var fi = new FileInfo(info.Arguments);
validFile = fi == null ? false : fi.ExistsNow();
}
catch (Exception ex) { }
info.FileName = String.Format("mailto:{0}{1}", fileName, new FileInfo(info.Arguments).ToValidMailToArgument());
info.Arguments = "";
}
}
if (useProcessStart)
{
proc.StartInfo = info;
try
{
if (validURL || validFile || validDir || validEmail)
proc.Start();
}
catch (Exception ex)
{
switch (ex.Message)
{
case "No process is associated with this object.":
break;
default:
MessageBox.Show(ex);
if (info.Arguments.ToEmptyIfNull().Length > 0)
MessageBox.Show(String.Format("{0} could not be opened with parameters: {1}", info.FileName, info.Arguments));
else
MessageBox.Show(String.Format("{0} could not be opened", info.FileName));
break;
}
}
}
}
To start with, you don't want to swallow exceptions. On your catch blocks, make sure you're doing something after catching an exception. Also, find out what specific exceptions can be thrown by methods you're calling in your try blocks and catch those specific exceptions, like so:
try
{
SomeMethod();
}
catch (SpecificExceptionType1)
{
//do something based on what this exception means
}
catch (SpecificExceptionType2)
{
//ditto here
}
catch
{
//handle unexpected exceptions here
}
Also, this smells suspiciously like homework - perhaps implementing a command shell? If so, retag it as homework. If not, just tell me to stuff it.

Categories

Resources