EWS Item loses loaded property while executing code - c#

Im trying to load and use the properties of EWS Items. During my codes execution the object loses it's value.
Im loading messageId, attachments and subjuect.
Here's my code:
'''
FindItemsResults<Item> items = EwsHelper.GetMails(credentials); //Gets the items from the exchange service object. This method populate FindItemResults. It works.
//Find correct EmailMessage with messageId (mailInput.MessageId is a param to my code to verify that I found the correct mail.
string messageId = mailInput.MessageId;
//The Id.UniqueId can be found. The property is loaded inside of the "EwsHelper.GetMails".
foreach (Item item in items.Where(i => i.Id.UniqueId == messageId))
{
//Here im loading all the properties I need once again. I can verify that the object does have loaded property through the debugger. Everything is fine!
item.Load(new PropertySet(ItemSchema.Subject,
ItemSchema.Id, ItemSchema.Attachments));
if (item == null || !(item is EmailMessage))
throw new Exception();
dynamic fileObj = new ExpandoObject();
//Here the item.Subject (which recently was loaded) is null... Cant figure out why?!
fileObj.Filename = $"{item.Subject.RemoveInvalidFileNameChar()}.msg";
}
'''

Related

the object has been updated by another user since it was last fetched

I'm added somefield so my SharePoint solution but i keep getting the error the object has been updated by another user since it was last fetched.
foreach (var field in new PageAndFieldData().Fields)
{
var spField = web.Fields.FirstOrDefault(i => i.InternalName == field.field_name); // if dont exist = create
if (spField == null)
{
var fieldXml = field.Xml;
var newspField = web.Fields.AddFieldAsXml(fieldXml, false, AddFieldOptions.DefaultValue);
if (groups.Contains(field.group_name))
newspField.Group = field.group_name;
else
{
newspField.Group = field.group_name;
}
_Ctx.Load(newspField);
_Ctx.ExecuteQuery(); <--- This line throws the error
}
}
Can someone point out why it keeps throwing an error.
Make sure field schema (fieldXml variable in your case) does not contain Version attribute otherwise SharePoint considers the field is getting updated.
For example, the error will occur while creating a field using the following field schema:
<Field Version='1' Type='Geolocation' DisplayName='Location' />
and will not with:
<Field Type='Geolocation' DisplayName='Location' />
Probably there is a workflow associated with that list, that gets triggered and modifies the item simultaneously with your code.
If there is no workflow, then the item might be modified by other user, like it's saying. The point is, the item should not be modified (by others) in SP from the time you fetch it to the time you update it in SharePoint, otherwise SP rises "conflicting changes" error.

Updating a field item's value in a Sharepoint form via C# - value not displaying?

I'm having trouble with a field on my form displaying. It's a DateTime data type and is being used to track how many days an item has been at that stage of production. I tried converting the item.["DaysInInitation"] to an Int, to see if that would work but nothing displays still. Could anyone point me in the right direction? Here is my code:
ClientContext ctx = new ClientContext(URL);
ctx.Credentials = new SharePointOnlineCredentials(Username, password);
List list = ctx.Web.Lists.GetByTitle(ListName);
ListItemCollection items = list.GetItems(CamlQuery.CreateAllItemsQuery());
ctx.Load(items); // loading all the fields
ctx.ExecuteQuery();
foreach (var item in items)
{
// important thing is, that here you must have the right type
// i.e. item["Modified"] is DateTime
//item["fieldName"] = newValue;
if (item.Id == fo.docid)
{
item.["DaysInInitation"] = fo.ini_di;
item.Update();
}
// do whatever changes you want
item.Update(); // important, rembeber changes
}
ctx.ExecuteQuery(); // important, commit changes to the server

Sitecore access layout definition programmatically

