Sharepoint Sequential Workflow not adding Task into Tasklist - c#

After the deployment of the workflow onto the sharepoint site, I am able to start the workflow by creating new rows of a list. These are also reflected in the field, "no. of workflow in progress". However, I cannot seem to find the tasks created for specific users in the Task list.
As a beginner with Sharepoint development, I am not exactly sure what is wrong. Please kindly advise.

this is my tested code:
private void OnCreateTask_MethodInvoking(object sender, EventArgs e)
{
taskId1 = Guid.NewGuid();
// SPContentTypeId myContentTypeId=new SPContentTypeId("0x01080100e73fd5f172cb40d8a5dca97fad7a58b8");
SPContentType myContentType = SPContext.Current.Web.ContentTypes["Powerfull Approval Workflow Task"];
CreateTaskApproval_ContentTypeID = myContentType.Id.ToString();
#region Enable ContentTypes
if (this.workflowProperties.TaskList.ContentTypesEnabled != true)
{
workflowProperties.TaskList.ContentTypesEnabled = true;
}
bool contenTypeExists = false;
foreach (SPContentType contentType in workflowProperties.TaskList.ContentTypes)
{
if (contentType.Name == myContentType.Name)
{
contenTypeExists = true;
break;
}
}
if (contenTypeExists != true)
{
workflowProperties.TaskList.ContentTypes.Add(myContentType);
}
myContentType.EditFormUrl = "_layouts/SequentialWorkflow/TaskEdit/TaskEditForm.aspx";
myContentType.DisplayFormUrl = "_layouts/SequentialWorkflow/TaskEdit/TaskEditForm.aspx";
myContentType.Update();
#endregion
taskProperties.PercentComplete = (float)0.0;
taskProperties.AssignedTo = myInstantiationData.User;
taskProperties.DueDate = myInstantiationData.DueDate;
taskProperties.Description = myInstantiationData.Request;
taskProperties.StartDate = DateTime.Now;
taskProperties.Title = "Please approve " + this.workflowProperties.Item.DisplayName;
}

Related

c# outlook addin userproperty of first item in collection not found

