How to load messages faster? EWS C# - c#

I have a question about loading methods for EWS. I have a lot of messages in my outlook and I'm also using EWS and WinForms.
Right know my code is this:
while (more)
{
FindItemsResults<Item> findResults1 = allItemsFolder.FindItems("System.Message.DateReceived:01/01/2011..12/31/2022", iv);
foreach (var item in findResults1)
{
if (item.GetType() == typeof(Microsoft.Exchange.WebServices.Data.EmailMessage))
{
listik.Add(item);
}
}
more = findResults1.MoreAvailable;
if (more)
{
iv.Offset += 1000;
}
}
It took 12 minutes already for me for running my application and I decided to stop it, because something is wrong. I think I have more than 61k messages.
The idea is to show only those messages, which have my criteria, like email address. So, I should go through all the messages and folders and put suitable in one list to show them. I'm not sure how to do this better.
Anyone can help me with that?
Edit//Added more code
PropertySet psPropSet = new PropertySet(BasePropertySet.FirstClassProperties)
{
RequestedBodyType = BodyType.Text
};
Added more code:
foreach (var item in listik)
{
if (item != null)
{
if (((EmailMessage)(item))?.From?.Address != null)
{
var d = ((EmailMessage)(item)).From.Address;
if (d.Contains(comboBox2.SelectedItem.ToString()))
{
item.Load(psPropSet);
emails.Add((EmailMessage)item);
if (item.Subject != null)
{
listBox1.Items.Add(item.Subject);
}
}
}
}
}
I found a link from Microsoft:
https://learn.microsoft.com/en-us/exchange/client-developer/exchange-web-services/email-properties-and-elements-in-ews-in-exchange
It's about first-class properties and I can see here EWS element - FROM, but I can't figure out how to set it in iv.PropertySet.

I would try to remove the search and try again its pretty pointless anyway with such a broad date range, the all items folder is a search folder so your applying one search on top of the other which generally doesn't work well. Also use a property set to limit the result that is returned to just the properties you want which will also make the query run faster eg
iv.PropertySet =
new PropertySet(
BasePropertySet.IdOnly,
ItemSchema.Subject);

No email app, including Outlook, ever loads all messages in a folder. Use a virtual listview/grid and retrieve the messages (using the appropriate offset) only when displaying them to an end user.

I found the way how it's working. Thanks, everyone for your help.
iv.PropertySet = new PropertySet(EmailMessageSchema.From, ItemSchema.Subject);
while (more)
{
FindItemsResults<Item> findResults1 = allItemsFolder.FindItems(iv);
foreach (var item in findResults1)
{
if (item.GetType() == typeof(Microsoft.Exchange.WebServices.Data.EmailMessage))
{
listik.Add(item);
}
}
more = findResults1.MoreAvailable;
if (more)
{
iv.Offset += 1000;
}
}

Related

Getting a list of all users via Valence

I am trying to get a list of all users in our instance of Desire2Learn using a looping structure through the bookmarks however for some reason it continuously loops and doesn't return. When I debug it it is showing massive amounts of users (far more than we have in the system as shown by the User Management Tool. A portion of my code is here:
public async Task<List<UserData>> GetAllUsers(int pages = 0)
{
//List<UserData> users = new List<UserData>();
HashSet<UserData> users = new HashSet<UserData>();
int pageCount = 0;
bool getMorePages = true;
var response = await Get<PagedResultSet<UserData>>("/d2l/api/lp/1.4/users/");
var qParams = new Dictionary<string, string>();
do
{
qParams["bookmark"] = response.PagingInfo.Bookmark;
//users = users.Concat(response.Items).ToList<UserData>();
users.UnionWith(response.Items);
response = await Get<PagedResultSet<UserData>>("/d2l/api/lp/1.4/users/", qParams);
if (pages != 0)
{
pageCount++;
if (pageCount >= pages)
{
getMorePages = false;
}
}
}
while (response.PagingInfo.HasMoreItems && getMorePages);
return users.ToList();
}
I originally was using the List container that is commented out but just switched to the HashSet to see if I could notice if duplicates where being added.
It's fairly simple, but for whatever reason it's not working. The Get<PagedResultSet<UserData>>() method simply wraps the HTTP request logic. We set the bookmark each time and send it on.
The User Management Tool indicates there are 39,695 users in the system. After running for just a couple of minutes and breaking on the UnionWith in the loop I'm showing that my set has 211,800 users.
What am I missing?
It appears that you’ve encountered a defect in this API. The next course of action is for you to have your institution’s Approved Support Contact open an Incident through the Desire2Learn Helpdesk. Please make mention in the Incident report that Sarah-Beth Bianchi is aware of the issue, and I will work with our Support team to direct this issue appropriately.

