C# - User Settings broken - c#

We had a rare exception occur when reading the standard .Net user settings (this are the ones found in "project properties" in VS 2008):
System.Configuration.ConfigurationErrorsException was caught
Message="Configuration system failed to initialize"
Source="System.Configuration"
BareMessage="Configuration system failed to initialize"
Line=0
StackTrace:
at System.Configuration.ConfigurationManager.PrepareConfigSystem()
at System.Configuration.ConfigurationManager.GetSection(String sectionName)
at System.Configuration.PrivilegedConfigurationManager.GetSection(String sectionName)
at System.Diagnostics.DiagnosticsConfiguration.GetConfigSection()
at System.Diagnostics.DiagnosticsConfiguration.Initialize()
at System.Diagnostics.DiagnosticsConfiguration.get_IndentSize()
at System.Diagnostics.TraceInternal.InitializeSettings()
at System.Diagnostics.TraceInternal.get_Listeners()
InnerException: System.Configuration.ConfigurationErrorsException
Message="Unexpected end of file has occurred. The following elements are not closed: setting, SettingsTest.Properties.Settings, userSettings, configuration. Line 7, position 1. (C:\\Documents and Settings\\USER\\Local Settings\\Application Data\\Hitcents\\SettingsTest.vshost.exe_Url_ghwhc20utv4toanuinmj0pfsljthcugo\\1.0.0.0\\user.config line 7)"
Source="System.Configuration"
BareMessage="Unexpected end of file has occurred. The following elements are not closed: setting, SettingsTest.Properties.Settings, userSettings, configuration. Line 7, position 1."
Filename="C:\\Documents and Settings\\USER\\Local Settings\\Application Data\\Hitcents\\SettingsTest.vshost.exe_Url_ghwhc20utv4toanuinmj0pfsljthcugo\\1.0.0.0\\user.config"
Line=7
StackTrace:
at System.Configuration.ConfigurationSchemaErrors.ThrowIfErrors(Boolean ignoreLocal)
at System.Configuration.BaseConfigurationRecord.ThrowIfParseErrors(ConfigurationSchemaErrors schemaErrors)
at System.Configuration.BaseConfigurationRecord.ThrowIfInitErrors()
at System.Configuration.ClientConfigurationSystem.OnConfigRemoved(Object sender, InternalConfigEventArgs e)
InnerException: System.Xml.XmlException
Message="Unexpected end of file has occurred. The following elements are not closed: setting, SettingsTest.Properties.Settings, userSettings, configuration. Line 7, position 1."
Source="System.Xml"
LineNumber=7
LinePosition=1
SourceUri=""
StackTrace:
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
at System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String arg)
at System.Xml.XmlTextReaderImpl.ThrowUnclosedElements()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Xml.XmlTextReaderImpl.Skip()
at System.Xml.XmlTextReader.Skip()
at System.Configuration.XmlUtil.StrictSkipToNextElement(ExceptionAction action)
at System.Configuration.BaseConfigurationRecord.ScanSectionsRecursive(XmlUtil xmlUtil, String parentConfigKey, Boolean inLocation, String locationSubPath, OverrideModeSetting overrideMode, Boolean skipInChildApps)
at System.Configuration.BaseConfigurationRecord.ScanSectionsRecursive(XmlUtil xmlUtil, String parentConfigKey, Boolean inLocation, String locationSubPath, OverrideModeSetting overrideMode, Boolean skipInChildApps)
at System.Configuration.BaseConfigurationRecord.ScanSections(XmlUtil xmlUtil)
at System.Configuration.BaseConfigurationRecord.InitConfigFromFile()
InnerException:
*NOTE: this is re-created from a test app.
I pulled up the user.config file, and half of it was missing.
I expect our application was terminated abruptly for some reason or another.
This seems very rare, here is how we interact with the settings:
//How we read
Settings settings = Settings.Default;
_ourStaticMemberVariable = settings.OurValue;
//How we save
Settings settings = Settings.Default;
settings.OurValue = "Our Value";
settings.Save();
Is there anything wrong with how we're using it? Both calls have a try-catch that place some default values, but the values need to be able to reset from our application.
When in this state, our application cannot save new settings--and I cannot figure out a good way to programmatically recover. I had to manually find the user.config and delete it.
I also tried calling Settings.Reset(), etc. but get the same exception.
Any ideas on how to fix this? Or are we better off writing our own settings system or saving persistent settings in another way?
EDIT: A workaround is to delete the file from code, if you get a ConfigurationErrorsException.
Anyone know how to get the full path of the user.config file?

