IronCow Task Deletion Permissions Problem - c#

I'm using the IronCow managed API for RememberTheMilk (http://ironcow.codeplex.com/) and I'm trying to remove tasks using my program. I've already logged in and downloaded the tasks list, but when I later try to remove one I get the following exception:
[IronCow.RtmException] = {"User not logged in / Insufficient permissions"}
I'm removing tasks using this code (rtm is my logged in RTM object, myTask is the Task object I'm looking to delete)
TaskListCollection tlc = rtm.TaskLists;
foreach (TaskList list in tlc)
{
TaskListTaskCollection taskListsTasks = list.Tasks;
foreach (Task task in taskListTasks)
{
if (!(task.IsDeleted || task.IsCompleted) && task.Name == myTask.Name)
{
list.Tasks.Remove(task);
}
}
}
the line it errors on is list.Tasks.Remove

Discovered it was a permissions problem due to permissions being stored from an old version of the app that didn't need to delete

Related

Outlook VSTO plugin stops executing while iterating over contacts in default contacts folder

I wrote an Outlook plugin in which a method searches for a contact's phone number by searching the default contact folder for contacts with a specified email address.
The for loop in the sample below simply seems to stop running for some of my outlook users.
The "processing contact" message is the last message logged, and the "Iteration completed" message never appears.
Also, seemingly no exceptions occur (I can't test this on a development box right now and I'm depending on my logged debug messages), the method simply seems to stop in the midst of the for loop and the method calling the method below does not continue executing.
var phoneNumbers = new List<PhoneNumberModel>();
var mailAddress = "findme#incontacts.com";
var contacts = Application.ActiveExplorer().Session.GetDefaultFolder(OlDefaultFolders.olFolderContacts);
if(contacts != null)
{
logger.Debug($"Iterating contact items...");
foreach (ContactItem foundContact in contacts.Items)
{
logger.Debug("Processing contact: {contact.CompanyAndFullName}");
if ((foundContact.Email1Address?.ToLower() ?? "").Contains(mailAddress.ToLower()))
{
if (!string.IsNullOrWhiteSpace(foundContact.BusinessTelephoneNumber))
{
phoneNumbers.Add(new PhoneNumberModel { NumberType = "Business phone number", PhoneNumber = foundContact.BusinessTelephoneNumber });
}
}
logger.Debug($"AddPhoneNumbersFromDefaultAddressBook() Iteration completed");
}
}
I suspected an API timeout of some sort, so I wrapped the call to the above method in a timeout handler:
int timeout = 1000;
var task = SomeOperationAsync();
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
// task completed within timeout
} else {
// timeout-logic
}
// further-logic
The timeout-logic and further-logic does not execute.
Any ideas what could be going on here?
Your code assumes you can only have ContactItem objects in the Contacts folder. It will fail if you have a DistItem object.
Also keep in mind that you cannot access Outlook Object Model on a secondary thread (such as that used by the Task object). Only Extended MAPI objects can be accessed from secondary threads, but that requires Extended MAPI. If using Redemption (I am its author) is an option, is RDO family of objects wraps Extended MAPI and can be accessed from secondary threads.
Thirdly, never loop through all items in a a folder, let Items.Find/FindNext or Items.Restrict do the heavy lifting. In you particular case, that query must probably be something like [Email1Address] = 'user#site.demo'

EntityFramework and handling duplicate primary key/concurrency/race conditions situations