I want to access the layout definition of an item so that I can access the renderings added to the item, and then access the datasources attached to said renderings. I can't seem to find a way to do this. The best I could do is access the __renderings field but I then found out that this is going to access the original rendering definition item rather than the specific, datasourced instance stored in the Design Layout.
This is on Sitecore 7.5 MVC
If it helps, this is what I tried doing:
// Get the default device
DeviceRecords devices = item.Database.Resources.Devices;
DeviceItem defaultDevice = devices.GetAll().Where(d => d.Name.ToLower() == "default").First();
// Get the rendering references for the default device
Sitecore.Data.Fields.LayoutField layoutField = item.Fields["__renderings"];
Sitecore.Layouts.RenderingReference[] renderings = layoutField.GetReferences(defaultDevice);
// Get the required renderings
RenderingItem headerRenderingItem = null;
RenderingItem aboutRenderingItem = null;
foreach (var rendering in renderings)
{
if (rendering.Placeholder == "headerPlaceholder")
headerRenderingItem = rendering.RenderingItem;
else if (rendering.Placeholder == "/aboutSectionPlaceholder/textPlaceholder")
aboutRenderingItem = rendering.RenderingItem;
}
Assert.IsNotNull(headerRenderingItem, "no header rendering item found");
Assert.IsNotNull(aboutRenderingItem, "no about rendering item found");
// Get their datasources
ID headerDatasourceId = ID.Parse(headerRenderingItem.DataSource); // The datasource string is null as it is accessing the datasource definition item itself
ID aboutDatasourceId = ID.Parse(aboutRenderingItem.DataSource); // Same as above
The RenderingReference.RenderingItem refers to the rendering item in the /layout section. What you could do is use RenderingReference.Settings.Datasource.
So your code would look something like:
foreach (var rendering in renderings)
{
if (rendering.Placeholder == "headerPlaceholder")
headerRenderingDatasourceId = rendering.Settings.Datasource;
else if (rendering.Placeholder == "/aboutSectionPlaceholder/textPlaceholder")
aboutRenderingDatasourceId = rendering.Settings.Datasource;
}
Item headerRenderingDatasourceItem;
if (!string.IsNullOrEmpty(headerRenderingDatasourceId)
headerRenderingDatasourceItem = item.Database.GetItem(headerRenderingDatasourceId);

Find a recipient with a given address in a folder

My company needs an add-in for automatically adding offers to the email when it is the first time we send an email to a recipient.
My question is :
How can I check if this is the first time the user sends an email to the recipients?
I tried this but I receive error that Recipient is unknown property. And I also think that this is not the right approach...
object folderItem;
Boolean AlreadyEmailed = false;
if (mail != null)
{
const string PR_SMTP_ADDRESS =
"http://schemas.microsoft.com/mapi/proptag/0x39FE001E";
Outlook.Recipients recips = mail.Recipients;
foreach (Outlook.Recipient recip in recips)
{
Outlook.PropertyAccessor pa = recip.PropertyAccessor;
string smtpAddress =
pa.GetProperty(PR_SMTP_ADDRESS).ToString();
string filter = "[Recipient] = 'John#foo.com'";
filter = filter.Replace("John#foo.com", smtpAddress);
Debug.WriteLine(filter);
folderItem = items.Restrict(filter);
if(folderItem != null)
{
Debug.WriteLine("We found items that have the filter");
AlreadyEmailed = true;
}
//Debug.WriteLine(recip.Name + " SMTP=" + smtpAddress);
}
if(!AlreadyEmailed)
{
Debug.WriteLine("This is the first time we email ... ");
}
}
The Sent property of the MailItem class returns a Boolean value that indicates if a message has been sent. In general, there are three different kinds of messages: sent, posted, and saved. Sent messages are items sent to a recipient or public folder. Posted messages are created in a public folder. Saved messages are created and saved without either sending or posting.
Also you may use the following Extended MAPI properties that deal with the message state (replied/forwarded):
PR_ICON_INDEX (http://schemas.microsoft.com/mapi/proptag/0x10800003)
PR_LAST_VERB_EXECUTED (the DASL name is http://schemas.microsoft.com/mapi/proptag/0x10810003)
PR_LAST_VERB_EXECUTION_TIME (0x10820040)
To get these values use the PropertyAccessor class (see the corresponding properties of Outlook items).
Be aware, new Outlook items don't have the EntryID property set.
You can Use To/CC/BCC properties in Items.Find/Restrict. Note that it is better to use Find in your case since you only need a single match, not all of them. Also note that Restrict will not return null if no matches are found, but rather an Items collection with Items.Count == 0.
That being said, To/CC/BCC might not include addresses, only names, so search won't help you. You can still loop through all items in the folder and explicitly check the Recipients collection of each item, but that will be hugely inefficient.
On the Extended MAPI level (C++ or Delphi), one can create subrestrictions on message recipients (or attachments), but the Outlook Object Model does not expose that functionality.
If using Redemption is an option (I am its author), its implementation of Find/Restrict does support queries on the Recipients collection:
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set YourOutlookFolder = Application.ActiveExplorer.CurrentFolder
set rFolder = Session.GetFolderFromID(YourOutlookFolder.EntryID)
set rItems = rFolder.Items
set rMsg = rItems.Find("Recipients LIKE 'John#foo.com' ")
while not (rMsg Is Nothing)
Debug.print rMsg.Subject
set rMsg = rItems.FindNext
wend
In C# (not tested):
Redemption.RDOSession Session = new Redemption.RDOSession();
Session.MAPIOBJECT = Application.Session.MAPIOBJECT;
set rFolder = Session.GetFolderFromID(YourOutlookFolder.EntryID);
Redemption.RDOMail rMsg = rFolder.Items.Find("Recipients LIKE 'John#foo.com' ") ;
AlreadyEmailed = rMsg != null;

Outlook AddIn: creating new ContactItem

I use the following code to assign some data to an appropriate ContactItem (Sender) of given MailItem. If Sender.GetContact() returns null, I'm trying to create a new ContactItem.
Outlook.MailItem myItem = (Outlook.MailItem)this.OutlookItem;
Outlook.ContactItem currentContact = myItem.Sender.GetContact();
if (currentContact != null)
{
currentContact.Body = "Example";
currentContact.Save();
}
else
{
currentContact = Globals.ThisAddIn.Application.CreateItem(Outlook.OlItemType.olContactItem) as Outlook.ContactItem;
currentContact.Email1DisplayName = myItem.SenderName;
currentContact.Email1Address = myItem.SenderEmailAddress;
currentContact.Email1AddressType = myItem.SenderEmailType;
currentContact.Body = "Example";
currentContact.Save();
}
But this does not seem to work fine for me. The next time I'm getting the contact of that MailItem (see the following code), it returns null. Again. And again.
Outlook.MailItem myItem = (Outlook.MailItem)this.OutlookItem;
Outlook.ContactItem currentContact = myItem.Sender.GetContact();
Is there something wrong? It seems like that new ContactItem is not assigned to Sender.
GetContact will return ContactItem object only if the outgoing message (does not work for incoming) had the contact explicitly added as a recipient.
GetContact will not check if you happen to have a contact item with the same email address.
If you need to find a matching contact, explicitly use MAPIFolder.Items.Find on the Contacts folder.

Categories

Resources