EWS communication error when downloading an email - c#

I am reading continuous emails from the exchange server and processing their attachments. I have seen various examples of the same but I still get error
You must load or assign this property before you can read its value
My code is as below
ItemView itemView = new ItemView(NoEmailProcess);
itemView.OrderBy.Add(ItemSchema.DateTimeReceived, SortDirection.Ascending);
FindItemsResults<Item> searchResults = service.FindItems(folder.Id, itemView);
foreach (var item in searchResults)
{
if (item is EmailMessage)
{
item.Load();
try
{
// Process my email
}
catch
{
// error
}
}
}
The thing to note is that I dont get this error every time. I get it 10% of times and never during debugging
I was wondering should I use 'Bind' before the 'Load'?
EmailMessage.Bind
Not sure what the problem could be. Could someone please help with areas I should investigate?

An exception with the message "You must load or assign this property before you can read its value" is thrown if you attempt to read a property which isn't present on Item.
The Items returned by service.FindItems contain only some properties. Though the property ItemSchema.HasAttachments is returned for an Item, the property ItemSchema.Attachments is missing. Thus you can only check if there are attachments present on an Item. But trying to read them at once will throw the shown exception.
Before you can read the property ItemSchema.Attachments you need to load it first, You can do it by ItemSchema.Bind or ItemSchema.Load. Both calls result in a GetItem request.
Since a GetItem request returns the property ItemSchema.Attachments too (see the linked MS doc above) you are safe to read it.

Related

Retrieving all items from a SharePoint list and putting each field into an object

I am trying to retrieve all of the items in a list from a SharePoint site. The fields are titled "Review Level Title", "Reviewer IDs", and "Review Level Priority". What I'm trying to do is to get the information from all three fields seperately, put them into the object I created, and then return the list with all of the objects I have created for each SharePoint item.
I have researched a lot on how to access this information from the SharePoint site, but I can not get it to work. Here is what I have created so far:
public List<OperationsReviewLevel> Get()
{
var operationsReviewLevels = new List<OperationsReviewLevel>();
ClientContext context = new ClientContext(ConfigurationManager.AppSettings["SharePointEngineeringChangeRequest"]);
var SPList = context.Web.Lists.GetByTitle("Review Levels");
CamlQuery query = new CamlQuery();
ListItemCollection entries = SPList.GetItems(query);
context.Load(entries);
context.ExecuteQuery();
foreach(ListItem currentEntry in entries)
{
operationsReviewLevels.Add(new OperationsReviewLevel(currentEntry["Review Level Title"].ToString(), currentEntry["Reviewer IDs"].ToString(), (int)currentEntry["Review Level Priority"]));
}
return operationsReviewLevels;
}
Whenever I try this code, I receive an error saying:
Microsoft.SharePoint.Client.PropertyOrFieldNotInitializedException: The property or field has not been initialized. It has not been requested or the request has not been executed. It may need to be explicitly requested.
I can not find any solutions to this error (in my scenario) online, and was wondering if anyone could see what I am doing wrong in this scenario.
Thanks everyone!
After reading the comment from Alessandra Amosso under my question, I ended up debugging entries. It took a lot of digging in the debugger, but I was able to find what the field names were being retrieved as. Debugging your ListItemCollection, if you go into Data, then any entry there, and then into FieldValues, you can see what each field value should be retrieved as.
In my case, all spaces were replaces with _x0020_ and the word priority was cut to just priorit due to length of the field name.
With this, I was able to change my foreach loop to:
foreach (ListItem currentEntry in entries)
{
operationsReviewLevels.Add(new OperationsReviewLevel(currentEntry["Review_x0020_Level_x0020_Title"].ToString(), currentEntry["Reviewer_x0020_IDs"].ToString(), Convert.ToInt32(currentEntry["Review_x0020_Level_x0020_Priorit"].ToString())));
}
And it now works properly.
Hope this helps anyone in the future!
Guess you're using SharePoint online, SharePoint online will remove the field special characters as staticname when creating fields, for example: Review Level Title will be ReviewLevelTitle.
Here is my test code.
foreach (ListItem currentEntry in entries)
{
Console.WriteLine(currentEntry["ReviewLevelTitle"].ToString()+'-'+ currentEntry["ReviewerIDs"].ToString()+'-'+ currentEntry["ReviewLevelPriority"]);
//operationsReviewLevels.Add(new OperationsReviewLevel(currentEntry["Review Level Title"].ToString(), currentEntry["Reviewer IDs"].ToString(), (int)currentEntry["Review Level Priority"]));
}
If you're not using SharePoint online,make sure the fields match also.

Outlook.MailItem custom properties issue