TweetSharp C# api Search only returns first 100 tweets

I've used TweetSharp api to work with twitter.
The following code I am using to search Tweets on twitter. Problem is it does not returning more than first 100 Tweets.
public List<TwitterStatus> SearchTweetsBySearchText(int intTotalRec,string searchText)
{
List<TwitterStatus> lstTwitterStatusRet = new List<TwitterStatus>();
UpdateResetTimeForApplicationForSearch("Moderator");
TwitterApplicationModel twitterApplication = new TwitterApplicationModel();
twitterApplication = TwitterApplicationBL.GetApplicationInstanceForSearch("Moderator");
if (twitterApplication != null)
{
TwitterService service = new TwitterService(twitterApplication.ConsumerKey, twitterApplication.ConsumerSecret, twitterApplication.AccessToken, twitterApplication.AccessTokenSecret);
var twitterSearchResult = service.Search(new SearchOptions { Q = searchText, Count = intTotalRec });
if (service != null)
{
if (service.Response != null)
{
if (service.Response.RateLimitStatus.RemainingHits <= 0)
{
TwitterApplicationBL.UpdateApplicationRemainingHitsForSearch(twitterApplication.TwitterApplicationID, false, service.Response.RateLimitStatus.ResetTime);
}
}
}
if (twitterSearchResult != null)
{
lstTwitterStatusRet = ((List<TwitterStatus>)twitterSearchResult.Statuses);
foreach (TwitterStatus objTwitterStatus in lstTwitterStatusRet)
{
objTwitterStatus.CreatedDate = objTwitterStatus.CreatedDate.AddHours(-4);
}
}
}
return lstTwitterStatusRet;
}
Can any one suggest what can be done?
Twitter search only goes back 5 - 7 days, or 1,500 tweets, whichever comes first. The search API is the same. Any tweets beyond that are not available through any known method (as of now). Twitter has them, but there is no way to get them.
And in your case, one can never get more than 100 results in from a search. So, you need to issue another search using the max_id in the "next_results" section
more info on paging here
https://dev.twitter.com/docs/working-with-timelines
Happy Coding..
:)

Any use to grab a SPListItem by multiple means in an event receiver?

I am working on supporting code in a custom event receiver developed about 6 years ago... There was no source code, so we had to reflect the production assembly, and are working on cleaning it up before working.
In the code, I came across this, and I can't tell why it would be done, and I don't know enough about SharePoint to be able to know if there is a reason it has to be done this way, or if the original coder was an idiot (both are possible...)
public override void ItemAdded(SPItemEventProperties properties)
{
Trace.WriteLine("ItemAdded() invoked.");
base.DisableEventFiring();
base.ItemAdded(properties);
try
{
SPContext context = SPContext.GetContext(properties.OpenWeb());
SPUserToken userToken = context.Site.SystemAccount.UserToken;
using (SPSite site = new SPSite(context.Site.ID, userToken))
using (SPWeb web = site.OpenWeb(context.Web.ID))
{
SPListItem listItem = null;
try
{
listItem = web.GetListItem(properties.ListItem.Url);
web.AllowUnsafeUpdates = true;
}
catch
{
Trace.WriteLine("No Url properties, we must be running in CLI mode. Exiting...");
}
if (listItem != null)
{
SPList parentList = listItem.ParentList;
listItem = parentList.GetItemById(properties.ListItemId);
}
...
}
}
catch (Exception ex)
{
Trace.WriteLine(ex.ToString());
}
finally
{
base.EnableEventFiring();
}
}
It just seems like this is getting the SPListItem by multiple ways, when it is passed in in the properties object... Same for the Website.. So, I guess my question is since they end up just getting the List item by the properties anyways through the list, is there really any reason to go through all the other checks/methods to just throw the value away in the end?
The difference is that it's not getting the list item using the current user's credentials; it's grabbing it using the system account's credentials.
The system account may have permissions surrounding the list item that the current user does not.
That said, there are most certainly easier ways of getting the list items, and there's no reason to get it several times like that, even if getting it once may be appropriate.

SPListItem.Tasks always empty