Outlook 2016
.Net Framework 4.5
i encounter a really strange behaviour:
when i iterate through the items collection of a contact folder in some very special undefined cases (which i do not really understand) some userproperties of the first item of the collection fail to load. However the UserProperties are definitly set.
The approach is following:
I open the contact folder (to which the items will be moved) in outlook.
then i execute the "test"
the execution of the test can be suammrized as following:
click button ->
start thread
iterate through the items (on first iteration no items are present).
add new items{
create item
set userproperty PRE before item is initially saved
save item
move item to desired folder
set userproperty POST after item is moved
save item
}
end thread
click button ->
start thread
iterate through the items (here the userproperty POST sometimes fails to load on the first item of the collection, however when i investigate it, it IS there. It only fails for the first item and succeeds for every other following item).
...END
it seems to me that outlook somehow fails to update the userproperty definitions timely. But note that the first BackgroundWorker thread is already finished when iterating through the items with the second backgroundworker thread.
The problem could be related to the fact that iam viewing the folder in the explorer while the items are added and iterated.
This bug is hard to reproduce and does only occur rarely.
however i'm really missing insight into the inner workings of outlook so i can only speculate.
Idea for workarounds:
I could add an item with all userproperties before moving it. the problem here is that i need to add new userproperties, after the item is initially saved and moved to the folder, in some scenarios.
in few cases the userproperty key is dynamically created (with a pattern) so it wouldn't be optimal to predefine all userproperties.
It's very important that the userProperties are reliably loaded because some important features are based upon them.
Does anybody has a clue how the problem is caused and how to solve it? because this behaviour is driving me crazy.
some Code (not the original but it should contain all the relevant aspects)
//Ribbon
TestNS.TestCaller testCaller;
string folderID = "00000000BDB409934ED327439481EB6E1E1CC4D3010055B62301B58E32478DCD8C0D3FA6304600002C4CA4400000";
public void testButton0_Action(Office.IRibbonControl control)
{
if(testCaller == null){
testCaller = new TestNS.TestCaller(ThisAddIn.Outlook,folderID);
}
testCaller.Run();
}
//Ribbon end
using System.Runtime.InteropServices;
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Diagnostics;
using System.Windows.Forms;
using System.ComponentModel;
namespace TestNS
{
public class TestCaller{
private Outlook.Application application;
private BackgroundWorker worker = new BackgroundWorker();
private Test test = null;
private string folderId;
private bool init = true;
private bool busy = false;
public TestCaller(Outlook.Application application, string folderId){
this.application = application;
this.folderId = folderId;
worker.DoWork += new DoWorkEventHandler(DoWork);
worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(OnCompleted);
}
public void Run()
{
if (!busy)
{
busy = true;
test = new Test(application, folderId, init);
worker.RunWorkerAsync();
}
}
private void DoWork(object sender, DoWorkEventArgs e)
{
test.Process();
test = null;
}
private void OnCompleted(object sender, RunWorkerCompletedEventArgs e)
{
busy = false;
init = false;
}
}
class Test
{
public const string key_preCreateProperty ="preCreate";
public const string key_postCreateProperty = "postCreate";
private Outlook.Application application;
private string folderId;
private bool createData;
public Test(Outlook.Application application,string folderId,bool createData)
{
this.application = application;
this.folderId = folderId;
this.createData = createData;
}
public void Process(){
Examine();
if(createData){
CreateData();
}
}
public void CreateData()
{
List<Poco> pocos = new List<Poco>();
for (int i = 0; i < 10; i++)
{
pocos.Add(
new Poco
{
Pre = "Pre" + i,
Post = "Post" + i
}
);
}
CreateContactItems(folderId,pocos);
}
public void Examine()
{
bool preIsLoaded = false;
bool postIsLoaded = false;
Debug.WriteLine(">>>Examine");
Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
Outlook.Items folderItems = folder.Items;
int i = 0;
//print UserProperties registered to the items
foreach(Outlook.ContactItem contactItem in folderItems){
var itemUserProperties = contactItem.UserProperties;
string itemUserPropertiesString = "";
foreach (var itemProp in itemUserProperties)
{
Outlook.UserProperty prop = (Outlook.UserProperty)itemProp;
itemUserPropertiesString += " " +prop.Name + " " + prop.Value + " \n";
}
//HERE: sometimes it prints only Pre on the first index of the iteration
Debug.WriteLine(string.Format("i={0} , itemUserProperties Count={1} , following UserProperties: \n{2}", i++, itemUserProperties.Count, itemUserPropertiesString));
string pre = null;
string post = null;
try
{
pre = contactItem.GetUserProperty(key_preCreateProperty);
preIsLoaded = true;
}
catch(KeyNotFoundException ex){
Debug.WriteLine("Error: Pre Not found"); //should not happen - doesn't happen
}
try
{
post = contactItem.GetUserProperty(key_postCreateProperty);
postIsLoaded = true;
}
catch (KeyNotFoundException ex)
{
Debug.WriteLine("Error: Post Not found"); //shoul not happen - happens rarely totally indeterminitic
}
Marshal.ReleaseComObject(itemUserProperties);
}
Debug.WriteLine("<<<Examine");
if (folderItems.Count > 0 && (!preIsLoaded || !postIsLoaded))
{
MessageBox.Show("preIsLoaded="+preIsLoaded +" \n" +"postIsLoaded="+postIsLoaded);
}
Marshal.ReleaseComObject(folderItems);
Marshal.ReleaseComObject(folder);
}
public void CreateContactItems(string folderId,List<Poco> pocos)
{
Outlook.MAPIFolder folder = application.Session.GetFolderFromID(folderId);
foreach(Poco poco in pocos){
CreateContactItem(folder,poco);
}
Marshal.ReleaseComObject(folder);
}
public void CreateContactItem(Outlook.MAPIFolder testFolder,Poco data)
{
Outlook.ContactItem contactItem = application.CreateItem(Outlook.OlItemType.olContactItem);
contactItem.SetUserProperty(key_preCreateProperty, data.Pre);
contactItem.Save();
Outlook.ContactItem movedContactItem = (Outlook.ContactItem)contactItem.Move(testFolder);
Marshal.ReleaseComObject(contactItem);
contactItem = movedContactItem;
contactItem.FirstName = data.Pre;
contactItem.LastName = data.Post;
contactItem.SetUserProperty(key_postCreateProperty, data.Post);
contactItem.Save();
Marshal.ReleaseComObject(contactItem);
}
}
public static class Util
{
public static void SetUserProperty(this Outlook.ContactItem item, string name, dynamic value)
{
Outlook.UserProperty property = item.UserProperties[name];
if (property == null)
{
property = item.UserProperties.Add(name, Outlook.OlUserPropertyType.olText);
}
property.Value = value;
}
public static dynamic GetUserProperty(this Outlook.ContactItem item, string name)
{
Outlook.UserProperty property = item.UserProperties[name];
if (property != null)
{
return property.Value;
}
throw new KeyNotFoundException(string.Format("UserProperty name={0} not found", name));
}
}
public class Poco
{
public string Pre
{
get;
set;
}
public string Post
{
get;
set;
}
}
}
Thank you for any replies
Outlook Object Model cannot be used on a secondary thread within a COM addin. Outlook 2016 will raise an exception as soon as it detects an OOM object being accessed on a secondary thread.

