Uploads within NancyFX hang on upload - c#

nuget package Microsoft.Azure.Storage.File 9.4.2 uploads files somewhere < 26MB just fine, and silently hangs indefinitely when uploading files > 26MB.
Project is targeting .NET (Desktop) Framework 4.7.2.
***** Update *****
This problem occurs when attempting a large-ish file upload, using various clients, and to various cloud services (I've experienced the same problem uploading to S3), but only within the context of a NancyFx web application. Same problem occurs locally as when deployed to an Azure App Service, so it is almost certainly unrelated to my local dev configuration.
To be clear, the uploads hang when attempting an upload within a NancyFx application; I am not uploading to a NancyFx application.
For now, my solution is to just don't do the file upload from within Nancy, but I'll leave this question open in case anyone has an interest in a technical solution to the problem that still exists.
***** End Update *****
And to be clear, file uploads
Attempted usage is as follows:
public void UploadFileFromFile(string azureFileName, string localFileName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(SafeConfig.AzureFileStorageMaterialConnectionString);
CloudFileClient client = storageAccount.CreateCloudFileClient();
CloudFileShare share = client.GetShareReference(SafeConfig.AzureFileStorageMaterialShareName);
CloudFileDirectory dir = share.GetRootDirectoryReference();
CloudFile fileReference = dir.GetFileReference(azureFileName);
fileReference.UploadFromFile(localFileName);
}
Worth noting, the client hangs just the same when I use the fileReference.UploadFromByteArray() method, and also hangs the same when I try using the various *Async alternatives as well.
When I try use the method fileReference.UploadFromStream(), I get an exception "Object is not in a usable state," which I do not consider to be a particularly actionable exception message. This is my preferred method to use for uploading, but the different error experience might make it a separate question.

I'm using the same package and same code as yours, everything is fine and file size more than 26M can be uploaded. Can you try to restart your visual studio and try again?
My code:
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.File;
using System;
namespace MyConsole
{
class Program
{
static void Main(string[] args)
{
Program p = new Program();
string azureFileName = "1.zip";
string localFileName = #"D:\1.zip";
Console.WriteLine("start upload..");
p.UploadFileFromFile(azureFileName, localFileName);
Console.WriteLine("completed**");
Console.ReadLine();
}
public void UploadFileFromFile(string azureFileName, string localFileName)
{
CloudStorageAccount storageAccount = CloudStorageAccount.Parse("xxxx");
CloudFileClient client = storageAccount.CreateCloudFileClient();
CloudFileShare share = client.GetShareReference("testfolder");
CloudFileDirectory dir = share.GetRootDirectoryReference();
CloudFile fileReference = dir.GetFileReference(azureFileName);
Console.WriteLine("going to upload");
fileReference.UploadFromFile(localFileName);
}
}
}
The file can be uploaded:

Related

Read audio file duration in C# on Linux with .net 6

I have an asp.net core API that was recently updated from .net5 to .net6.
There is a piece of code that should read a duration of an audio file. The code that seems to have worked on previous versions was this:
try
{
//
// NAudio -- Windows only
//
using var fileReader = new AudioFileReader(filePath);
return Convert.ToInt32(Math.Ceiling(fileReader.TotalTime.TotalSeconds));
}
catch (DllNotFoundException)
{
try
{
//
// LibVLCSharp is crossplatform
//
using var libVLC = new LibVLC();
using var media = new Media(libVLC, filePath, FromType.FromPath);
MediaParsedStatus parsed = Task.Run(async () => await media.Parse(MediaParseOptions.ParseNetwork, timeout: 2000).ConfigureAwait(false)).Result;
if (parsed != MediaParsedStatus.Done) throw new ArgumentException("Could not read audio file");
if (!media.Tracks.Any(t => t.TrackType == TrackType.Audio) || (media.Duration <= 100)) throw new ArgumentException("Could not read audio from file");
return Convert.ToInt32(Math.Ceiling(TimeSpan.FromMilliseconds(media.Duration).TotalSeconds));
}
catch (Exception ex) when (ex is DllNotFoundException || ex is LibVLCSharp.Shared.VLCException)
{
try
{
using var fileReader = new Mp3FileReader(filePath);
return Convert.ToInt32(Math.Ceiling(fileReader.TotalTime.TotalSeconds));
}
catch (InvalidOperationException)
{
throw new ArgumentException("Could not read audio file");
}
}
}
The application was deployed on Linux and, I don't know which part of the code did the exact calculation (I am assuming the VLC part), but since the update to .NET6, all of these fail, and since the last fallback is NAudio, we get the following exception:
Unable to load shared library 'Msacm32.dll' or one of its dependencies.
I am using Windows, but I tried running the app with WSL, and I can't get the VLC part to run either - it always throws the following exception (even after installing vlc and vlc dev SDK):
LibVLC could not be created. Make sure that you have done the following:
Installed latest LibVLC from nuget for your target platform.
Unable to load shared library 'libX11' or one of its dependencies. In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable: liblibX11: cannot open shared object file: No such file or directory at LibVLCSharp.Shared.Core.Native.XInitThreads()
at LibVLCSharp.Shared.Core.InitializeDesktop(String libvlcDirectoryPath)
at LibVLCSharp.Shared.Helpers.MarshalUtils.CreateWithOptions(String[] options, Func`3 create)
Is there any clean way to read a duration of an audio file on all platforms?
Needless to say, NAudio works like a charm on Windows, and so does the VLC (with the proper nuget package).
If you install ffmpeg, you can do this quite easily. ffmpeg comes installed in most linux distros by default, but in case it isn't, you can install it with your favorite package manager.
sudo apt install ffmpeg
To install it in windows, you'll need to download the build files, extract it, and add it to the PATH.
Next, install Xabe.FFMpeg package in your project.
Finally, you can call the static method Xabe.FFMpeg.FFMpeg.GetMediaInfo() to get all information regarding your audio file. Here is a sample snippet that I tested on my linux machine.
using System;
using System.IO;
using Xabe.FFmpeg;
namespace Program;
public static class Program
{
public static void Main(string[] args)
{
string filename;
if (args.Length == 0)
{
Console.WriteLine("No arguments found! Provide the audio file path as argument!");
return;
}
else if (File.Exists(filename = args[0]) == false)
{
Console.WriteLine("Given file does not exist!");
return;
}
try
{
var info = FFmpeg.GetMediaInfo(filename).Result;
TimeSpan duration = info.Duration;
Console.WriteLine($"Audio file duration is {duration}");
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
}
}
The error you are seeing is because we were assuming that you would display a video on linux, using X11, so we are always initializing X11. See here.
We shouldn't do that for your use case(because you may not have a GUI available). Please report the issue here : https://code.videolan.org/videolan/LibVLCSharp/-/issues
or even better, submit a pull request on github or gitlab.
As for your question of why did it work on .net 5 and not anymore, I'm not sure we have enough info to tell why, because you didn't send us the error message from that machine.
I would encourage you to take a look at atldotnet. It is a small, well maintained completely managed code / cross platform library without any external dependencies and was accurate detecting audio file duration in all of my test cases (more accurate than ffmpeg). Most common audio formats are supported.
var t = new Track(audioFilePath);
// Works the same way on any supported format (MP3, FLAC, WMA, SPC...)
System.Console.WriteLine("Duration (ms) : " + t.DurationMs);

SharpSvn.SvnException: sqlite[S8]: attempt to write a readonly database

I got following error when I do `
svnclient.CleanUp(WorkDirPath);`
SharpSvn.SvnException: sqlite[S8]: attempt to write a readonly database
---> SharpSvn.SvnException: Additional errors:
---> SharpSvn.SvnException: sqlite[S8]: attempt to write a readonly database
Update
I have visual studio application and from this application i need upload/download any file to SVN server and this feature can access by end user. so for this i installed VisualSVN Server Manager Version: 4.3.3 on windows server. in my application i imported nuget for this SharpSvn.1.8-x64 to atchive this task (I am new in subversion and client).
Updated : I updated sharpSVN to 1.14001.156 thanks for it. but still my problem is not solved. i still get following error when try to add file "Failed to lock working copy" and then I tried Clean Up Command got "sqlite[S8]: attempt to write a readonly database" error. Is Visual SVN Server Version: 4.3.3 ok with SharpSVN 1.14 ?
following is my code written in C#
svnclient.Authentication.DefaultCredentials = new NetworkCredential(_svnuser, _svnpwd);
CleanCommand(svnclient,_userworkdir);
public bool AddFile(string path, SvnClient svnclient)
{
try
{
return svnclient.Add(path);
}
catch (Exception ex)
{
Log.Error(String.Format(String.Format("Exception in function AddFile := {0} FilePath :- {1}", ex.Message.ToString(), path)));
return false;
}
}
public bool CleanCommand(SvnClient svnclient, String workingdir)
{
bool res = false;
try
{
res = svnclient.CleanUp(workingdir);
}
catch (Exception ex)
{
Log.Error(String.Format(String.Format("Exception in function CleanCommand := {0}, workingdir :- {1}", ex.Message.ToString(), workingdir)));
res = false;
}
return res;
}
Note that SharpSVN 1.8 is outdated. If you use Subversion client based on SharpSVN (AnkhSVN?), it makes sense to update it or to switch to an up-to-date native Subversion 1.14.x client.
As an immediate solution, you can check out a new working copy and continue you work with it. If you have uncommitted changes in the working copy, you can copy them over into a new working copy (don't copy hidden .svn directory though).
I think that something prevents you from opening or writing the contents of the .svn metadata directory. This could be due to insufficient permissions or another program that locks your working copy:
Check NTFS permissions to the .svn directory in the root of your working copy and the .svn/wc.db file in particular (e.g., C:\Users\MyUser\MyVsProject\.svn\wc.db). You should double-check that your user account has permissions to write to C:\Users\MyUser\MyVsProject\ directory and all its contents.
Check if other SVN clients or programs work concurrently with your client and lock the working copy.

How to return the directory of the running .NET Core 2.2 app hosted on an Azure Windows Server VM?

So I have a .NET Core 2.2 app running on an Azure VM with Windows Server 2019 which has the following disk configuration:
The disk on the red box is where the App files are located. Now, when Directory.GetCurrentDirectory() is called by the app, it returns the root directory of the project and not the current directory where the app is running. When I tried to run it locally, it works.
To illustrate it:
When run locally, the directory ~/MyApp/bin/Debug/netcoreapp2.2/ is returned by the call. When run in the VM, ~/MyApp/ is returned instead.
Here's the relevant code where the issue happens. What I do here is when the app is closed, it copies the current configuration file from ~/MyApp/bin/Debug/netcoreapp2.2/ to the ~/MyApp/ directory. This code works when run on a local machine, but it is not when running on the VM. How to make sure that calling Directory.GetCurrentDirectory() does indeed point to the directory of the running app?
private void ProcessExit(object sender, EventArgs e)
{
try
{
string rawConfigLocation = _config.GetSection("configurationSettings")["ConfigurationDirectory"];
File.Delete($"{Path.Combine(rawConfigLocation, "Config.json.inc")}");
using (var writer = File.CreateText($"{Path.Combine(Directory.GetCurrentDirectory(), "Config.json.inc")}"))
{
using (var reader = new StreamReader(Path.Combine(Directory.GetCurrentDirectory(), "Config.json")))
{
while (!reader.EndOfStream) writer.WriteLine(reader.ReadLine());
writer.Close();
}
Console.WriteLine(rawConfigLocation);
File.Move($"{Path.Combine(Directory.GetCurrentDirectory(), "Config.json.inc")}", $"{Path.Combine(rawConfigLocation, "Config.json.inc")}");
File.Delete($"{Path.Combine(rawConfigLocation, "Config.json")}");
File.Move($"{Path.Combine(rawConfigLocation, "Config.json.inc")}", $"{Path.Combine(rawConfigLocation, "Config.json")}");
Debug.WriteLine($"New file saved as {Path.Combine(rawConfigLocation, "Config.json")}");
#region [WINDOWS ONLY] Lines for debugging. Will be removed if the issue of incorrect config saving is fixed.
using (EventLog eventLog = new EventLog("MyApp"))
{
eventLog.Source = "MyApp";
eventLog.WriteEntry(
$"Raw Config Location: {_config.GetSection("configurationSettings")["ConfigurationDirectory"]}{Environment.NewLine}" +
$"File that was deleted: {Path.Combine(rawConfigLocation, "Config.json.inc")}{Environment.NewLine}" +
$"Temporary file created: {Path.Combine(Directory.GetCurrentDirectory(), "Config.json.inc")}{Environment.NewLine}" +
$"Current Directory: {Directory.GetCurrentDirectory()}{Environment.NewLine}" +
$"New file saved as {Path.Combine(rawConfigLocation, "Config.json")}",
EventLogEntryType.Information,
101,
1);
}
#endregion
}
}

How can I allow the user to modify connection strings stored in app.config if they lack write permissions?

First, some background on our app: When deployed, our application will be installed on a clients machine in the Program Files directory. We use connection strings which are stored in the App.config file that comes with the program. Under most circumstances, these connection strings will never change. However, at some point, it may be possible that the connection string info will go out of date. To that end, we have included a feature in our program that allows the user to enter new database information if the database can't be reached. The information is parsed into a connection string, tested for validity, and written back into the config file if valid. (Yes, this change is intended to affect all users on the computer, since they will be unable to run the application without a valid connection string anyway - if one user knows the DB info, then other users on the same computer will benefit from that knowledge. Writing to App.config instead of a per-user settings file is preferred.)
The problem I'm running into is that the end user will not have admin permissions, and thus will not be able to run our app at a level that allows it to make any changes to its own config file (since it is located in the C:\Program Files directory). I'm looking at a couple of different options, but I'm having problems implementing each of them:
Move config file to a different location. Not possible in this case because we are deploying an executable, and from what I understand, the App.config file must reside in the same directory.
Separate the connection string info into an external config file. I know about the configSource property that can be added to the connection string section of App.config. However, I'm having trouble specifying a concrete target. I can't simply put the file alongside the executable (otherwise I'd get the same permissions issues as the regular App.config). However, it appears environment variables (such as %AppData%) are not supported as valid config sources. I have tried to implement the solution from this question, but the program crashes before I can change the config source to a valid string because the ConfigurationManager apparently attempts to read the config source folder immediately and thus crashes with a FileNotFoundException.
Create our own config file implementation. I could always just create a custom class that is dedicated to reading a config file that is located in a specific location, but I would prefer using the built-in ConfigurationManager if possible.
My main question is this: How can I allow the end user (who only has read permissions in the application folder) to modify config settings dynamically when the config file must stay in the application folder?
Since windows xp, the OS prevents programs with out admin privileges from writing to the Program Files folder. The "Program Data" folder was created to allow programs to store persistent information. I always use a custom config file to store program data that an end User needs to config to connect to a database. I also encrypt at least the password of the connection string, but that is a another discussion. I provided a sample class and usage that stores a config file in Program Data Folder.
Config Class
using System;
using System.IO;
using System.Xml.Serialization;
namespace MyNamespace
{
public class Config
{
public string SomeStringProperty { get; set; }
public int SomeIntProperty { get; set; }
private static string _filePath = null;
static Config()
{
_filePath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.CommonApplicationData) + #"\My Program Name";
}
public static Config LoadConfig()
{
if (File.Exists(_filePath))
{
try
{
XmlSerializer reader = new XmlSerializer(typeof(Config));
StreamReader file = new StreamReader(_filePath);
Config config = (reader.Deserialize(file) as Config);
return config;
}
catch (Exception ex)
{
//Deal With no file file read error here.
}
}
// IF we get here no valid config file was loaded so make a new one.
return new Config();
}
public Exception SaveConfig()
{
try
{
XmlSerializer writer = new XmlSerializer(typeof(Config));
StreamWriter file = new StreamWriter(_filePath);
writer.Serialize(file, this);
file.Close();
return null;
}
catch (Exception ex)
{
return ex;
}
}
}
}
Basic Usage
Config config = Config.LoadConfig();
Debug.WriteLine("SomeIntProperty=" + config.SomeIntProperty.ToString());
Debug.WriteLine("SomeStringProperty=" + config.SomeStringProperty);
config.SomeIntProperty = 10;
config.SomeStringProperty = "Hello";
config.SaveConfig();
var configuration = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("~");
var section = (ConnectionStringsSection)configuration.GetSection("connectionStrings");
section.ConnectionStrings["YourNameConnectionString"].ConnectionString = "yourstring";

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.

Categories

Resources