Send Log file with email? Unity - c#

I'm using Unity and C#
I want to send the output log file to my email at runtime, I used ByteSheep answer from this question and ArkaneX comment from this question to attach a txt file, now I was successful at sending txt files but how can I send the log file? I used this code to set the path to the log System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData) + #"\Unity\Editor\Editor.log" and it does get the correct path, the problem is I'm getting
IOException: Sharing violation on path
when System.Net.Mail.Attachment attachment = new System.Net.Mail.Attachment(attachmentPath); is called.
I think I need o close the log file first but is that even possible?
maybe a solution would be duplicating the log file and sending the new one? would that work? if so how?
Any help is apprechiated.
Thanks in advance,

I had a similar situation and came up with below code. As the log file is in use by the program, I'm creating a copy of it and sending it as an email attachment.
private string logFilePathS = #Directory.GetCurrentDirectory() + #"\logs\log.txt";
private string logFilePathD = #Directory.GetCurrentDirectory() + #"\logs\log-" + String.Format("{0:dd-MMM-yyyy}", DateTime.Now) + ".txt";
File.Copy(logFilePathS, logFilePathD, true);
mailMessage.Attachments.Add(new Attachment(logFilePathD));
Once the email is sent, you can delete the new file created.
File.Delete(logFilePathD);

Related

How to create multiple files in design automation api for revit and download result as one zip file