Selenium Webdriver: How to confirm element no longer displayed on page

I have a table containing details about jobs.
Currently I can use the following code to find the specified job and select delete.
[TestMethod]
public void DeleteJob()
{
JobsPage.GoTo();
JobsPage.Delete("TestJobTitle");
Assert.IsTrue(DeleteJobPage.IsAt, "Delete job page not displayed");
}
Below Method to find the specified job and click delete
public static void Delete(string delete)
{
var test = Driver.Instance.FindElement((By.XPath("//table/tbody/tr[td[2] = '" + delete + "']/td[9]/a[3]")));
test.Click();
}
I am now attempting to find a way to confirm the Job is no longer displayed on the JobsPage.
Assert.IsTrue(JobsPage._View("TestJobTitle"), "Job is still present");
The above Assert in the TestMethod is not working
I attempted the below method but need help to get working.
public static bool _View(string view)
{
IList<IWebElement> messages = Driver.Instance.FindElements(By.XPath("//table/tbody/tr[td[2] = '" + view + "']")).ToList();
foreach (IWebElement message in messages)
{
if (message.Text == view)
{
return true; // Job is still present
}
}
return false; // Job is not present
}
Don't know whether this helps or not. I have same scenario and I do search in a table for a user still exists or not.
public static bool ValidateSearchResult(string s)
{
bool val = false;
try
{
new WebDriverWait(Drivers._driverInstance, new TimeSpan(0, 0, 10)).Until(ExpectedConditions.ElementExists(By.TagName("tbody")));
IList<IWebElement> StatusColumnData = Drivers._driverInstance.FindElements(By.XPath("//table/tbody/tr/td[2]"));
foreach (IWebElement element in StatusColumnData)
{
if (element.Text.Contains(s))
{
val = true;
break;
}
else
val = false;
return val;
}
}
catch(Exception e)
{
throw (e);
}
}

Unresponsive UI while using Async & Await

I am trying to use async and await in my coding while I transfer big amounts of data from my WCF service to my WPF client application. Now it does take about 2-3 minutes to load the data, but now I struggle with my UI that's unresponsive for that total time. It's not very user-friendly. Is there a way to get my my UI responsive while the data loads with the coding that I currently have?
public pgSysproStock()
{
InitializeComponent();
SysproStock.WindowState = WindowState.Normal;
this.UpdateStockAsync();
}
private async void UpdateStockAsync()
{
dgSysproStock.IsEnabled = false;
using (TruckServiceClient TSC = new TruckServiceClient())
{
var allStock = await TSC.GetSysproStockAsync();
dgSysproStock.ItemsSource = allStock.Select(item =>
new AllStock
{
Id = item.Id,
StockCode = item.StockCode,
Description = item.Description,
ConvFactAltUom = item.ConvFactAltUom,
ConvMulDiv = item.ConvMulDiv,
ConvFactOthUom = item.ConvFactOthUom,
MulDiv = item.MulDiv,
Mass = item.Mass,
Updated_Supplier = item.Updated_Supplier,
CycleCount = item.CycleCount,
ProductClass = item.ProductClass.ToString(),
UnitCost = item.UnitCost,
Discount = item.Discount,
Warehouse = item.Warehouse,
MinimumStock = item.MinimumStock,
MaximumStock = item.MaximumStock,
StockForNow = item.StockForNow,
CoilWidth = item.CoilWidth,
SheetCoilLength = item.SheetCoilLength,
MaterialThickness = item.MaterialThickness
}).ToArray();
dgSysproStock.IsEnabled = true;
}
}
Thank you for any advice! :D
It seems that your operation is initiating operation incorrectly.
I suggest you create handler On Load or some other event for your window, mark it async and do the call from there. Should be simple as this:
private async void Form1_Load(object sender, EventArgs e)
{
dgSysproStock.IsEnabled = false;
using (TruckServiceClient TSC = new TruckServiceClient())
{
var allStock = await TSC.GetSysproStockAsync();
dgSysproStock.ItemsSource = allStock.Select(item =>
new AllStock
{
...
}).ToArray();
dgSysproStock.IsEnabled = true;
}
}
Note that I'm using Form.Load event but you may use different.

