MailItem.CreationTime is Read Only - Any Workarounds? - c#

I recently posted a question about saving an email once it's sent - I have just about everything working, except for one small detail. Basically, I am able to catch an email right before it sends, and do whatever I want with it - in my case, save it. However, if you try to access that email's CreationTime attribute, it returns January 1st 4501 at 12AM. This is most likely because it hasn't actually been 'created' yet, in that it will be created in the Sent items folder as soon as my code finishes executing and it actually sends.
I'd like to leave this MailItem, which is about to be sent, untouched. I would like to duplicate it, change the CreationTime attribute of the duplicate to DateTime.Now, then save the duplicate, then allow Outlook to continue sending the original. However, when I attempt to modify the CreationTime, I get an error that that attribute is read-only. Is there any way to 'break into' it? Or any way to force a write or something?

A better approach is attaching to the sent items Folder.ItemAdd so you can save messages after they have been sent instead of before - that way your MailItem.CreationTime should be accurate. This may or may not be an option for you but could alleviate the issue.
Outlook.Folder sentItems = ThisAddIn.Application.Session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderSentMail) as Outlook.Folder;
sentItems.Items.ItemAdd += new Outlook.ItemsEvents_ItemAddEventHandler(sentItems_ItemAdd);
// ...
void sentItems_ItemAdd(object Item)
{
var msg = Item as Outlook.MailItem;
msg.SaveAs(yourPath, Outlook.OlSaveAsType.olMSG);
}
Note: You need to handle proper COM resource disposal and error handling.

Related

Exception while saving data into a txt file

I am trying to write the data to a file, and the data is continuously updated every 100ms. So when I click save button then
System.InvalidOperationException: Collection was modified enumeration operation may not execute.
error comes up. Upon my search there is solutions to this probelm if there is Foreach loop but in my case there is no Foreach loop.
Bellow is the code I used
File.WriteAllLines(fileDialog.FileName,
RawDataFromSerialPort.Select((v, i) => $"{i + 1} Raw data is -->, {v.ToString()}"));
I'd say your serial port is still receiving data on a background thread whilst you're trying to read from the raw data collection, I'd suggest making a copy of the collection and then writing the copy out to the file.
Try using the syncroot property on the collection while doing the copy.
https://learn.microsoft.com/en-us/dotnet/api/system.array.syncroot?view=netframework-4.7.2
Check the stacktrace as well, there you'll find the drill down of the call stack where eventually a foreach-(like)loop is used.
Click on the 'view details' link, expand the $exception node and look for the StackTrace field.
The problem was that the List name I was accessing was wrong so correcting the list name RawDataFromSerialPort made my problem solved

Can't remove address book in Outlook 2010

I'm running the code below and I was under the impression that it did what it was supposed to. However, it seems that Outlook never deletes the address book folder. It just sets .ShowAsOutlookABto false. It means that when I check if the folder exists at the next start-up of Outlook, the folder is there (although I didn't realize it since it didn't show in the UI).
Outlook.MAPIFolder defaultContactsFolder =
this.Application.GetNamespace("MAPI").GetDefaultFolder(
Outlook.OlDefaultFolders.olFolderContacts);
defaultContactsFolder.Folders["My AB"].Delete();
I also tried the following code to make sure it's not something with my choice of library.
Outlook.Folder defaultContactsFolder =
this.Application.Session.GetDefaultFolder(
Outlook.OlDefaultFolders.olFolderContacts) as Outlook.Folder;
Outlook.Folders contactFolders = defaultContactsFolder.Folders;
if (contactFolders.Cast<Outlook.Folder>().Where(
element => element.Name == _CrmkAddressBookName).Count() > 0)
contactFolders["My AB"].Delete();
In each case, the Delete is executed but results in merely hiding the address book from the user interface. I want the stupid thing gone for good!
How can I really remove a folder with an address book?
I've done a mistake like that but with a different entity, although still in Outlook. The recommendation I've got was simply to ignore the issue. The Deleted directory was full of items with the same name and the user was chacked when they discovered it.
My solution, mostly to calm down the customer, was to rename the fields I knew that the end-user usually checked and add the text "Safely stored by Outlook maintnance". Then the user was happy.
As far my knowledge streches, though, the short answer to your question is "sorry, you can't".
The long answer brings us to the option of removing the account and creating a new one but it wouldn't surprise me if all the stuff then re-appeared all over again. :)

Algorithm advice Unique value and Edit