I am working on a project where I am required to create multiple revit files, zip them all together and download the zip file as the output in design automation API for Revit.
My project is completely working as expected on my local machine, but when I upload my appbundle and execute my workitem, I get a "failedInstructions" status.
I am not aware whether it is possible to create multiple revit files in design automation API
Following is what I have tried:
This is my workitem json, you see I am passing a json array with sample data for the wall.
"arguments":{
"ElementParams":{
"url":"{'elementdata':[[{'Keys':'Sytème','Value':'Wall_1'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_2'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_3'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}],[{'Keys':'Sytème','Value':'Wall_4'},{'Keys':'Thickness','Value':'120.00'},{'Keys':'Length','Value':'2500.00'},{'Keys':'Height','Value':'1200.00'}]]}"
},
"resultFamily":{
"verb":"put",
"url":"https://storage.googleapis.com/bucketname/RevitObjects.zip?XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"headers": {
"Authorization": "",
"Content-Type": "application/octet-stream"
}
}
}
In my code, I create a new document in a loop.
Document doc = app.NewProjectDocument(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) + "\\" + "DefaultTemplates.rte");
and save and close the current document
SaveAsOptions options = new SaveAsOptions();
options.OverwriteExistingFile = true;
doc.SaveAs(Assembly.GetExecutingAssembly().Location) + "\\" + fileName, options);
doc.Close(); //Closing the document
List<string> files = Directory.GetFiles(Assembly.GetExecutingAssembly().Location) + "\\").Where(a => a.Contains(Path.GetFileNameWithoutExtension(fileName)) && a.Split('.').Count() > 2).ToList();
foreach (var fl in files)
{
if (File.Exists(fl))
File.Delete(fl);
}
byte[] filebytes = File.ReadAllBytes(GlobalData.TemplatePath + "\\" + GlobalData.DestinationFile);
GlobalData.FileList.Add(GlobalData.DestinationFile, filebytes);
Here fileName is Wall_1, Wall_2, Wall_3 and Wall_4 which will appear in a loop
Here what I am doing is saving the created revit file example Wall_1
After closing the document, there is a copy of the file created example Wall_1.0001.rvt. I delete all the additional files created and keep one final version and add it to file bytes.
The data added in byte[] filebytes is then used to create a zip file of name "RevitObjects.zip"
After which I delete all the files.
This process works perfect on my local machine, but when I execute the workitem the log created states the following:
[07/03/2019 13:47:38] Error: An unexpected error happened during phase CoreEngineExecution of job.
[07/03/2019 13:47:38] Job finished with result FailedExecution
[07/03/2019 13:47:38] Job Status:
{
"status": "failedInstructions",
No other error message is stated in the log.
Let me know if multiple revit document creation is possible in design automation api for revit
Are we not allowed to perform delete operation in the working directory.
I tried by creating a folder and performing the same operation mentioned above, but I got an access denied message.
Let me know where I have gone wrong. Also any guidance to achieve the task will be appreciated
Thank you
First of all, Yes, multiple revit file output is supported by Design Automation system, it's very easy that you just need to set the parameter zip to "true" of your output, and within your plugin, save all your output file to a folder as you named in your output parameter of "localName", please check my blog post at https://forge.autodesk.com/blog/how-generate-dynamic-number-output-design-automation-revit-v3 for all the details.
You are not allowed to access any other folders except the current working folder, you can create subfolder under current working folder and put all your files there.
Hope it helps.
If the json argument is very large, you may provide a "inputParameters.json" as an input file, instead of passing everything in the WorkItem payload

how to Save File using C# Windows Application

I'm using C# windows application .
I want to save files in my local system.
I used Open File dialog to attach the files.
Here the text inside the file is copying,I want the file itself to get copied with a new name.But what I am really looking for is , it should just save the file automatically and not show the SaveDialog Box?
How it can be done in windows application.Can anybody help me please?
The code is shown below:
private string GetFileName()
{
OpenFileDialog op1 = new OpenFileDialog();
DialogResult result = op1.ShowDialog();
if (result == DialogResult.OK) // Test result.
{
txtEn.Text = op1.FileName;
FileName = op1.FileName;
//MessageBox.Show(FileName);
File.Copy(op1.FileName, #"D:\Backup\");
}
return FileName;
}
SQL Server 2012 seems unrelated to your question. Provided that you have proper access rights to the target directory, then in order to automate the procedure (as per your question) you don't need to use the OpenFileDialog; just a single line should suffice the goal:
//Overwriting a file of the same name is not allowed
File.Copy(FileName, #"D:\Backup\" + FileName)
or
//Overwriting a file of the same name is allowed
File.Copy(FileName, #"D:\Backup\" + FileName, true)
You can also apply some additional logic pertinent to backup file naming (upon necessity).
Hope this may help. Best regards,
Are you trying to copy a file from some x location on your file system to y location (in your case D:\Backup folder) in the file system? If that is the requirement here, I see that you are using the FileName property of OpenFileDialog which gets the File path. This you are appending to D:\Backup. You should instead use the Path.GetFileName property to first extract the file name with extension and then append it to the new folder path
File.Copy(fileName, #"D:\Backup\" + Path.GetFileName(fileName));

Open a .txt file on Android

I am currently working in Unity3D and wish to simply open a .txt file upon clicking on a button.
EDIT : When I say open a .txt file, I mean open it in some editor on the device, not open it asnd save it's content to some string in my app. Kind of like opening a browser to access a website from the app.
Here's the code I currently have (C#) :
private void ShowTextFile(string fileName)
{
Application.OpenURL(Application.streamingAssetsPath + "/PATH/" + fileName);
}
But it's not working ! What am I missing ?
EDIT : I'm expecting for the .txt file to open in another window (like opening a web browser, for example), but it simply isn't doing anything. Not even getting an error.
EDIT2 : I tried using Application.persistentDataPath instead, and in both cases, it says my .txt file doesn't exist. However, when using Application.persistentDataPath, it opens up a message box asking me what I want to open the file with. Whatever I choose, it will give me an error, telling me error loading file or something like that. I've also noticed that it opens "file:///". Is it normal that there is a file:/// before the path ?
EDIT3 (I'm on fire !) : I think the problem might be related to the fact that there is a "." in my path (the com.me.myapp in the data path). Is there any way to avoid this ? Am I even looking at the right path ?
I've tried opening a txt file on Android before, using this:
TextAsset txt = (TextAsset)Resources.Load("file", typeof(TextAsset));
string content = txt.text;
Where file is the name of the txt file (don't need to write file.txt).
The variable string will contain the contents of the text file, you just need to loop through them afterwards.
This method requires:
using System.Text;
using System.IO;
Put file.txt inside a directory named "Resources" (inside Assets dir), if it isn't there then create a new one.
This is my code for Android:
var rpath = Path.Combine(Application.streamingAssetsPath, "file_name");
WWW www = new WWW(rpath);
yield return www;
StringReader streamReader = new StringReader(www.text);
text = streamReader.ReadToEnd();
For iOS:
var rpath = Path.Combine(Application.streamingAssetsPath, "file_name");
StreamReader streamReader = new StreamReader(rpath);
text = streamReader.ReadToEnd();
Note: file_name in StreamingAssets folder
Found a solution that works ! Here's the thing, the streaming assets path, on Android, returns a path that can only be read by a WWW object. So I simply read it with a WWW object then recreated the file in my persistent data path. Added a check to make sure the file doesn't already exist before creating it. Also, make sure you create the directory in case it doesn't exist, else you'll get an error. Note that this solution is probably not optimal if you have large files that are regularly accessed.
string realPath = Application.persistentDataPath + "/PATH/" + fileName;
if (!System.IO.File.Exists(realPath))
{
if (!System.IO.Directory.Exists(Application.persistentDataPath + "/PATH/"))
{
System.IO.Directory.CreateDirectory(Application.persistentDataPath + "/PATH/");
}
WWW reader = new WWW(Application.streamingAssetsPath + "/PATH/" + realPath);
while ( ! reader.isDone) {}
System.IO.File.WriteAllBytes(realPath, reader.bytes);
}
Application.OpenURL(realPath);
If anyone has anything to add to this answer, feel free !

What repository can I save to without having admin rights?

I'm facing a problem with an Internet application I'm working on right now (programming in C#).
I have to create a report and then send it via email to a certain user. After I create the report, I save it first into a temporary file, then attached it to the email giving the file path.
It's working on my computer because I have the administrator right, but it doesn't for my coworkers who don't have the admin right on their computer.
The file path I'm using is:
string filePath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.InternetCache),
fileName
);
Is there any temporary repository I can use that doesn't require admin rights?
Thanks.
Considering your ASP.NET tag, you should look at using Isolated Storage.
If you're using the built in mail classes in .Net, there's really no reason you need to write the attachment to a file at all, unless whatever is generating the report requires it.
This would work, assuming your report generator doesn't require file output and can just return bytes.
SmtpClient smtpClient = new SmtpClient(); //do whatever else you need to do here to configure this
byte[] report = GetReport();//whatever your report generator is
MailMessage m = new MailMessage();
//add your other mail fields (body, to, cc, subject etc)
using (MemoryStream stream = new MemoryStream(report))
{
m.Attachments.Add(new Attachment(stream,"reportfile.xls"));//just guessing, use the right filename for your attachment type
smtpClient.Send(m); //note that we send INSIDE this using block, because it will not actually read the stream until you send
//and you want to make sure not to dispose the stream before it reads it
}
How are you attaching it to the email? From the sounds of your question it appears that all you're doing is giving them the path to the file you create, rather than attaching it (as, once you attach it, it's embedded in the email and thus there are no paths involved).
If the web application is creating the temporary file then you can use the app_data folder (which is usually writable), and get a unique file name by using Path.GetRandomFileName().
So, something like
var myTemporaryFileName = Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data",
Path.GetRandomFileName());
Then write your file to this temporary file name, then attach it to the email
MailMessage message = new MailMessage("recipient#example.com", "", ""
"subject",
"mail body");
Attachment data = new Attachment(file, MediaTypeNames.Application.Octet);
ContentDisposition disposition = data.ContentDisposition;
disposition.FileName = "thefilenameyouwanttouseintheemail.ext";
message.Attachments.Add(data);
Now you can send it.
Don't forget to clean them up after though!

C# Creating a text file contains the error logs

I have created a text file to save the error in that created file. I have a button which, once pressed, generates an error which should be saved to the file. But if I press the button twice, it will overwrite the first error generated, because the contents of the file are overwritten. I want to generate a another separate file to save the new error. A new file should be generated for each new error.
Thanks in advance
Simple use: FileExists Method and then if it exists pick a new name. Alternatively you could just append to the file.
PSUDO:
public string checkFileName(string fileName){
if(File.Exists(fileName)){
/Pick a new one
newFileName= fileName + DateTime.Now.ToLongDateString()
return checkFileName(newFileName)
}
return fileName
}
This could be the perfect link for you How to Open and Append a log file
You can add time stamp in filename, in this case you would get new file each time.
private void SaveErrorMessage(string errorMessage)
{
string errorFile = null;
for( int x = 0; x < Int32.MaxValue; ++x )
{
errorFile = string.Format(CultureInfo.InvariantCulture, "error-{0}.txt", x);
if( !System.IO.File.Exists(errorFileTest) )
{
break;
}
}
File.WriteAllText(errorFile, errorMessage);
}
This will overwrite the last file after you've had Int32.MaxValue files, but that'll take a while.
An alternative (and probably better) approach would be to simply append to the file, rather than creating a new one.
You may also want to consider using a more robust logging solution, such as log4net.
Creating file in C# is probably what you're looking for.
So you want to generate a unique file name for each error that occurs in your program? Probably the easiest way to accomplish this is to use the date/time when the error occured to name the file. In the function where you are writing to the file you will want to name the file like this:
string filename = LogPath + DateTime.Now.ToString("yyyyMMdd.HHmmss") + ".err";
Where LogPath is the path to the folder you want to write the error files to.

Categories

Resources