Nested Asynchronous function in Silverlight

I am trying to call a nested Asynchronous function but I am not getting the required data.
Since I am using a wcf service with Silverlight I can only use Asynchronous functions.
In my code I am saving a set of rows containing userdata. Before I save it I need to check the username is unique. Now I only need to find out the first one and then break out of loop and show a message to the user.for simplicity sake, I have stripped the function of all the extra data and this is how it looks
private void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.CheckIsUserNameUnique += (s, e) =>
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
_UpdatedUsers = new ObservableCollection<User>();
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
};
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}
In this case I am trying to find if the username is unique,show user a message and return.
Obviously it's not as simple as that.I have tried a couple more different ways but it didn't work. How do I get this working?
I think you can make your life easier by adding a couple of helper functions. The first one is an asynchronous function that checks whether a user is unique. You may need to add some code to set tcs.SetException if there is an error.
private Task<bool> IsUserUniqueAsync(UserViewModel user, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
dataService.CheckIsUserNameUnique += (s, e) =>
{
tcs.SetResult(e.IsUnique);
};
dataService.IsUserNameUnique(user.UserName, user.UserID, Database.CurrentClient.ClientID);
return tcs.Task;
}
The second one updates all the users asynchrnously
public Task<bool> UpdateUsersAsync(ObservableCollection<User> updatedUsers, DatabaseServiceLocal dataService)
{
var tcs = new TaskCompletionSource<bool>();
BusyIndicator = true;
BusyMessage = "Saving...";
dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
tcs.SetResult(e.Success);
};
dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, updatedUsers, _DeletedProjectUsers);
return tcs.Task;
}
Then your SaveUsers method becomes a bit simpler.
private async void SaveUsers(bool CloseForm)
{
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
Dictionary<Task<bool>, User> tasks = new Dictionary<Task<bool>, User>();
// start all tasks in parallel
foreach (UserViewModel _User in _AllUsers)
{
if (_User.Dirty && !_User.IsBlank)
{
tasks.Add(IsUserUniqueAsync(_User, _dataService), _User);
}
}
// process each task as it completes
while(tasks.Count() > 0 )
{
var task = await Task.WhenAny(tasks.Keys.ToArray());
if(task.Result)
{
_UpdatedUsers.Add(_User.SaveAsUser());
}
else
{
MessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
return;
}
tasks.Remove(task);
}
if( await UpdateUsersAsync(_UpdatedUsers, _dataService))
{
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
}
}
Your code would more or less look like this.
ObservableCollection<User> _UpdatedUsers = new ObservableCollection<User>();
int _verifiedUsersCount = 0;
DatabaseServiceLocal _dataService = new DatabaseServiceLocal(Database);
//Verify unique users
private void SaveUsers(bool CloseForm)
{
_dataService.CheckIsUserNameUnique += CheckIsUserNameUnique;
foreach (UserViewModel _User in _AllUsers)
{
//bool success = _dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
if (_User.Dirty && !_User.IsBlank)
{
_dataService.IsUserNameUnique(_User.UserName, _User.UserID, Database.CurrentClient.ClientID);
}
}
}
//Store verified users to save
private void CheckIsUserNameUnique(object s, CheckIsUserNameUniqueEventArgs e)
{
if (e.IsUnique)
_UpdatedUsers.Add(_User.SaveAsUser());
else
{
csaMessageBox.Show(string.Format("Username {0} is not allowed as it already exists in the system. Please choose a different username.", ""), null);
}
verifiedUsersCount++;
//Call after all the users have been verified for uniqueness
if (_AllUsers.Count() == verifiedUsersCount)
{
OnUniqueUserVerifyComplete();
}
}
//Save verified users
private void OnUniqueUserVerifyComplete()
{
//No unique users
if (_UpdatedUsers.Count < 1) { return; }
_dataService.UpdateStaffAndUsersCompleted += (s, e) =>
{
BusyIndicator = false;
if (e.Success)
{
}
if (CloseForm)
ReturnToHomePage();
else
{
LoadUsers();
OnUsersSaved();
}
};
BusyIndicator = true;
BusyMessage = "Saving...";
_dataService.UpdateUsers(Database.CurrentProject.ProjectID, Database.CurrentClient.ClientID, _UpdatedUsers, _DeletedProjectUsers);
}