I have an empty list accepting string values.
When an element will be added I need to check if a string with the same value already exist in the list, if yes an exception should occur (ROLE 1 only unique value in the array).
Now I would like a user lets edit element in the list, if the new edited value is unique fine, otherwise an exception should occur.
My problem is: let's imagine the user select the edit element but actually does not change the value when sending to the server. The system should detect that the element has not being changed and accept the value (even if is already present in the list).
PS I simplificate the problem, I'm actually using MVC and EF & linq. My problem is that I cannot check if the value inserted has been edited or not in the interface of my application.
Could you help me out to find an effective algo to solve this problem? Thanks
Let me know if the question is enough clear or you need more information
This is my solution:
Let the client check if the text was modified. If not, tell the server there was no modification. If this is not possible have the client send both the orinigial text and the modified text, and then the server will be able to check if it was modified. (if it wasn't then there is no need to touch the data you are storing). This applies for both desktop and web enviroments.
Preferibly don't use a list, use a set (may be a hashset). The set will only allow to have each item once. In case you can't I guess you can continue using the list. If I understand correctly you are using a database, so if you could interface with the database engine directly instead of syncing the list (or set) your application will have a performance boost.
Convert the edition of the list/set into a add-remove pair (instead of setting the item). Have it check if the list/set contains the new value before doing any modification. If the new value is already present then you can throw an exception or send a message to the client (or whatever is more appropiate for your enviroment).
You may want to sync the access to your list/set, keep it simple: use a lock (Monitor). I would consider a read-write lock, but that is complicating things while you are learning. [If you interface directly with the database engine, you can let it handle that instead]. Note: there is no need for this if you will only have one single client... ever (unless that single client can send multiple concurrent requests... :P).

What the most efficient way of monitoring changes to data on an ASP.Net form?

I have an ASP.Net form and I want to send an email when the user changes their data. The email should only include data that has changed, and there are about 15 data fields total.
I don't want to use an ORM since I am updating a website that a 3rd party built for us, and all their data access calls go through a custom library of theirs.
The only ways to do this I can think of is
Make another database call to get old values and compare the form values one-by-one. If they're different, append to the email.
Store original data somewhere when it's first loaded (hidden field, session, etc), and once again compare the data one field at a time and append the differences to an email
Have someone on SO tell me there's an easier and/or simpler way that I haven't thought of
All the text boxes will have a TextChanged event, you can have them mark themselves as modified. ComboBox's will have a SelectedIndexChanged event, and so on.
Edit: All changed events can check their initial values (even on reverted changes) and either mark themselves as still modified or on a revert, as un-modified.
Here are some suggestions that may / may not be useful:
Trigger on the database table and the trigger compares the old (using the DELETED table) and updated (using the INSERTED table) and then sends an email. This may or may not be viable and I am not a big advocate of triggers.
Like you have already said you could make another database call, which would be my reccommended approach.
From what you've said I think that the only way forward is to create a duplicate dataset on the form to store the old data and run a comparison at the point where you want to produce the email.
You can use Dataset.Copy to copy structure and data.
However, now that I think about it there's always the Datset.GetChanges() method and the Dataset.AcceptChanges() along with DataSet.HasChanges()
Example code from this link:
if(dataSet.HasChanges(DataRowState.Modified |
DataRowState.Added)&& dataSet.HasErrors)
{
// Use GetChanges to extract subset.
changesDataSet = dataSet.GetChanges(
DataRowState.Modified|DataRowState.Added);
PrintValues(changesDataSet, "Subset values");
// Insert code to reconcile errors. In this case, reject changes.
foreach(DataTable changesTable in changesDataSet.Tables)
{
if (changesTable.HasErrors)
{
foreach(DataRow changesRow in changesTable.Rows)
{
//Console.WriteLine(changesRow["Item"]);
if((int)changesRow["Item",DataRowVersion.Current ]> 100)
{
changesRow.RejectChanges();
changesRow.ClearErrors();
}
}
}
}
// Add a column to the changesDataSet.
changesDataSet.Tables["Items"].Columns.Add(
new DataColumn("newColumn"));
PrintValues(changesDataSet, "Reconciled subset values");
// Merge changes back to first DataSet.
dataSet.Merge(changesDataSet, false,
System.Data.MissingSchemaAction.Add);
}
PrintValues(dataSet, "Merged Values");

Disregarding updates on non-checked-in entries in a sharepoint list (SPAudit)

Okay, this is a little hard to explain, as the title might suggest.
I have an event receiver on ItemUpdated and ItemCheckedIn, which both writes custom SPAuditEntries. When CheckedIn occurs though - it comes with two update entries as well (one for added file, and one for a simple update to the list item I suspect).
I'd love to get rid of these entries. At first I thought it would be really simple, just put an if in the itemUpdated event receiver, and stop everything
if(SPListItem.CheckedOut = false) { //... do nothing }
However I couldn't find any way to ascertain the checkout-status of the listitem.
My next thinking was, they hit almost at exactly the same time, so I could just crawl into the auditCollection, filter down to the specific listitem, user, and time (minus a second) and delete the two entries. But, sadly I found out I couldn't delete auditentries.
Anyone got any ideas?
Checked out status is determined via:
if (item.Level == SPFileLevel.Checkout) {
where item is an SPListItem
-Oisin

Categories