i have the following situation for my Add-In (Office >= 2010):
I want to add some custom properties to an Outlook.MailItem (property must be mail associated) while the mailtext is written.
If this mail is sent i want to grap the send event and get the previously set properties again, doing something and removing the properties and continue sending.
Problem if i use PropertyAccessor:
I use it as follows to save the property while writing the mail:
string propTag = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/test_property"
mailItem.PropertyAccessor.SetProperty(propTag, value);
And to read the property again on sending the mail:
string propTag = "http://schemas.microsoft.com/mapi/string/{00020329-0000-0000-C000-000000000046}/test_property"
string readProperty = mailItem.PropertyAccessor.GetProperty(propTag);
works if cached mode is enabled on exchange
works NOT if cached mode isn't enabled... i can't find the previously setted properties anymore (Exception with unknown property is thrown)
OutlookSpy (http://www.dimastr.com/outspy/home.htm) can find the property on sending so does anyone knows how to read the properties in a different way?
I would thank you very much for every help.
You need to call Save if you want your changes to be persisted.

Message read by OnEntryWritten are coming with parameters not set

I'm using the OnEntryWritten event in order to get events from the event log when they are fired.
The problem I started to see today is that some messages come with parameters unset.
For example:
The Windows Filtering Platform has permitted a bind to a local port. Application Information: Process ID:9852 Application Name:\device\harddiskvolume7\program files (x86)\google\chrome\application\chrome.exe Network Information: Source Address::: Source Port:51714 Protocol:17 Filter Information: Filter Run-Time ID:0 Layer Name:%%14608 Layer Run-Time ID:38
You can see the %%14608 parameter. This comes with a value if I see the same log in the Event Viewer.
I'm running a windows service as LocalSystem, so I don't know if this is a permission issue or this technology is not useful at all.
I have tried the rest offered on C# and they also don't meet my requirements.
UPDATE: this is the code I'm using to read the events.
1) First I subscribe to the corresponding Event log:
private void Subscribe()
{
_eventLog.EnableRaisingEvents = true;
var callbackFunction = new EntryWrittenEventHandler(OnEntryWritten);
_eventLog.EntryWritten += callbackFunction;
// Save a reference for callbackFunction
_eventHandler = callbackFunction;
}
2) Then on the callback method, I read data from the message:
public void OnEntryWritten(Object source, EntryWrittenEventArgs entryArgs)
{
// When overwrite policy is enabled, this will trigger for all elements when it starts writing new ones
try
{
var entry = entryArgs.Entry;
var timeWritten = entry.TimeWritten;
// This comes with %% values depending on the log
string message = entry.Message;
}
catch(Exception ex)
{
...
}
}
3) The event log variable is simply initialized as:
var eventLog = EventLog.GetEventLogs().FirstOrDefault(el => el.Log.Equals(logName, StringComparison.OrdinalIgnoreCase));
I need some help on this, honestly I don't know what else to try.
UPDATE
I'm adding some images here so everybody can understand the situation a little bit better. To be honest, it looks like there's no solution but to implement a dictionary and replace manually the required values, which appear to be always constants.
This is what I see on the Event Viewer for a given Event ID:
This is what I see on my program when I read that entry:
You can clearly see that the following values:
"Machine key." (Key type)
"Read persisted key from file." (Operation)
Are coming unmapped in the ReplacementStrings and the Message properties as: %%2499 and %%2458
This is the message value I get on the program:
"Key file operation.\r\n\r\nSubject:\r\n\tSecurity ID:\t\tS-1-5-18\r\n\tAccount Name:\t\tMyAccount$\r\n\tAccount Domain:\t\tWORKGROUP\r\n\tLogon ID:\t\t0x3e7\r\n\r\nProcess Information:\r\n\tProcess ID:\t\t6644\r\n\tProcess Creation Time:\t2019-04-03T12:17:24.587994400Z\r\n\r\nCryptographic Parameters:\r\n\tProvider Name:\tMicrosoft Software Key Storage Provider\r\n\tAlgorithm Name:\tUNKNOWN\r\n\tKey Name:\t816339d2-c476-4f1e-bc40-954f0aa0f851\r\n\tKey Type:\t%%2499\r\n\r\nKey File Operation Information:\r\n\tFile Path:\tC:\ProgramData\Microsoft\Crypto\Keys\6d55a45fd69327293e9ed3e7930f4565_5663a8bb-2d1d-4c0d-90c1-624beddabe9c\r\n\tOperation:\t%%2458\r\n\tReturn Code:\t0x0"
What can be done here? There also nothing in entry.Data that might help me out to obtain both values.
No, I believe you're mistaken, sorry that this answer is too late. I found a similar event that was raised by chrome and evaluated if there's anything missed by the event handler. There wasn't anything missed. The message I got in my console output exactly matched what I saw in my Event Viewer.
A better solution would be to
Use entry.Data to get the complete data instead of entry.Message
entry.Data will return a byte[] which you can convert to a string. Here's the link to all properties that an entry will have.

How to get the SMTP Adress of the sender outlook / Exchange