facebook desktop app C#

I am trying to build a desktop app to use facebook api and get data from friends.
Anyways I am stuck in the log in stage.
I have used some advice and made the log in to facebook with WebBrowser. It works great.
I am stuck at trying to make it give me status = Failed or success
I tried doing it like this at the end of the button_1 method
if (!w.DocumentText.Contains(#"<div class=""linkWrap noCount"">Messages</div>"))
{
w.Navigate(#"http://www.facebook.com/login.php");
MessageBox.Show("Login error. Wrong username or password!");
}
else
{
MessageBox.Show("Logged in successfully");
}
the < div class=""linkWrap noCount"">Messages< /div> is only shown while logged in so thats why I use it to see if a user is logged in
but the problem is it always gives me an error (wrong user and pass) becasue it reads it before the browser finishes to navigate to the page. I tried threads and thread sleep and even timers but it doesnt seem to work
an ideas?
here is the code:
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(WorkThreadFunction));
thread.Start();
string email = textBox1.Text;
string password = textBox2.Text;
// create a new browser
WebBrowser w = new WebBrowser();
w.Dock = DockStyle.Fill;
this.Controls.Add(w); // you may add the controll to your windows forms if you want to see what is going on
// latter you may not chose to add the browser or you can even set it to invisible...
// navigate to facebook
w.Navigate(#"http://www.facebook.com/login.php");
// wait a little
for (int i = 0; i < 100; i++)
{
System.Threading.Thread.Sleep(10);
System.Windows.Forms.Application.DoEvents();
}
HtmlElement temp=null;
// while we find an element by id named email
while (temp == null)
{
temp = w.Document.GetElementById("email");
System.Threading.Thread.Sleep(10);
System.Windows.Forms.Application.DoEvents();
}
// once we find it place the value
temp.SetAttribute("value", email);
temp = null;
// wiat till element with id pass exists
while (temp == null)
{
temp = w.Document.GetElementById("pass");
System.Threading.Thread.Sleep(10);
System.Windows.Forms.Application.DoEvents();
}
// once it exist set its value equal to passowrd
temp.SetAttribute("value", password);
// if you already found the last fields the button should also be there...
var inputs = w.Document.GetElementsByTagName("input");
int counter = 0;
bool enableClick = false;
// iterate through all the inputs in the document
foreach (HtmlElement btn in inputs)
{
try
{
var att = btn.GetAttribute("tabindex");
var name = btn.GetAttribute("id");
if (enableClick)// button to submit always has a differnt id. it should be after password textbox
{
btn.InvokeMember("click");
counter++;
}
if (name.ToUpper().Contains("PASS") || att=="4")
{
enableClick = true; // button should be next to the password input
}
// try a max of 5 times
if (counter > 5)
{
break;
}
}
catch
{
}
}
}
Checkout the facebook-sharp SDK for Windows forms:
https://github.com/facebook-csharp-sdk/facebook-winforms
I recommend you use Facebook C# SDK. It uses the OAuth protocol, for user-authentication.
Down an code example how to get user friends with Facebook-C#-SDK:
using Facebook; //add reference to facebook dll for it work
declare the fields:
private FacebookOAuthResult result;
private FacebookOAuthClient OAuth;
and
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (webBrowser1.Url.AbsolutePath == "/login.php")
{
// do login..
}
if (FacebookOAuthResult.TryParse(e.Url, out result))
{
if (result.IsSuccess)
{
FacebookClient fbClient = new FacebookClient(result.AccessToken);
dynamic friends = fbClient.Get("/me/friends"); //User friends
// do something..
}
else
{
string errorDescription = result.ErrorDescription;
string errorReason = result.ErrorReason;
string msg = String.Format("{0} ({1})", errorReason, errorDescription);
MessageBox.Show(msg, "User-authentication failed!");
}
}
}
and then for start user-authentication:
//..
OAuth = new FacebookOAuthClient();
OAuth.AppId = appId; // see link above,you can find how to get it
OAuth.AppSecret = appSecret; // see link above,you can find how to get it
Uri loginUrl = OAuth.GetLoginUrl(paramenters);
webBrowser1.Navigate(loginUrl.AbsoluteUri);

Categories