I wrote a library, referenced by numerous applications, that tracks who is online and which application and page they are viewing.
The data is stored, using EF6, in a Sql Server 2008 table which tracks their username (primary key), application, page and timestamp. I only want to store the latest request for each person so each username should only be stored once.
The library code, which is called from the Global.asax of each application looks like this:
public static void Add(ApplicationType application, string username, string pageRequested)
{
using (var db = new CommonDAL()) // EF context
{
var exists = db.ActiveUsers.Find(username);
if (exists != null)
db.ActiveUsers.Remove(exists);
var activeUser = new ActiveUser() { ApplicationID = application.Value(), Username = username, PageRequested = pageRequested, TimeRequested = DateTime.Now };
db.ActiveUsers.Add(activeUser);
db.SaveChanges();
}
}
I'm intermittently getting the error Violation of PRIMARY KEY constraint 'PK_tblActiveUser_Username'. Cannot insert duplicate key in object 'dbo.tblActiveUser'. The duplicate key value is (xxxxxxxx)
What I can only guess is happening is Request A comes in, removes the existing username. Request B (from same user) then comes in, tries to remove the username, sees nothing exists. Request A then adds the username. Request B then tries to add the username. The error frequently seems to be triggered when a web server sends a client a 401 status, which again points to multiple requests within a short period of time triggering this.
I'm having trouble mocking this race condition using unit tests as I haven't done much async programming before, but tried to create async tests with delays to mock multiple simultaneous slow requests. I've tried to use using (var transaction = new TransactionScope()) and using (var transaction = db.Database.BeginTransaction(System.Data.IsolationLevel.ReadCommitted)) to lock the requests so request A can complete before request B begins but can't verify either one fixes the issue as I can't mock the situation reliably.
1) Which is the right way to prevent the exception (Most recent request is the one that ultimately is stored)?
2) Which is the right way to to write a unit test to prove this is working?
Since you only want to store the latest item, you could use a last update wins and avoid the race condition on who can insert first, the database handles the locks and the last to call update (which is the most recent) is what is in the table.
Something like the following should handle any primary key errors if you run into concurrency issues on the edge case that a brand new user has 2 requests at the same time and avoid an "infinite" loop of errors (well until a stack overflow exception any way).
public static void Add(ApplicationType application,
string username,
string pageRequested,
int recursionCount = 0)
{
using (var db = new CommonDAL()) // EF context
{
var exists = db.ActiveUsers.Find(username);
if (exists != null)
{
exists.propa = "someVal";
}
else
{
var activeUser = new ActiveUser
{
ApplicationID = application.Value(),
Username = username,
PageRequested = pageRequested,
TimeRequested = DateTime.Now
};
db.ActiveUsers.Add(activeUser);
}
try
{
db.SaveChanges();
}
catch(<Primary Key Violation>)
{
if(recursionCount < x)
{
Add(application, username, pageRequested, recursionCount++)
}
else
{
throw;
}
}
}
}
As for unit testing this, it will be very hard unless you insert an artificial delay or can force both threads to run at the same time. Sometimes the timing on the race conditions is in the millisecond range depending on the issue. Tasks may not work because they are not guaranteed to run at the same time, you throw them to the background thread pool and they run when they can. Old school threads may work but I don't know how to force it since the time between read and remove & create are most likely in the 5 ms range or less.

How to get the collection of running packages from SSIS server?

I try to wait until all running packages are finished on SQL Server after I started an SSIS package, but I cannot figure out the correct way to do it. The code I have so far is:
var runningPackagesBefore = catalog.Executions.ToList();
// [..] logic to start the package
while (true)
{
// get all packages that are new
catalog.Executions.Refresh();
var newOperations = catalog.Executions.Except(runningPackagesBefore);
// get all packages that are new, running and are in the same folder and project as the package
var runningOperations =
newOperations.Where(
operation => operation.FolderName == catalogFolder.Name
&& operation.ProjectName == project.Name
&& operation.Status == Operation.ServerOperationStatus.Running);
if (!runningOperations.Any())
{
break;
}
// [..] sleep and timeout logic here
}
The catalog.Executions.Refresh() call causes deadlock problems sometimes. The documentation also says "Do not reference this method directly...".
A refresh is needed because otherwise the executions collection is cached and returns 0 new transactions. And when it runs without deadlocks it returns the amount of running packages correctly.
So I am trying to find a way to see if all packages are finished running. The package I am running is a "master" package that starts multiple other packages. Otherwise I could simply get the Execution ID and get the operation state from the catalog, but that is not possible in this case.
Solved it by recalling the integrationservice and getting a new catalog. This refreshes it automatically:
// get all executions for this project that are currently running
var runningPackagesBefore = catalog.Executions.Select(operation => operation.Id).ToList();
// [..] logic to execute the package
while (true)
{
var integrationServices = new IntegrationServices(sqlConnection);
Catalog refreshedCatalog = integrationServices.Catalogs[catalogName];
// get all packages that are running
var runningOperations = refreshedCatalog.Executions.Where(
operation => operation.Status == Operation.ServerOperationStatus.Running);
// get all packages that are new
var newRunningOperations = runningOperations.Where(
operation => !runningPackagesBefore.Contains(operation.Id));
if (!newRunningOperations.Any())
{
break;
}
// [..] sleep and timeout logic here
}

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.

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.

Categories