I have a custom sharepoint (2007) list (named testlist) on which I attached a test workflow (built with sharepoint designer 2007 and named testwf), which only task defined in the 'Actions' section at 'Step 1' is to wait until april 2014.
When I add a new item to the testlist the testwf will start and, when I switch to the grid view, the item has the field "testwf" as running.
Now I need to access the workflow associated with the item and then "complete" this task via code by changing its status but, using the following code, I always get the item.Tasks list empty (but I can see that the internal variable m_allTaskListTasks has 1 element).
using (SPSite site = new SPSite("http://mysp"))
{
site.AllowUnsafeUpdates = true;
SPWeb web = site.OpenWeb();
web.AllowUnsafeUpdates = true;
foreach (SPList list in web.Lists)
{
if (list.Title != "testlist") continue;
foreach (SPListItem item in list.Items)
{
item.Web.AllowUnsafeUpdates = true;
if(item.Tasks.Count > 0)
//do work
}
}
}
Maybe I'm missing something...
I use this code to access my workflowtasks:
Guid taskWorkflowInstanceID = new Guid(item["WorkflowInstanceID"].ToString());
SPWorkflow workflow = item.Workflows[taskWorkflowInstanceID];
// now you can access the workflows tasks
SPTask task = workflow.Tasks[item.UniqueId];
Cross-posted question.
#petauro, have you made any headway on this? I can corroborate #moontear's answer based on the following code that I have used with success in the past:
...
// get workflow tasks for SPListItem object item
if (item != null && item.Workflows != null && item.Workflows.Count > 0)
{
try
{
var workflows = site.WorkflowManager.GetItemActiveWorkflows(item);
foreach (SPWorkflow workflow in workflows)
{
// match on some indentifiable attribute of your custom workflow
// the history list title is used below as an example
if (workflow.ParentAssociation.HistoryListTitle.Equals(Constants.WORKFLOW_HISTORY_LIST_TITLE))
{
var workflowTasks = workflow.Tasks;
if (workflowTasks != null && workflowTasks.Count > 0)
{
// do work on the tasks
}
}
}
}
catch
{
// handle error
}
}
...
While only slightly different from the code you posted in your latest comment, see if it helps.
Another minor point: are there multiple instances of lists titled "testlist" within your SPWeb? If not, why iterate over web.Lists? Just get the one list directly and avoid some superfluous CPU cycles: SPWeb.GetList()
You have to go differently about this. You need to get the workflow task list and retrieve your task from there and finish it.
First you would need to check whether a workflow is running on your item: if (item.Workflows > 0) from there you could iterate through all the workflow instances on the list item, get the SPWorkflowAssociation and the associated task and history list. From there you would only need to find the task you are looking for in the associated task list.

How can I get a list of possible transitions for a given role in a state machine workflow?

On a given state machine workflow, how do we find out the possible transitions for a given role. In my scenario, only certain roles have the permission to perform certain activities. I have to get that list. The helper class StateMachineWorkflowInstance isn't helpful here as it just returns all the possible transitions, ignoring the role of the actor.
Any help here would be appreciated.
Thanks,
Socratees.
Looks like there is no straight forward way to do this. I wrote this method based roughly on the solution at Ruurd Boeke's blog . I'm getting the list of possible events, and then looking if they can be executed by the user role. It's a work around, but still works fine.
public string[] GetTransistions(string strUser)
{
string[] strRoles = System.Web.Security.Roles.GetRolesForUser(strUser);
List<string> strActivity = new List<string>();
ReadOnlyCollection<WorkflowQueueInfo> queues = workflowInstance.GetWorkflowQueueData();
foreach (WorkflowQueueInfo info in queues)
{
if (!info.QueueName.Equals("SetStateQueue"))
{
foreach (string subscribedActivity in info.SubscribedActivityNames)
{
HandleExternalEventActivity heea = workflowInstance.GetWorkflowDefinition().GetActivityByName(subscribedActivity) as HandleExternalEventActivity;
#region check roles
if (heea.Roles != null)
{
foreach (WorkflowRole workflowRole in heea.Roles)
{
foreach (string strRole in strRoles)
{
if (workflowRole.Name.Equals(strRole))
{
strActivity.Add(heea.EventName);
//permissionLog += workflowRole.Name + " can perform " + heea.EventName + " Activity. ";
}
}
}
}
#endregion
}
}
}
return strActivity.ToArray();
}

Categories