having an issue when saving data, I am trying to set it up so if the user tries to save their name data for their character and a file already exists, it will create a second xml file "NameData2.xml" and so forth until a maximum of 3 files is reached, ( so the user has differant characters to choose from ) however at the moment it is simply creating 2 xml files at once all containing the same name ( i would guess this is due to them checking all at once in the same if else statements possibly? all i could find when trying to find an answer was how to check for a files existence and if it cant find it how to create one, i will post my code below if anyone has any suggestions that would be brilliant as im quite stumped!
Thankyou in advance.
// This will save the users generated name in a created file
// NameData.xml and will take the user to the partySelectionScreen.
private void continueButton_Click(object sender, RoutedEventArgs e)
{
try
{
NameSavingInformation nameInfo = new NameSavingInformation();
nameInfo.GeneratedName = generatedNameTexbox.Text;
SaveXml.SaveData(nameInfo, "NameData.xml");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
if(File.Exists("NameData.xml"))
{
NameSavingInformation nameInfo = new NameSavingInformation();
nameInfo.GeneratedName = generatedNameTexbox.Text;
SaveXml.SaveData(nameInfo, "NameData2.xml");
}
else if (File.Exists("NameData2.xml"))
{
NameSavingInformation nameInfo = new NameSavingInformation();
nameInfo.GeneratedName = generatedNameTexbox.Text;
SaveXml.SaveData(nameInfo, "NameData3.xml");
}
else if (File.Exists("NameData3.xml"))
{
MessageBox.Show("You have passed the limit of existing characters" +
"To continue please return to the main menu and delete at least 1 character");
}
You should do like this.
This will perform a a search on the files that doesn't exists and will generate them. This will permit the user to delete any character the wants without breaking the algorithm.
private void continueButton_Click(object sender, RoutedEventArgs e)
{
if(!File.Exists("NameData.xml"))
{
SaveFileInfo("NameData.xml");
}
else if (!File.Exists("NameData2.xml"))
{
SaveFileInfo("NameData2.xml");
}
else if (!File.Exists("NameData3.xml"))
{
SaveFileInfo("NameData3.xml");
}
else
{
MessageBox.Show("You have passed the limit of existing characters" +
"To continue please return to the main menu and delete at least 1 character");
}
}
public SaveFileInfo(string fileName)
{
try
{
NameSavingInformation nameInfo = new NameSavingInformation();
nameInfo.GeneratedName = generatedNameTexbox.Text;
SaveXml.SaveData(nameInfo, fileName);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Related
Good day.
In my C# windows forms app, I would like to open .pdf files.
The code to do this is:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(lblPdf.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The .pdf file paths are storred in an SQL database.
They are stored in this manner: C:\Folder1\Folder2\File Name
In this example this means:
lblPdf.Text="C:\Folder1\Folder2\File Name";
*note: File Name(s) is/are stored without file type (so no .pdf at the end)
Of course this doesn't work, so I added the "#" and ".pdf" to the string:
lblTest.Text = ("#" + "\"" + lblPdf.Text + ".pdf" + "\"");
When I test this with a Message Box:
MessageBox.Show(lblTest);
I get:
#"C:\Folder1\Folder2\File Name.pdf"
The trouble I am experiencing is that this works:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
MessageBox.Show(lblTest.Text);
System.Diagnostics.Process.Start(#"C:\Folder1\Folder2\File Name.pdf");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
and this does not work:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
MessageBox.Show(lblTest.Text);
System.Diagnostics.Process.Start(lblTest.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Can anyone shed a light on why this is so?
The error message I receive in the second example is:
"The system cannot find the file specified"
MessageBox.Show gives me the correct syntax and file path in both cases.
Thank you.
#Shovers and anyone else to whom it may concern:
private void btnOpenPdf_Click(object sender, EventArgs e)
{
lblTest.Text = ("#" +lblPdf.Text + ".pdf" );
try
{
MessageBox.Show(lblTest.Text);
System.Diagnostics.Process.Start(lblTest.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Thanks guys.
Just adding the
+ ".pdf"
to the label (lblPdf.Text) is the answer.
private void btnOpenPdf_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(lblPdf.Text + ".pdf");
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
I can give you a number of hints:
1 Exceptions
Proper exception handling is a pet peeve of mine and yours is problematic. Your code handles fatal exceptions. And never catching fatal exceptions is a very important part. Doing it will only get you more and less understandable followup errors. Here are two artciles on the mater I do link often:
https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/
https://www.codeproject.com/Articles/9538/Exception-Handling-Best-Practices-in-NET
2. How are those PDF stores with the Database?
PDFs are Binary Large Objects (BLOBS). Ther are two schools of tought on to store blobs with a DB and both affect wich path you have to give:
You store the blob itself in the DB. Usually that requires setting up a HTTP handler to provide the file for download/user consumption. In this case you need a URL to access those files
You store the files in the Filesystem. The DB only contains the paths. In this case you have to eitehr use the URL, Share path or whatever else way you got to download those files
SQL Filestream and equivalent attributes from other DB are a bit of a combination of the two. It works mostly like the 1st one, with performance closer to the 2nd one.
You might have some 4th bastardised version here. Or you simply did not understand how how to use the values in the DB.
I want to delete a file, in case it is locked by another process even though I have set try catch, but the program is still dark cash at fi.Delete(), so how to fix it.
A first chance exception of type 'System.UnauthorizedAccessException'
occurred in mscorlib.dll
Additional information: Access to the path 'H:\J\R\sound.MP4' is
denied.
private void GView_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
{
try
{
string cellValue = GView.Rows[e.RowIndex].Cells["NAME"].Value.ToString();
var confirmResult = MessageBox.Show("delete this item " + cellValue,
"Confirm Delete!!",
MessageBoxButtons.YesNo);
if (confirmResult == DialogResult.Yes)
{
System.IO.FileInfo fi = new System.IO.FileInfo(cellValue);
fi.Delete();
}
else
{
}
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
}
}
private void GView_CellContentDoubleClick(object sender, DataGridViewCellEventArgs e)
{
try
{
string cellValue = GView.Rows[e.RowIndex].Cells["NAME"].Value.ToString();
var confirmResult = MessageBox.Show("delete this item " + cellValue,
"Confirm Delete!!",
MessageBoxButtons.YesNo);
if (confirmResult == DialogResult.Yes)
{
System.IO.FileInfo fi = new System.IO.FileInfo(cellValue);
fi.Delete();
}
else
{
}
}
catch(System.IO.IOException)
{
// exception when file is in use or any other
}
catch (UnauthorizedAccessException ex)
{
MessageBox.Show(ex.Message);
}
catch(Exception ex)
{
// all other
}
}
I read this article, as suggested by #Keyur PATEL, and figuring out this is a configuration of Visual Studio, I solved it by doing the following:
Navigate to "Debug / Exceptions / Common Language Runtime Exceptions / System"
Scroll down to where "NullReferenceException" is, and uncheck the "throw" checkbox, and check the "user-handled".
Thanks for your help
The user, whose account is used to run your application, must have access to that path
There are 2 ways to achieve this:
Configure a special application pool for your application, that will run under a user that has necessary permissions (can access admin shares on remote server). So your entire application will run under that account and have all its permissions.
Using impersonation to execute parts of your code under another account. This doesn't require any IIS configuration and is more secure and flexible than first way (for example? you can impersonate several accounts in a single application).
I am currently working on an application for the company I work for. Part of this application deals with discrepancy reporting and sending emails out when a new discrepancy number has been created. First, it is important to realize that I am redeveloping this application from VB.NET to C#. In the old application the developer chose to read an XML file for a few email addresses. I've read to use alternate options unless the XML file is full of information. This is not intended to be an opinionated question and sorry if this sounds like one. However, I am looking for the correct way of doing this. Should these email addresses be kept in a database table for easy adding/deleting or is there a more standardized way to do this? Please find the current code below.
public void PrepareEmail(string subject, string message)
{
if (MessageBox.Show(#"Are you sure you want to save and send Discrepancy Report: " + tbxDRNumber.Text + #"?\n Click YES to save\n Click NO to cancel", #"Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
SendEmail(subject, message);
}
}
public Array AddEmail()
{
string[] dRemail = { "", "", "" };
if (File.Exists(#"\\fs01\Applications\EMS-Manager\DREmailAddresses.xml"))
{
XmlReader emailDocument = new XmlTextReader(#"\\fs01\Applications\EMS-Manager\DREmailAddresses.xml");
while (emailDocument.Read())
{
var type = emailDocument.NodeType;
switch (type)
{
case XmlNodeType.Element:
if (emailDocument.Name == "DRCreatedAddEmail")
{
dRemail[0] = emailDocument.ReadInnerXml();
}
if (emailDocument.Name == "DRActionNeededAddEmail")
{
dRemail[1] = emailDocument.ReadInnerXml();
}
if (emailDocument.Name == "DRPendingAddEmail")
{
dRemail[2] = emailDocument.ReadInnerXml();
}
else
{
MessageBox.Show(#"The file: 'DREmailAddresses.xml' was not found at: \\fs01\Applications\EMS-Manager");
}
break;
}
}
}
return dRemail;
}
public void SendEmail(string subjectText, string bodyText)
{
string[] email = (string[])AddEmail();
//object oOutlook = default(Microsoft.Office.Interop.Outlook.Application);
var oMessage = default(MailItem);
Activator.CreateInstance(Type.GetTypeFromProgID("Outlook.Application"));
if (subjectText == "New Discrepancy Created. DR" + tbxDRNumber.Text + " ")
{
oMessage.To = email[0];
oMessage.Subject = subjectText;
oMessage.HTMLBody = bodyText;
try
{
oMessage.Send();
}
catch (System.Exception e)
{
MessageBox.Show(#"Send Failed with error: " + e);
throw;
}
}
else if (subjectText == tbxDRNumber.Text + " - Action Needed")
{
oMessage.To = email[1];
oMessage.Subject = subjectText;
oMessage.HTMLBody = bodyText;
try
{
oMessage.Send();
}
catch (System.Exception e)
{
MessageBox.Show(#"Send Failed with error: " + e);
throw;
}
}
else if (subjectText == tbxDRNumber.Text + "DR Pending Approval")
{
oMessage.To = email[2];
oMessage.Subject = subjectText;
oMessage.HTMLBody = bodyText;
try
{
oMessage.Send();
}
catch (System.Exception e)
{
MessageBox.Show(#"Send Failed with error: " + e);
throw;
}
}
}
There isn't necessarily anything wrong with flat file configuration files. It really depends on your use case. How often do the emails in the file change? How many entries are there? Do users of the application edit the list? Are there any complex rules where different addresses will get sent different emails?
If this just a simple mailing list that doesn't change often it's probably fine to use the xml file. You could also just create an email distribution list to send to instead, like ApplicationDiscrepancyReport. That way you can just manage the recipients in active directory. If you stick with the XML email addresses, at the very least I would try to get rid of the hardcoded path to the xml file located on your file share.
If the email addresses change a lot, and are changed by users of the application, I would recommend moving this to a SQL database. If the recipients list is changing frequently you may want to add tracking of when these addresses get edited as well.
As you see I have some object in my hand but I couldn't figure out how to get current file name. I am getting _currentSlideName from an xml file and compare to open new slide.
Do you have any suggestion to get current power point presentation file name?
ppt.Application _pptApplication = new ppt.Application();
private void Open(string fileName)
{
_presentation = _pptApplication.Presentations.Open(fileName, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
}
private void CheckSlide()
{
if (_oSlideShowView == null)
{
try
{
Open( _settingObj.Path + _currentSlideName);
}
catch (Exception)
{
Open(_settingObj.Path+ "Test.pptx" );
}
}
else if (_currentSlideName != _presentation.Path)
{
try
{
Open( _settingObj.Path + _currentSlideName);
}
catch (Exception)
{
Open(_settingObj.Path+ "Test.pptx" );
}
}
}
Getting the full filename of the open presentation is simply Presentation.FullName. In your case, this would be:
_pptApplication.ActivePresentation.FullName
Note that this only returns the presentation's name if the file is not currently saved. If it is not saved, the presentation's Path is an empty string.
EDIT: The example above returns the full filename. If you want only the name, use the following. Just to clarify that this only makes sense with saved presentations, I've added a check on Path.
if(!_pptApplication.ActivePresentation.Path.Equals("")) {
var name = _pptApplication.ActivePresentation.Name
... do processing...
}
else {
... error ...
}
I have a try catch statement which handles reading a list of xml files and outputs them to csv files.
Now I want to be able to move faulty xml files to a different folder from the healthy files but am not sure how to do it.
What I have got so far is as below:
bool faultyYN = false;
foreach (string filename in XMLFiles)
{
using (var reader = new StreamReader(filename))
{
string shortFileName = Path.GetFileNameWithoutExtension(filename);
XMLShredder.DataFile df = null;
try
{
var sw = new Stopwatch();
sw.Start();
df = Shredder.ShredDocument(XDocument.Load(reader, LoadOptions.SetLineInfo));
sw.Stop();
var elapsed = sw.ElapsedMilliseconds;
_log.InfoFormat(" Shredded file <{0}> in {1}ms", shortFileName, elapsed);
string outputFileName = Path.Combine(outputDirectory, shortFileName) + ".csv";
sw.Reset();
sw.Start();
using (var writer = new ChunkedShreddedFileWriter(outputFileName))//full file path
{
new DataFileCsvWriter().Write(df,
writer);
}
sw.Stop();
var elapsed2 = sw.ElapsedMilliseconds;
_log.InfoFormat(" Wrote file <{0}> in {1}ms", shortFileName, elapsed2);
}
catch (XmlException e)
{
_log.Error(String.Format("Reading failed due to incorrect structure in XML Document. File Name : <{0}>. Error Message : {1}.", shortFileName, e.Message), e);
faultyYN = true;
}
catch (IOException e)
{
_log.Error(String.Format("Reading failed due to IO Exception. File Name : <{0}>. Error Message : {1}.", shortFileName, e.Message), e);
}
if(bool faultyYN == true)
{
MoveFaultyXML(faultyXMLDirectory, shortFileName);
}
}
TidyUp(XMLFiles);//deletes the files after the process has finished.
}
I have tried adding the Move faulty files to faulty directory after the catch but the files still keep getting deleted.
So basically the method that does not work as I don't know where I should be calling it from is "MoveFaultyXML(faultyXMLDirectory, shortFileName)".
I have read on the net that I shouldn't be using a an exception to branch out but in this case I couldn't think of an alternative solution. The exception has to be thrown for me to know that there is something wrong with the file.
If there is another way of dealing with this which is better practice or if this way works but I am doing it wrong then please help me and I would really appreciate it.
Thanks,
Jetnor.
First solution that comes to my mind would be to:
Move the MoveFaultyXML(faultyXMLDirectory, shortFileName); call to do it within the appropriate catch block:
catch (XmlException e)
{
//log
MoveFaultyXML(faultyXMLDirectory, shortFileName);
}
You don't need the boolean faultyYN.
Now you can create a class representing your XML file (instead of storing just file names in your XMLFiles list):
public class XMLFile
{
public string FileName { get; set; }
public bool Delete { get; set; }
}
And set the Delete flag to 'false' if you move the file.
In the TidyUp delete only files with this flag set to 'true'.
An alternative solution would be to:
Replace foreach() with
for(int i=XMLFiles.Count - 1; i >= 0; i--)
{
string filename = XMLFiles[i];
//the rest of your code
}
Change the catch block with the XMLException to:
catch (XmlException e)
{
//log
MoveFaultyXML(faultyXMLDirectory, shortFileName);
XMLFiles.RemoveAt(i);
}
This way when you get to CleanUp function, any files that were moved are no longer on the list to be deleted.
The `XmlException' is thrown when the XML is incorrect, so it is inside this catch block that you have to call your MoveFaultyXML.
Additional Notes:
Don't add YN to boolean names. Use something like xmlIsFaulty = true. This makes the code easier to read because then you have conditional statements like
if(xmlIsFaulty){MoveFaultyXml();}
which even a non-programmar can understand.
In this code, you're redeclaring the faultyYN variable which should given an error.
if(bool faultyYN == true)
{
MoveFaultyXML(faultyXMLDirectory, shortFileName);
}
After you've declared the variable at the start of the method, you do not need to declare it again.
This is because TidyUp(XMLFiles); still gets executed after your exception is caught, you can move TidyUp(XMLFiles); to within the try block or only call it in catch blocks which are needed.