Here's a solution that does not require you to exit the application with kudos to Jarle (http://www.codeproject.com/Articles/30216/Handling-Corrupt-user-config-Settings?msg=3608682#xx3608682xx). Early on, before Settings ever gets called, use this
public static bool CheckSettings()
{
var isReset = false;
try
{
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.PerUserRoamingAndLocal);
}
catch (ConfigurationErrorsException ex)
{
string filename = string.Empty;
if (!string.IsNullOrEmpty(ex.Filename))
{
filename = ex.Filename;
}
else
{
var innerEx = ex.InnerException as ConfigurationErrorsException;
if (innerEx != null && !string.IsNullOrEmpty(innerEx.Filename))
{
filename = innerEx.Filename;
}
}
if (!string.IsNullOrEmpty(filename))
{
if (System.IO.File.Exists(filename))
{
var fileInfo = new System.IO.FileInfo(filename);
var watcher
= new System.IO.FileSystemWatcher(fileInfo.Directory.FullName, fileInfo.Name);
System.IO.File.Delete(filename);
isReset = true;
if (System.IO.File.Exists(filename))
{
watcher.WaitForChanged(System.IO.WatcherChangeTypes.Deleted);
}
}
}
}
return isReset;
}
Essentially, rather than relying on Sittings to throw the error, read the file with the ConfigurationManager, that way the system's version never gets into a bad state.