I am trying to get the SMTP Adress of the sender in an outlook plugin.
This worked as expected when I follow the examples from MSDN
like this one here:
private void GetSMTPAddressForRecipients(Outlook.MailItem mail)
{
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();
Debug.WriteLine(recip.Name + " SMTP=" + smtpAddress);
}
}
But since some time (some weeks) the reference schema at
http://schemas.microsoft.com/mapi/proptag/0x39FE001E
can not be resolved anymore.
Errormessage:
System.Runtime.InteropServices.COMException: http://schemas.microsoft.com/mapi/proptag/0x39FE001E Property unknown or ca not be found.
If I try the URL in a browser I get:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
All examples I can find (for office 2013 and above) are pointing to ressources at http://schemas.microsoft.com/mapi/proptag/SOMETHING
I also could not find any info in forums or oon MSDN that this moved or changed ..
Is anyone else running into this ?
Is ther a known solution or workaroud.
http://schemas.microsoft.com/mapi/proptag/0x39FE001E is not a link, it the actual DASL property name that the PropertyAccessor object expects. The format is different for the fixed and named MAPI properties (e.g. http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/85100003).
You can look at the MAPI properties and their DASL names in OutlookSpy (I am its author - click IMessage button).
Also keep in mind that you should not expect any particular MAPI property to be present - they are not guaranteed to be present and you must expect and handle errors returned by the PropertyAccessor object.
In your particular case, you can are not checking the SMTP address of a sender, you are working wit the message recipients. For the recipients, check if the PR_SMTP_ADDRESS property is there. If not, open the adders entry (Recipient.AddressEntry) and check for that property from the AddressEntry. You can also check for the presence of the PR_EMS_AB_PROXY_ADDRESSES multivalued property (an array is returned). You can so try AddressEntry.GetExchangeUser().PrimarySmtpAddress (be prepared to handle errors and nulls).
Once again, take a look at the message with OutlookSpy to see which property is present.

My SharePoint feature receiver activates a list definition feature, but my code cannot see the list template until the "second pass"

I am into my sixth hour battling with what hopefully should have a simple solution, so I thought I would post here.
I have an feature with a feature receiver whose sole purpose is to activate a deployed list definition feature and then create an instance of that new list definition.
The list definition feature, called "Custom Access List", is scoped at web.
So my feature receiver activates this list definition feature, having GUID "1E503BDA-803B-4a1a-A042-019FA1A70C4C":
...
string featureGuid = "1E503BDA-803B-4a1a-A042-019FA1A70C4C"; // my 'Custom try
{
SPFeatureCollection featureCollection = web.Features;
featureCollection.Add(new Guid(featureGUID), true); // activat the 'Custom Access List' feature
}
catch (Exception e)
{
// log exception
}
This code executes fine, and the list definition feature is activated, and the new list definition appears in the "Create" site menu option in the UI.
However, this is where my issue starts. The next line of my feature receiver code then tries to create an instance of this newly-available list:
SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; // exception! Value does not fall within the expected range
web.Lists.Add("My new custom access list","", listTemplate);
But the line SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; throws an exception with "Value does not fall within the expected range." - the list template, despite being deployed, visible and available in the UI under the "Create" site menu action, cannot be found in the receiver code.
Debugging the code confirms that the web.ListTemplates SPListTemplateCollection does not contain a entry for this new "Custom Access List", despite the UI suggesting otherwise.
And here is the weird thing. An exception is thrown, but if I then re-run the code i.e. reactivate the feature in the UI, to re-execute that feature receiver, the list template is then found -
SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; // found this time. It sees it the second time around
web.Lists.Add("My new custom access list","", listTemplate); // works fine
So, in a nutshell - initially, after activating a feature which, through receiver code, activates a list definition feature, that list definition is not visible until after a "postback" or some form of "SPWeb refresh". Then it is visible.
Am I missing something here? A call of web.Update() here:
try
{
SPFeatureCollection featureCollection = web.Features;
featureCollection.Add(new Guid(featureGUID), true); // true to force activation
web.Update();
}
...
does nothing. Is there some way I can "refresh" the SPWeb object so that the new list template can be seen and used?
The workaround I have found, for now, is to add the "Custom Access List" list template feature as an activation dependency in the "parent" feature receiver itself, and to make the "Custom Access List" list template feature hidden. That way, to my knowledge, the custom list definition feature is forcibly activated and I find that web.ListTemplates["Custom Access List"]; is found.
But I would much rather the former approach work - to activate, in my receiver code, the list definition feature and then to find it so that an instance of the list can then be created.
Andrew,
The problem is to do with internal async events and the timing of the activity. As you say if you go away and come back it works - i.e. the async event has completed. You are treating the featureCollection.Add as a synchronus method.
What you really should be doing if you need a template and a list instance created at the same time is using the XML framework for this.
Add a to your feature that has the list template, or alternatively add a new feature for the list instance and reference the FeatureID of the list template.
Andrew
You need to call EnsureListsData on the SPListCollection that you just updated.
http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistcollection.ensurelistsdata.aspx
Seems that the list template is not yet created. You can try to do a loop and wait to be created
using(SPWeb web = site.OpenWeb())
{
SPListTemplate listTemplate = null;
while (listTemplate == null)
{
Thread.Sleep(1000);
try
{
listTemplate = web.ListTemplates["Custom Access List"];
if (listTemplate != null)
{
// here your code
web.Lists.Add("My new custom access list", "", listTemplate);
}
}
catch
{
web = site.OpenWeb();
}
}
}

Categories

Resources