C# Windows Service Not Compressing Folder Correctly - c#

Im currently building a Windows service that will be used to create backups of logs. Currently, the logs are stored at the path E:\Logs and intent is to copy the contents, timestamp their new folder and compress it. After this, you should have E:\Logs and E:\Logs_[Timestamp].zip. The zip will be moved to C:\Backups\ for later processing. Currently, I am using the following to try and zip the log folder:
var logDirectory = "E://Logs";
var timeStamp = DateTime.Now.ToString("yyyyMMddHHmm");
var zippedFolder = logDirectory + "_" + timeStamp + ".zip";
System.IO.Compression.ZipFile.CreateFromDirectory(logDirectory, zippedFolder);
While this appears to create a zip folder, I get the error Windows cannot open the folder. The Compressed (zipped) Folder E:\Logs_201805161035.zip is invalid.
To address any troubleshooting issues, the service is running with an AD account that has a sufficient permission level to perform administrative tasks. Another thing to consider is that the service kicks off when its FileSystemWatcher detects a new zip folder in the path C:\Aggregate. Since there are many zip folders that are added to C:\Aggregate at once, the FileSystemWatcher creates a new Task for each zip found. You can see how this works in the following:
private void FileFoundInDrops(object sender, FileSystemEventArgs e)
{
var aggregatePath = new DirectoryInfo("C://Aggregate");
if (e.FullPath.Contains(".zip"))
{
Task task = Task.Factory.StartNew(() =>
{
try
{
var logDirectory = "E://Logs";
var timeStamp = DateTime.Now.ToString("yyyyMMddHHmm");
var zippedFolder = logDirectory + "_" + timeStamp + ".zip";
ZipFile.CreateFromDirectory(logDirectory, zippedFolder);
}
catch (Exception ex)
{
Log.WriteLine(System.DateTime.Now.ToString() + " - ERROR: " + ex);
}
});
task.Dispose();
}
}
How can I get around the error I am receiving? Any help would be appreciated!

Related

Why is my download from Azure storage empty?

I can connect to the Azure Storage account and can even upload a file, but when I go to download the file using DownloadToFileAsync() I get a 0kb file as a result.
I have checked and the "CloudFileDirectory" and the "CloudFile" fields are all correct, which means the connection with Azure is solid. I can even write the output from the file to the console, but I cannot seem to save it as a file.
public static string PullFromAzureStorage(string azureFileConn, string remoteFileName, string clientID)
{
var localDirectory = #"C:\cod\clients\" + clientID + #"\ftp\";
var localFileName = clientID + "_xxx_" + remoteFileName;
//Retrieve storage account from connection string
var storageAccount = CloudStorageAccount.Parse(azureFileConn);
var client = storageAccount.CreateCloudFileClient();
var share = client.GetShareReference("testing");
// Get a reference to the root directory for the share
CloudFileDirectory rootDir = share.GetRootDirectoryReference();
//Get a ref to client folder
CloudFileDirectory cloudFileDirectory = rootDir.GetDirectoryReference(clientID);
// Get a reference to the directory we created previously
CloudFileDirectory unprocessed = cloudFileDirectory.GetDirectoryReference("Unprocessed");
// Get a reference to the file
CloudFile sourceFile = unprocessed.GetFileReference(remoteFileName);
//write to console and log
Console.WriteLine("Downloading file: " + remoteFileName);
LogWriter.LogWrite("Downloading file: " + remoteFileName);
//Console.WriteLine(sourceFile.DownloadTextAsync().Result);
sourceFile.DownloadToFileAsync(Path.Combine(localDirectory, localFileName), FileMode.Create);
//write to console and log
Console.WriteLine("Download Successful!");
LogWriter.LogWrite("Download Successful!");
//delete remote file after download
//sftp.DeleteFile(remoteDirectory + remoteFileName);
return localFileName;
}
In the commented out line of code where you write the output to the Console, you explicitly use .Result because you're calling an async method in a synchronous one. You should either also do so while downloading the file as well, or make the entire method around it async.
The first solution would look something like this:
sourceFile.DownloadToFileAsync(Path.Combine(localDirectory, localFileName), FileMode.Create).Result();
EDIT:
As far as the difference with the comment, that uses GetAwaiter().GetResult(), goes: .Result wraps any exception that might occur in an AggregateException, while GetAwaiter().GetResult() won't. Anyhow: if there's any possibility you can refactor the method to be async so you can use await: please do so.

Cannot get a certificate file from application running at server