The way to programmatically recover is to do what you did manually - delete the user settings file. Then call Settings.Reset. (You could also write a new user settings file with default values instead of deleting it, but if you're using the configuration manager properly that's essentially the same thing.)
This is a pretty rare occurrence, but it's not totally unheard of. Not only can your program crash while writing the user settings file, the file itself is user-writeable, so other programs the user runs could mess with it.
To avoid this particular vulnerability, persist user settings in a durable store with transactional integrity, i.e. a database. (You'll still have vulnerabilities, just not this one.) That's a lot of work for what in most cases will be a marginal improvement in reliability. But "in most cases" doesn't mean "in all cases;" yours may warrant it.

[STAThread]
private static void Main(string[] args)
{
try
{
// ...
}
catch (System.Configuration.ConfigurationErrorsException ex)
{
var config = ((System.Configuration.ConfigurationErrorsException)ex.InnerException).Filename;
// notify user, ask them to restart
System.IO.File.Delete(config);
Application.Exit();
}
}

Related

c# Rotativa issue in production server using user built template pdf generation

i am developing a enterprise app in c# .net. There are many pdf documents generated in the system. I use Rotativa for pdf handling. There is one pdf which uses user created template in the system. System fetches data from the system and replaces the template variables with the dynamic values from server and downloads the pdf. This particular pdf is working fine in my local and development server, but fails in the production server. Will be glad if somebody could help. i have attached the error and the code. please have a look.
public ActionResult GenerateRedemptionLetterGift(int id, int templateId)
{
try
{
int RedTempId = templateId; //Convert.ToInt32(Request.QueryString["templateId"]);
int type = 2;
RedemptionCode RedemptionObj = new RedemptionCode();
RedemptionObj = BlObj.GetRedemptionDetail(id);
return new Rotativa.MVC.ActionAsPdf("ReturnTemplate", new { id, RedTempId, type }) { FileName = "Redemption_Letter_" + RedemptionObj.Id.ToString() + ".pdf" };
}
catch (Exception ex)
{
throw new Exception("Main Method", ex);
}
}
here i call a function ReturnTemplate as ActionAsPdf where all the data is fetched and replaced in the user created template.
public ActionResult ReturnTemplate(int id, int RedTempId, int type)
{
try
{
RedemptionTemplateBO RedTemp = new RedemptionTemplateBO();
RedTemp = BlObj.GetRedemptionTemplateForEdit(RedTempId);
Hashtable TempStrings = new Hashtable();
if (type == 1)
{
TempStrings = GenerateRedemptionHashTable(id);
}
else if (type == 2)
{
TempStrings = GenerateRedemptionHashTableGift(id);
}
StringBuilder builder = new StringBuilder();
builder.Append("<html><head><title>Redemption Letter</title></head><body><style> #font-face {font-family: myFirstFont;src: url(~/fonts/Roboto-Regular.ttf);} p{font-family: 'Roboto', sans-serif;color: #3e3e3e;font-size: 15px;font-weight: 400;margin-bottom: 10px}</style>");
builder.Append(RedTemp.TemplateContent);
builder.Append("</body></html>");
foreach (string key in TempStrings.Keys)
{
builder.Replace("[" + key + "]", (string)TempStrings[key]);
}
return Content(builder.ToString());
}
catch( Exception ex)
{
throw new Exception("Return Template", ex);
}
}
I have checked in the local using a break point, if i am getting the correct data in the string for returning in the second method. Its coming fine.
Its running fine in both local and development server. I am getting the expected pdf.
But when i run it in production. i am running into an error, and it doesnt seem to be hitting the try catch block also.
Server Error in '/' Application.
Error: Failed loading page http://app.com/Redemption/ReturnTemplate/185?RedTempId=3&type=2 (sometimes it will work just to ignore this error with --load-error-handling ignore)
Exit with code 1 due to network error: RemoteHostClosedError
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.Exception: Error: Failed loading page http://app.com/Redemption/ReturnTemplate/185?RedTempId=3&type=2 (sometimes it will work just to ignore this error with --load-error-handling ignore)
Exit with code 1 due to network error: RemoteHostClosedError
This is the last few stack trace
Rotativa.Core.WkhtmltopdfDriver.Convert(DriverOptions options, String html) +793
Rotativa.MVC.AsPdfResultBase.CallTheDriver(ControllerContext context) +27
Rotativa.MVC.AsPdfResultBase.BuildPdf(ControllerContext context) +203
Rotativa.MVC.AsPdfResultBase.ExecuteResult(ControllerContext context) +27
WkhtmltopdfDriver takes too long to respond from production server.
Could it be due to some outgoing calls in Rotativa server. But still my other pdf generations work fine with rotativa in the production server.
We had a similar but different error: Failed loading page:...HostNotFoundError
Basically, rotativa was trying to resolve the domain name from within the intranet, but this particular network does not allow you to access their own public facing sites using its bound domain name. Switching to .UrlAsAPdf and using the intranet IP address, fixed this.
Also test the PDF view/ page locally first, to see that it is doing what you want.

ASPX works locally but not on server

I have uploaded a web project on the server.
While it was running smoothly on my local pc where the development was made, it's not running at all on the server. As far as I can read the error, theres' a problem with an empty DataSet (fetches data from a SQL db). Again, when running the aspx locally everything is ok. Another issue I see on the errorlog is it points to my local drive "D:..." Shouldn't it point to the server address?
Error.
There is no row at position 0.
Exception Details: System.IndexOutOfRangeException: There is no row at position 0.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[IndexOutOfRangeException: There is no row at position 0.]
System.Data.RBTree`1.GetNodeByIndex(Int32 userIndex) +2474798
System.Data.DataRowCollection.get_Item(Int32 index) +21
WEB.Default.Page_Load(Object sender, EventArgs e) in D:\dev\Visual Studio\Temp\WEB\Default.aspx.cs:59
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +25
System.Web.UI.Control.LoadRecursive() +71
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3064
Any idea? I use the publish tool from VS2010 and it succesfully uploads in the server. But it's not working.
Another thing I don't get is, why the webpage sends this error if I have a try/catch in the page load. If there's an error, it sets a Label with a friendly message.
Thanks.
EDIT
Here's the page load code.
protected void Page_Load(object sender, EventArgs e)
{
try
{
if (!IsPostBack)
{
Session["FlagOpen"] = false;
var windowsIdentity = WindowsIdentity.GetCurrent();
if (windowsIdentity != null)
{
var userName = windowsIdentity.Name;
userName = Regex.Replace(userName, ".*\\\\(.*)", "$1", RegexOptions.None);
var ds = _objUser.GetRanking(userName);
var ranking = ds.Tables[0].Rows[0][1].ToString();
_objPersona.Ranking = ranking;
_objPersona.UserName = userName;
_objPersona.RealName = ds.Tables[0].Rows[0][0].ToString();
Session["User"] = _objPersona;
LblUserName.Text = ds.Tables[0].Rows[0][0].ToString();
ds = _objUser.GetFAQ(userName);
var cant = ds.Tables[0].Rows.Count;
}
else
{
BtnAbrirBandeja.Enabled = false;
LblUserName.Text = "Not allowed.";
}
}
}
catch (Exception)
{
LblWarnings.Text = "Error. Please contact sysadmin.";
throw;
}
}
EDIT 2.
Page keeps working locally. But not on the server. It throws the original error pointing to a local folder (when it's already uploaded and running from the server).
The DataSet being null is a consequence of the web not being able to communicate with the SQL server. Hence the error.
Basically, it runs OK while debugging, but not on server.
Any ideas? Thanks.
You need to test your dataset for null before you try to access an element from the dataset, hence the error message:
if (ds!=null)
{
//continue and access the dataset
}
else
{
//you didn't get any data or ds is simply null (result set is null)
}
You are also misusing the var keyword, you don't need to use var for simple types like strings and datasets.
For whatever reason your data is inaccessible or doesn't exist:
[IndexOutOfRangeException: There is no row at position 0.]
var ranking = ds.Tables[0].Rows[0][1].ToString();
You need to be checking ds.Tables.length (or count as it may be) before performing that line.
May be when running on your local machine it was taking data from your local server and now its getting data from your server database engine..tables may be empty there or may be tables not exist there..
Check your dataset fetching method for any errors..your try catch might have hidden that error..
your another part of question:
It throws that exception because your catch block has a 'throw' statement, which will just through the same error catched by the catch block with all the inner exception details..
Note: if you write
catch(Exception ex)
{throw ex;}
inner exception details would be lost...

Access To The Path ... Is Denied

Alright, I've seen tons of questions about this thing, but still, no one answers my question. In fact, each one of the questions I saw differs from the other, this access thing really seems to be hassling programmers.
Please check out the code:
DirectoryInfo Dir1 = Directory.CreateDirectory(Desktop + "\\DIR1");
DirectoryInfo Dir2 = Directory.CreateDirectory(Desktop + "\\DIR2");
//* Lets Create a couple of SubDirs in DIR1
for (int i = 0; i < 5; i++)
{
// this will create 5 SubDirs in DIR1, named Sub1, Sub2 ... Sub5.
Dir1.CreateSubdirectory("Sub" + (i + 1).ToString());
//* lets create 5 text files in each SubDir:
for (int j = 0; j < 5; j++)
{
File.Create(Dir1.FullName + "\\Sub"+(i+1).ToString() + "\\text"+(j+1).ToString() + ".txt");
}
}
//* Lets Move all what we created in DIR1 to DIR2 (THIS IS WHERE I'M GETTING THE EXCEPTION
Directory.Move(Dir1.FullName, Dir2.FullName + "\\DIR1");
// I also Tried Dir1.MoveTo(Dir2.FullName + "\\DIR1");
Stack Trace:
at System.IO.DirectoryInfo.MoveTo(String destDirName)
at Directory_Class.Program.Main(String[] args) in c:\users\vexe\documents\visual studio 2010\Projects\Directory_Class\Directory_Class\Program.cs:line 207
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
And of course, I tried the usual:
DirectorySecurity DirSec = Dir1.GetAccessControl();
string user = Environment.UserName;
DirSec.ResetAccessRule(new FileSystemAccessRule(user, FileSystemRights.FullControl, AccessControlType.Allow));
Dir1.SetAccessControl(DirSec);
But it didn't change a bit!
I also tried changing the permissions manually, by right clicking dir1 -> properties -> security -> edit -> add -> typed everyone (in the enter object names to select) -> ok -> fullcontrol to everyone. (I also saw that my user account had full control as well)
Any hints would be deeply appreciated
While it is an Access Denied exception, it sounds like the text files are in use and cannot be moved because there are open references to the file.
The File.Create method returns a FileStream object which I'd imagine must be closed/disposed before the files can be modified.
Try the following for your inner loop:
for (int j = 0; j < 5; j++)
{
using(var fs = File.Create(Dir1.FullName + "\\Sub"+(i+1).ToString() + "\\text"+(j+1).ToString() + ".txt"))
{
//fs.WriteByte(...);
fs.Close();
}
}
First off, you should use Path.Combine instead of doing string concatenation.
Second off, the stack trace isn't as helpful as the exception being thrown.
I imagine your problem might be fixed by doing this though:
Directory.Move(Dir1.FullName, Dir2.FullName);
If that fixes it, then the issue is with the DIR1 subdirectory you're trying to move it to.
As a debugging, step you should set failure auditing on the two folders (under advanced security settings). Just set everyone to audit all failures, then try your operation again. Depending on the OS version that you are running you should get the user account being used for the operation and what privilege was missing. Also make sure that there are no deny permissions set on the folder as they override all other permissions. You will want to look at the security event log. If there are no failure audits for the operation then it is not a permissions issues.
It seems to me Windows loves blocking deletes (renames) of directories for literally no reason. I'm sure it has one, but I don't care what it is. I've found that deleting the contents of the directory, then deleting the empty folder works every time. It works with the following rename as well.
I came up with this, as windows was giving me access to path denied for the FROM directory. I was just renaming it within the app, not really moving locations. Anyway, based on the above information, I came up with this and it works.
public static void MoveTo_BruteItAsNecessary(this DirectoryInfo FROM, string TO, bool recycle = false)
{
try
{
FROM.MoveTo(TO);
}
catch (IOException ex)
{
if (ex.Contains($"Access to the path '{FROM.FullName}' is denied."))
{ // Contains checks the Message & InnerException.Message(s) recursively
System.IO.Directory.CreateDirectory(TO);
foreach (var dir in FROM.GetDirectories())
dir.MoveTo(Path.Combine(TO, dir.Name));
foreach (var file in FROM.GetFiles())
file.MoveTo(Path.Combine(TO, file.Name));
if (recycle)
FROM.Recycle();
else
FROM.Delete();
}
else
throw;
}
}

System.IO.File.Copy() produces System.IO.IOException: The specified network name is no longer available

I have a windows service (C# .Net 3.5) that grabs data from a network share and does a copy to the host of the service.
The size of the data copied ranges from 50KB to 750MB, and the number of files copied varies. In perhaps 20% of the copies I am getting System.IO.IOException: The specified network name is no longer available.
My google-fu is failing to turn up an answer as to what might cause this during a File.Copy. Has anyone seen/solved this before?
Here is the recursive method that does the copy. The exception occurs on line File.Copy(fromFile, toFile, overwrite);
private static int RecursiveCopyDirectory(string from, string to, bool merge, bool overwrite, int depth)
{
depth++;
if (!from.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
to += Path.DirectorySeparatorChar;
}
if (!to.EndsWith(Path.DirectorySeparatorChar.ToString()))
{
to += Path.DirectorySeparatorChar;
}
System.Diagnostics.Debug.WriteLine(string.Format("RecursiveDirectoryCopy( {0}, {1}, {2} )", from, to, merge));
if (Directory.Exists(to))
{
if (!merge)
{
return (int)EventEnum.FileSystemError_DirectoryAlreadyExists;
}
}
else
{
Directory.CreateDirectory(to);
}
string[] directories = Directory.GetDirectories(from);
foreach (string fromDirectory in directories)
{
string [] fromDirectoryComponents = fromDirectory.Split(Path.DirectorySeparatorChar);
string toDirectory = to + fromDirectoryComponents[fromDirectoryComponents.Length - 1];
RecursiveCopyDirectory(fromDirectory, toDirectory, merge, overwrite, depth);
}
string[] files = Directory.GetFiles(from);
foreach (string fromFile in files)
{
string fileName = Path.GetFileName(fromFile);
//System.Diagnostics.Debug.WriteLine(string.Format("Name: {0}", to + fileName));
string toFile = to + fileName;
File.Copy(fromFile, toFile, overwrite);
}
return (int)EventEnum.GeneralSuccess;
}
File.Copy() opens up underline streams. You might have lost connection while File.Copy() is in progress. So, it can't flush and close the stream.
One possibility to recover from this, is to use the FileStream class and
call Win32 API CloseHandle when such exception occurs, doing so will release
the OS file handle so you can re-open the file.
[ DllImport("Kernel32") ]
public static extern bool CloseHandle(IntPtr handle);
FileStream fs;
try {
...
}
catch(IOException)
{
// If resource no longer available, or unable to write to.....
if(...)
CloseHandle(fs.Handle);
}
Also, MSDN recommends not to rely on overwrite. Try deleting existing file and creating new one when copying them.
File.Copy(..., ..., TRUE) does not work properly.
Be very careful with this method, as the Overwrite = True does NOT work properly.
I had an existing destination file that had some information inside it that was somehow preserved and carried over to the source file that was supposed to copy over it. This should be impossible, but I confirmed it for myself.
The error seems to indicate that the network connection is lost partway through and probably isn't to do with the code at all. If the same folder copy succeeds sometimes and fails other times then this would back up that it's not the code to blame and must be a resource access issue.
It turns out that the customer that was using this software was running two instances of it simultaneously, against the same data set. Once the redundant instance was stopped it resolved the error. Thanks everyone who answered.

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