C# infinite recursion during resource lookup - c#

I have a problem with this code:
if (_updater.IsNewVersionAvailable())
{
_isolatedStorageFile.CreateDirectory("Folder");
_isolatedStorageFile.CreateDirectory("Folder2");
foreach (string file in Directory.GetFiles(_sharedFilesFolder + "\\Folder"))
{
string fileName = Path.GetFileName(file);
//_isolatedStorageFile.CreateFile(fileName); // <- same problem
using (var outputStream = _isolatedStorageFile.OpenFile("Folder/" + fileName, FileMode.Create, FileAccess.Write)) // <- here is the problem (I tried with backslash (\\) and also doesnt work.
{
using (var inputStream = File.OpenRead(file))
{
inputStream.CopyTo(outputStream);
}
}
}
}
When I run the MS Test which called this piece of code I get this error:
error1
error2
The folders inside isolated storage are created normally ( I cannot create a file)
The strangest thing is that once when I started the test the file has been created - it was 1/20 runs.
Any idea?

One thing you can try is, insert this in your code right before you're getting the infinite recursion issue (from here and here):
try
{
throw new NotImplementedException();
}
catch (NotImplementedException ex)
{
}
I was just trying to figure out an issue where we intended to retrieve something from isolated storage, and it got stuck in this inf recursion. I was browsing the .Net and MSTest sources, and it seems that:
The file doesn't exist. Its trying to throw a FileNotFoundException from FileStream.Init > WinIOError.
To throw the exception, it's trying to get a string with Environment.GetResourceString("IO.FileNotFound_FileName", str), str). From there you get to functions like InternalGetSatelliteAssembly. Its trying to locate mscorlib.
Meanwhile, MSTest has defined an AssemblyResolver listener, which get's called at this point. It will iterate over some paths, doing a File.Exists check on them.
File.Exist will check for permissions to that file. For code access permissions, it'll throw a SecurityException with the parameter: Environment.GetResourceString("Security_Generic").
Loop back to point 2.
(IsolatedStorage never gets to catch the FileNotFoundException, so it won't create a new one.)
The NotImplementedException or AgrumentException seems to force mscorlib to be loaded, and the loop is avoided. Maybe there's a another way of making it easier to find, though.

In my case exactly this happened on some of the machines when my code tried to create a new file in IsolatedStorage. After some research, it appeared to be really a bug and happens when the machine has non-English active locale set. Following code fixed the issue in my case:
var currentCulture = Thread.CurrentThread.CurrentCulture;
var currentUiCulture = Thread.CurrentThread.CurrentUICulture;
Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;
var traceFileStream = new IsolatedStorageFileStream("system_log.txt", FileMode.OpenOrCreate, FileAccess.Write);
Thread.CurrentThread.CurrentCulture = currentCulture;
Thread.CurrentThread.CurrentUICulture = currentUiCulture;

Related

Accessing file with streamreader failed because it is being used by another process

I have a .NET Core application which is multithreaded. One aspect of the application is a health check which parses a log file for errors. This is the code used to access it:
using StreamReader reader = new StreamReader(GetLogFile);
I noticed that I occasionally get this error:
2021-01-12 11:15:14.890Z ERROR APP=2227 COMP=3789 [16] Health check Check logs for application issues threw an unhandled exception after 96.2407ms - Logger=Microsoft.Extensions.Diagnostics.HealthChecks.DefaultHealthCheckService,Level=ERROR,ThreadId=16,,Exception="System.IO.IOException: The process cannot access the file 'c:\apps\Cb.Publisher\Logs\Cb.Publisher.log' because it is being used by another process.
I changed my code to this:
using StreamReader reader = new StreamReader(File.OpenRead(GetLogFile));
In testing it I haven't encountered the issue but it occurred so rarely that I am not 100% sure it's resolved. Is my change likely to resolve this issue or is there a better way to do it?
Additional Info
This is the entire function:
private int LogLine(Regex reg)
{
GetLogFile = DefaultLogFile.GetLogFileName();
using StreamReader reader = new StreamReader(File.OpenRead(GetLogFile));
string line;
int lineNo = 0;
int errorLine = 0;
while ((line = reader.ReadLine()) != null)
{
Match match = reg.Match(line);
if (match.Success)
{
errorLine = lineNumber;
}
lineNo++;
}
return errorLine;
}
If I set a breakpoint on the while line in Visual Studio and run the function, then try to edit the file in Notepad I fails with the error The process cannot access the file because it is being used by another process.
After some investigation I'm wondering if this line could actually be the cause of my problems:
var fileTarget = (FileTarget)LogManager.Configuration.FindTargetByName("file-target");
It's in DefaultLogFile.GetLogFileName:
public string GetLogFileName()
{
var fileTarget = (FileTarget)LogManager.Configuration.FindTargetByName("file-target");
var logEventInfo = new LogEventInfo();
string fileName = fileTarget.FileName.Render(logEventInfo);
if (!File.Exists(fileName))
{
throw new Exception("Log file does not exist.");
}
return fileName;
}
You currently suggested solution will likely be enough, yes:
using StreamReader reader = new StreamReader(File.OpenRead(GetLogFile));
However, the proper solution is for you to check that the file is not being locked from wherever else you are using the file. This also means your logging framework (be it Log4Net, NLog, Serilog etc.) should be properly configured to not take an exclusive lock on the log file. I believe logging frameworks usually do not lock it from read access by default, so unless you have customized the configuration the logging framework should not be a problem.

c# File.Exists gets wrong result when network connection has been lost

I have to check a file on a mapped network drive.
f.e. P:\myFolder\myFile.dat
FileInfo fi = new FileInfo(myfile);
if (fi.Exists)
{
// Exists does not work if the network was interrupted.
// For whatever reason
// So now Try ... Catch, the FileInfo constructor can actually be omitted!
try
{
FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(myfile);
}
catch (FileNotFoundException ex)
{
this.Version = new Version("1.0.0");
}
}
else
{
this.Version = new Version("1.0.0");
}
It all works fine - until I unplug my network cable.
The FileInfo still thinks the file exists.
Why ?
The documentation states your described behaviour:
When the properties are first retrieved, FileInfo calls the Refresh method and caches information about the file. On subsequent calls, you must call Refresh to get the latest copy of the information.
https://learn.microsoft.com/en-us/dotnet/api/system.io.fileinfo
fi.Refresh(); worked !
#Sommmen
File.Exists(myfile) didn't work too.
It had the same problems like the FileInfo

SharePoint ClientContext.ExecuteQuery works in c# application but crashes in DLL

I have written C# code to search for specific file types in SharePoint lists within a site and display the file names in a listview.
The code works perfectly well in a C# windows application, but when it is compiled into a C# DLL and called from a Delphi2007 application it crashes when it hits the first call to ClientContext.ExecuteQuery(). There is no exception or error message - the Delphi application just stops running.
The really weird part is that my Delphi test application has a web browser component, and if I use that to navigate to the top level list on the site the DLL then works OK.
The question therefore is why does the first ExecuteQuery call fail in the DLL if I haven't logged on to the site first?
This is the C# code:
public void ListFiles()
{
string LContains = "<Contains><FieldRef Name='FileLeafRef'/> <Value Type ='Text'>{0}</Value></Contains>";
string LNotEqual = "<Contains><FieldRef Name='FileLeafRef'/><Value Type ='Text'>{0}</Value></Contains>";
string LWhereQuery = "";
switch (comboFileType.SelectedIndex)
{
case 0: LWhereQuery = string.Format(LContains, ".DOC"); break;
case 1: LWhereQuery = string.Format(LContains, ".PDF"); break;
case 2: LWhereQuery = string.Format(LNotEqual, "xxxx"); break;
}
Uri LUri = new Uri(SharePointURL);
using (SP.ClientContext LContext = new SP.ClientContext(SharePointURL))
{
System.Net.CredentialCache cc = new System.Net.CredentialCache();
if (!string.IsNullOrEmpty(Domain))
cc.Add(LUri, AuthenticationType, new System.Net.NetworkCredential(UserName, Password, Domain));
else
cc.Add(LUri, AuthenticationType, new System.Net.NetworkCredential(UserName, Password));
LContext.Credentials = cc;
LContext.AuthenticationMode = SP.ClientAuthenticationMode.Default;
var LWeb = LContext.Web;
lvItems.BeginUpdate();
try
{
try
{
SP.List LList = LWeb.Lists.GetByTitle(DefaultListName);
SP.CamlQuery LQuery = new SP.CamlQuery();
LQuery.ViewXml = "<View Scope='RecursiveAll'><Query><Where>"
+ LWhereQuery
+ "</Where></Query><RowLimit> 30 </RowLimit></View>";
SP.ListItemCollection LItems = LList.GetItems(LQuery);
LContext.Load(LItems);
LContext.ExecuteQuery(); **<<<< Crash happens here**
foreach (SP.ListItem LItem in LItems)
{
SP.File LFile = LItem.File;
LContext.Load(LFile);
LContext.ExecuteQuery();
var LViewItem = new ListViewItem();
try { LViewItem.Text = LFile.Name; }
catch { LViewItem.Text = "!Error"; }
try { LViewItem.SubItems.Add(LFile.TimeLastModified.ToString()); }
catch { LViewItem.SubItems.Add("!Error"); }
if (LFile.CheckOutType != Microsoft.SharePoint.Client.CheckOutType.None)
{
try { LViewItem.SubItems.Add(LFile.CheckedOutByUser.LoginName); }
catch { LViewItem.SubItems.Add("!Error"); }
}
else
LViewItem.SubItems.Add("Not checked out.");
try { LViewItem.Tag = LFile.ServerRelativeUrl; }
catch { LViewItem.Tag = "!Error"; }
lvItems.Items.Add(LViewItem);
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex);
}
}
finally
{
lvItems.EndUpdate();
}
}
The code is in the .cs of a dialog form in the DLL. The form displays as it should and the crash only happens when I click a button to do the search.
I put some debug code in to check all the string params etc. (by writing them to a text file) and they are all OK.
I tried debugging the DLL from VS by specifying the D2007 app as the 'startup external program' but I can't get breakpoints to work and at the point where it crashes it says: An unhandled exception of type 'System.StackOverflowException' occurred in Microsoft.SharePoint.Client.Runtime.dll and suggests I might have an infinite recursive call but, as mentioned earlier, the code all works perfectly if I have already logged into the site and browsed to the top level list, so i don't think it is a recursive call.
UPDATE: I got the debugging to work by copying the Delphi exe to the same directory as the DLL.
I've tried using the ExceptionHandlingScope but it hasn't helped. This is how it looks when it crashes:
The scope has no exception and the errormessage is blank. I tried a few connotations of what was inside the scope but to no avail.
The whole code block is in a try..catch and I've tried wrapping the ExecuteQuery line in it's own try..catch as well, but nothing catches it. The app crashes out every time when I hit continue.
I've also tried putting an execute query before loading the web but it still crashes out.
I'm thinking this has to be something to do with credentials? If I deliberately put the wrong username I get a polite '401 Unauthorized' back and no crash. And if I'm already logged in it doesn't crash either?
After trying the C# test application I tried the same with Delphi XE8 and that also worked, so in the end I've resorted to writing an intermediate DLL in XE8.
I noticed that when importing the TLB from the C# DLL into XE8 it behaved differently from D2007 in that it complained about other missing TLB's when building - notably the system.windows.forms library (and some dependencies). I'm not sure if this has any bearing on XE8 working and D2007 failing, but hopefully it well help anyone else needing a workaround.

C# TargetInvocationException and FormatException

Ok, I have a really weird situation happening here. First I need to give some background. I'm creating AI agents for a game that was made on the XNA engine. The way things are set up, people are supposed to use the agent's framework to generate a .dll that the game then uses to load the agents when it runs.
I have access to the code of the game (so I can see what's happening) and at this point I'm using someone else's agents as a starting point for my own. Recently, there were a few changes to the game (and consequentially, the framework), mostly in names of classes and interfaces which means I have to bring the agents up to speed. So, after I made all the updates necessary to be able to compile the agents with the new version of the framework, I came up with a problem. This is the code for the game loading the .dll
// dynamically load assembly from file GeometryFriendsAgents.dll
Assembly agentsDLL = Assembly.LoadFile(path);
// get type of classes BallAgent and SquareAgent from just loaded Assembly
Type circleType = AgentsDLL.GetType("GeometryFriendsAgents.CircleAgent");
Type rectangleType = AgentsDLL.GetType("GeometryFriendsAgents.RectangleAgent");
try {
// create instances of classes BallAgent and SquareAgent
npcCircle = (ICircleAgent)Activator.CreateInstance(circleType);
npcRectangle = (IRectangleAgent)Activator.CreateInstance(rectangleType);
}catch(TargetInvocationException e){
throw e.InnerException;
}
I can confirm that the path is correct. The lines inside the try/catch will throw a TargetInvocationException when I try to run the game (Which will automatically load the agents). I added the try/catch to see the inner exception, which is a FormatException, and VisualStudio gives the aditional information that the input string was not in the correct format.
I don't know what part of the agents code would be relevant for this, but I have yet to get to the weird part. In the implementation I'm using, the agents make use of a LearningCenter class. This class essentially reads and writes the learning files of the agents. at the start of the class it stores the path for the learning files:
protected const string path = #"..\..\..\..\Agents\";
So here's where things get weird. This is the correct path for the learning files. When earlier I made a mistake, I had this path (which before was repeated many times throughout the code) as
protected const string path = #"..\..\..\..\Agents";
When I build the .dll with the incorrect path, I can sucessfully load the agents and it will run the game. The problem then is that the path is incorrect, and when the LearningCenter tries to write the learning file, it will evidently fail with a DirectoryNotFoundException. The method in question is:
public void EndGame(float knownStatesRatio) {
if (_toSave) {
FileStream fileStream = new FileStream(path + _learningFolder + "\\Ratios.csv", FileMode.Append);
StreamWriter sw = new StreamWriter(fileStream);
sw.WriteLine(knownStatesRatio);
sw.Close();
fileStream.Close();
fileStream = new FileStream(path + _learningFolder + "\\IntraPlatformLearning.csv", FileMode.Create);
DumpLearning(fileStream, _intraplatformPlayedStates);
fileStream.Close();
if (interPlatform) {
fileStream = new FileStream(path + _learningFolder + "\\InterPlatformLearning.csv", FileMode.Create);
DumpLearning(fileStream, _interplatformPlayedStates);
fileStream.Close();
}
}
}
The exception occurs immediatly when creating the new filestream. I've tried shifting the missing \ to the _learningFolder variable, but when I do it goes back to the first problem. So long as the path is incorrect, I can run the game...
I should also mention that before this I initially encountered another TargetInvocationException at the same location. At the time the problem was fixed by changing the visibility of the agent classes to public.
I realize that the thing with the path is probably hiding the actual problem, but I just don't know where to look next.
edit: Here's the stack trace for the first problem
GeometryFriends.exe!GeometryFriends.AI.AgentsManager.LoadAgents() Line 396
GeometryFriends.exe!GeometryFriends.Levels.SinglePlayerLevel.LoadLevelContent() Line 78
GeometryFriends.exe!GeometryFriends.Levels.Level.LoadContent() Line 262
GeometryFriends.exe!GeometryFriends.ScreenSystem.ScreenManager.LoadContent() Line 253
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.DrawableGameComponent.Initialize()
GeometryFriends.exe!GeometryFriends.ScreenSystem.ScreenManager.Initialize() Line 221
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.Game.Initialize()
GeometryFriends.exe!GeometryFriends.Engine.Initialize() Line 203
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.Game.RunGame(bool useBlockingRun)
Microsoft.Xna.Framework.Game.dll!Microsoft.Xna.Framework.Game.Run()
GeometryFriends.exe!GeometryFriends.Program.Main(string[] args) Line 16
The agent that's failing first is the CircleAgent, here's the constructor:
public CircleAgent() {
//Change flag if agent is not to be used
SetImplementedAgent(true);
lastMoveTime = DateTime.Now;
lastRefreshTime = DateTime.Now;
currentAction = 0;
rnd = new Random(DateTime.Now.Millisecond);
model = new CircleWorldModel(this);
learningCenter = new CircleLearningCenter(model);
learningCenter.InitializeLearning();
startTime = DateTime.Now;
}
edit 2: Ok, I managed to zone in on the source of the FormatException.
The error occurs in this method of the CircleLearningCenter (the statement in the first if):
public override void addStateMovementValue(string[] lineSplit, string stateId, ref Dictionary<string, Dictionary<int, double>> lessons) {
if (!lineSplit[1].Equals("0")) {
lessons[stateId].Add(Moves.ROLL_LEFT, double.Parse(lineSplit[1]));
}
if (!lineSplit[2].Equals("0")) {
lessons[stateId].Add(Moves.ROLL_RIGHT, double.Parse(lineSplit[2]));
}
if (!lineSplit[3].Equals("0")) {
lessons[stateId].Add(Moves.JUMP, double.Parse(lineSplit[3]));
}
}
Which is called by this method in the LearningCenter:
private void createLearningFromFile(FileStream fileStream, ref Dictionary<string, Dictionary<int, double>> lessons) {
lessons = new Dictionary<string, Dictionary<int, double>>();
StreamReader sr = new StreamReader(fileStream);
string line;
while ((line = sr.ReadLine()) != null) {
string[] lineSplit = line.Split(',');
string stateId = lineSplit[0];
lessons.Add(stateId, new Dictionary<int, double>());
addStateMovementValue(lineSplit, stateId, ref lessons);
}
}
which in turn is called by this method (which it's called in the constructor of the circle):
public void InitializeLearning() {
if (File.Exists(Path.Combine(Path.Combine(path, _learningFolder), "IntraPlatformLearning.csv"))) {
FileStream fileStream = new FileStream(Path.Combine(Path.Combine(path, _learningFolder),"IntraPlatformLearning.csv"), FileMode.Open);
createLearningFromFile(fileStream, ref _intraplatformLessonsLearnt);
fileStream.Close();
} else {
createEmptyLearning(ref _intraplatformLessonsLearnt);
}
if (File.Exists(Path.Combine(Path.Combine(path, _learningFolder), "InterPlatformLearning.csv"))) {
FileStream fileStream = new FileStream(Path.Combine(Path.Combine(path, _learningFolder), "InterPlatformLearning.csv"), FileMode.Open);
createLearningFromFile(fileStream, ref _interplatformLessonsLearnt);
fileStream.Close();
} else {
createEmptyLearning(ref _interplatformLessonsLearnt);
}
}
In case it's not apparent, CircleLearningCenter is a subclass of LearningCenter. Also, sorry for the text wall, but I'm at my wits end.
Use System.IO.Path.Combine() to con-cat path parts. For example:
instead of :
FileStream(path + _learningFolder + "\\Ratios.csv")
use :
FileStream(Path.Combine(Path.Combine(path , _learningFolder) , "Ratios.csv"))
Just don't forget to remove \\ from each part.
And do the same for other FileStream paths.

Getting an exception as "The parameter is incorrect.\r\n" while moving file

I have written a code to move a file as follows
private void Move_Click(object sender, EventArgs e)
{
string strOrgpath = string.Empty, strNewpath = string.Empty;
strOrgpath = tvwACH.SelectedNode.ToString();
string strPath = strOrgpath.Substring(10);
FolderBrowserDialog folderborwser1 = new FolderBrowserDialog();
if (folderborwser1.ShowDialog() == DialogResult.OK)
{
try
{
strNewpath = folderborwser1.SelectedPath;
File.Move(strPath, strNewpath);
}
catch (Exception ex)
{
}
}
}
But i am getting the exception as i mentioned can any one tell why and some times i am getting the error as access to the path is denied
Make sure your substring call returns the correct result. If possible, use static methods from the Path class instead. Take a look at the MSDN page for File.Move and pay attention to what parameters are expected -- you should provide two valid full file names (e.g. C:\Blah\myFile.txt).
"Access denied" error message might happen if the user picks a folder they don't have write access to in the folder browser dialog. That's a scenario you'll have to handle in your code, perhaps by catching the UnauthorizedAccessException.
Update: the destination file should also point to a filename. So you'll need to do something like this:
var origFileName = Path.GetFileName(strPath);
strNewpath = Path.Combine(folderborwser1.SelectedPath, origFileName);
File.Move(strPath, strNewpath);
Without seeing the values that are being used in your application at run-time, I'm guessing tvwACH.SelecteNode.ToString() or strOrgpath.Substring(10) is not a valid File System path.
You should Debug your application and set a breakpoint to see what those values are (and post them if it's not obvious what your problem is at that point).

Categories