I have an application written in C# MVC 4, which will run on server, that has one certificate inside the project, in the App_Data folder. I need to get this certificate file to access a Web Service. The server is a Windows Server 2012, using iis7.
The code runs as expected locally, but it does not work on the server. There I receive the message "The system cannot find the file specified". But this file IS there (I return the content of this directory and the previous one, getting them on the browser's console).
I tried to rename the certificate from .pfx to .pcertx (a random one) and doesn't work on the server again, although it works locally.
Here's the code I'm using to try to get this file:
public string getCertificado()
{
string path = string.Empty;
try
{
path = HttpContext.Current.Server.MapPath(#"~\App_Data\CERTIFICATE.pcertx");
Byte[] rawCert = File.ReadAllBytes(path);
String certificado = Convert.ToBase64String(rawCert);
_X509Cert.Import(Convert.FromBase64String(certificado), "PASSWORD", X509KeyStorageFlags.PersistKeySet);
client.AddCerts(new X509Certificate[] { _X509Cert });
return string.Empty;
}
catch (Exception ex)
{
// In case of error, list the content of the current directory and the previous
string[] filePaths = Directory.GetFiles(HttpContext.Current.Server.MapPath(#"~\App_Data"));
string pastaAnterior = Path.GetFullPath(Path.Combine(HttpContext.Current.Server.MapPath(#"~\App_Data"), #"..\"));
string[] filePathsAnt = Directory.GetFiles(pastaAnterior);
return "Cannot get certificate." + ex.Message + "; " + ex.InnerException + "; Path: " + path + "; Folder content: " + string.Join("\n",filePaths) + "; Previous folder content" + string.Join("\n",filePathsAnt);
}
}
This is what I get from the browser's console:
"Não foi possível obter nenhum certificado.
The system cannot find the file specified.
Path: C:\Unisys\Management\Applications\sicopplustest\App_Data\CERTIFICATE.pcertx;
Caminho pasta:
C:\Unisys\Management\Applications\sicopplustest\App_Data\CERTIFICATE.pcertx
C:\Unisys\Management\Applications\sicopplustest\App_Data\DynamicAspx.xsl;
Caminho pasta anteriorC:\Unisys\Management\Applications\sicopplustest\ApplicationInfo.Debug.xml
C:\Unisys\Management\Applications\sicopplustest\ApplicationInfo.Release.xml
C:\Unisys\Management\Applications\sicopplustest\ApplicationInfo.xml
..."
If I got the certificate properly, no message would be sent.
I think it may be related to security, but how can I fix it? I don't know how to procede with this situation.

Zip file extraction when restoring a database

I've created a backup and restore procedure for my application. When the backup is run, it will create a .zip file of the SQLite database in the same directory as the database.
When restoring the database, it will rename the database, changing it from EPOSDatabase.db3 to tempEPOS.db3
Then, it takes the selected file and extracts it to the same location, under the name EPOSDatabase.db3, before deleting the renamed temporary database.
string dbPath = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
if (File.Exists(dbPath + "/tempEPOS.db3"))
{
File.Delete(dbPath + "/tempEPOS.db3");
};
File.Move(dbPath + "/EPOSDatabase.db3", dbPath + "/tempEPOS.db3");
ZipFile.ExtractToDirectory(dbPath + "/" + fileToRestore, dbPath + "/EPOSDatabase.db3");
File.Delete(dbPath + "/tempEPOS.db3");
My issue is that when I then have code that opens the connection, for example when I open the system settings page after the restore has been carried out, I get an error:
"Could not open database file: /data/user/0/com.companyname.ACPlus_MobileEPOS/files/EPOSDatabase.db3 (CannotOpen)"
As a further debug test, I added this code to the startup of the application:
string path = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
foreach (var file in Directory.GetFiles(path))
{
string strFile = Convert.ToString(file);
}
public readonly string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), "EPOSDatabase.db3");
var db = new SQLiteConnection(dbPath);
db.CreateTable<Category>();
db.CreateTable<SystemSettings>();
db.Close();
In the foreach loop, it only found the original .zip file that I was trying to restore from.
Then when it reaches the line
var db = new SQLiteConnection(dbPath);
it fails to create the database with the message
"Could not open database file: /data/user/0/com.companyname.ACPlus_MobileEPOS/files/EPOSDatabase.db3"
It seems like the file doesn't exist, so hasn't extracted properly, but if that was the case then why does it not just create a new database, rather than try to open it?
The extraction logic needs to be rechecked.
Specifically ExtractToDirectory.
Extracts all the files in the specified zip archive to a directory on the file system.
public static void ExtractToDirectory (string sourceArchiveFileName, string destinationDirectoryName);
In the original code
ZipFile.ExtractToDirectory(dbPath + "/" + fileToRestore, dbPath + "/EPOSDatabase.db3");
The contents of the zip file are extracting to a directory called {path}/EPOSDatabase.db3/.
If the goal was just to extract from the archive to the directory then only the directory location is required.
ZipFile.ExtractToDirectory(dbPath + "/" + fileToRestore, dbPath);
Additionally, a check should be done to make sure the desired file actually exists after the restore before deleting the old file.
//... extraction code omitted for brevity
if (!File.Exists(dbPath + "/EPOSDatabase.db3")) {
//...either throw error or alert that database is not present
//...could consider return old file back to original sate (optional)
} else {
File.Delete(dbPath + "/tempEPOS.db3");
}

Read files from LAN folder using StorageFolder.GetFilesAsync returns folders but no files

I'm trying to write a basic UWP app to stream media over a LAN via DLNA. I have three PC's on the same LAN, all running W10 Pro, a Homegroup set up, Media streaming switched on and configured on all of them but when I run the method below, passing in a remote folder all I get in folders back and no files, even though I know the folders contain files.
async private void LoadMediaFiles(StorageFolder mediaServerFolder)
{
try
{
MediaFolders = await mediaServerFolder.GetFoldersAsync();
MediaList.Items.Clear();
if (MediaFolders.Count > 0)
{
MediaList.Items.Clear();
foreach (StorageFolder folder in MediaFolders)
{
MediaList.Items.Add(" + " + folder.DisplayName);
}
MediaTitle.Text = "Media folders retrieved";
}
var queryOptions = new QueryOptions();
var options = new QueryOptions();
options.FileTypeFilter.Add(".avi");
options.FileTypeFilter.Add(".mp4");
options.FileTypeFilter.Add(".mkv");
options.FileTypeFilter.Add(".wmv");
options.FolderDepth = FolderDepth.Deep;
var queryFolder = mediaServerFolder.CreateFileQueryWithOptions(queryOptions);
MediaFiles = await queryFolder.GetFilesAsync();
if (MediaFiles.Count > 0)
{
foreach (StorageFile file in MediaFiles)
{
MediaList.Items.Add(file.DisplayName);
}
MediaTitle.Text = "Media files retrieved";
}
else
MediaTitle.Text = "No files found";
}
catch (Exception ex)
{
MediaTitle.Text = "Error locating media files " + ex.Message;
}
}
To get the known DLNA servers I use:
IReadOnlyList<StorageFolder> MediaServers = await KnownFolders.MediaServerDevices.GetFoldersAsync();
and then list the folders from the selected server. When the user taps on any folder it calls the above method but I never get files, only folders.
I can stream between each of the PC's no problem using WMP or VLC etc, it's only trying to get media files via UWP to stream that it doesn't work... I just get "No files found" on every folder.

Assistance with Threads and waiting form completion

I have a question about dealing with threads. I am copying files from one folder to another, then zipping them up. Problem is the winform appears to be attempting to zip the files before they are finished copying which in turn is causing the zip function to not complete. I did some looking around on here and to be honest I am having issues wrapping my head around how it works. MSDN has a nice little snippet:
// Wait on a single task with no timeout specified.
Task taskA = Task.Factory.StartNew(() => DoSomeWork(10000000));
taskA.Wait();
Console.WriteLine("taskA has completed.");
static void DoSomeWork(int val)
{
// Pretend to do something.
Thread.SpinWait(val);
}
again it's a bit over my head the code that I am trying to wait for complete
error_handling("Daily Backup Started", "BackupLog.txt");
string fileName = "";
string Source = #"C:\folder\Program";
string target = #"C:\folder\day_backup";
string datestamp = DateTime.Now.ToString("MMddyy-HHmm");
string[] files = System.IO.Directory.GetFiles(Source, "*.mdb");
foreach (string file in files)
{
fileName = System.IO.Path.GetFileName(file);
string destfile = System.IO.Path.Combine(target, fileName);
System.IO.File.Copy(file, destfile);
sub_error_handling(fileName+" has been copied", "DailyBackupLog.txt");
}
compression(#"C:\backupfolder\day_backup", #"\day_backup"+datestamp+".zip");
sub_error_handling("Files were packaged for transmission", "DailyBackupLog.txt");
also here is my zip code:
private void compression(string zipdir, string zipfilename)
{
try
{
using (ZipFile zip = new ZipFile())
{
zip.AddDirectory(zipdir);
zip.Comment = "This backup was created at " + System.DateTime.Now.ToString("G");
zip.Save(zipdir + zipfilename);
}
}
catch (Exception error)
{
error_handling("Incremental Backup Failed Compression was unsuccessful", "Incbackuplog.txt");
sub_error_handling(error + "", "Incbackuplog.txt");
error_handling("End Of Error Report", "Incbackuplog.txt");
}
}
it won't let me use a void to perform the new task, so not sure what else to try. Any suggestions ?
I'd say this is causing the hang:
zip.AddDirectory(zipdir);
zip.Comment = "This backup was created at " + System.DateTime.Now.ToString("G");
zip.Save(zipdir + zipfilename);
You are compressing all files in zipdir to a new file in the same location, so that the new file will be included in the zip file. So you are trying to include the new file inside itself, which is obviously impossible and explains, I think, why the zip process never ends.
By the way, you've set zipdir to a directory that's not the same as the one to which your code copies the files.

Categories