Update task item programatically in Sharepoint with CSOM - task

I want to update a task item programatically in CSOM. Item is updating but workflow is not triggering. I need just to open the item in sharepoint and save it. Then workflow is triggering.
List requestTasksList = MyWeb.Lists.GetByTitle("TestRequest Tasks");
List<TestRequestModel> testRequestList = new List<TestRequestModel>();
ListItemCollection ColListItems = requestTasksList.GetItems(Spqur);
ctx.Load(ColListItems);
ctx.ExecuteQuery();
foreach (ListItem task in ColListItems)
{
task["Status"] = "Completed";
task["TaskOutcome"] = "Approved";
task["PercentComplete"] = 1.0;
task["Checkmark"] = 1;
task.Update();
requestTasksList.Update();
}
ctx.ExecuteQuery();
This is the updated task item
As i said, When i click to save button, workflow is triggering and new task is creating.

I'm not sure if its typo but it should be
List requestTasksList = MyWeb.Lists.GetByTitle("TestRequest Tasks");
List<TestRequestModel> testRequestList = new List<TestRequestModel>();
ListItemCollection ColListItems = requestTasksList.GetItems(Spqur);
foreach (ListItem task in ColListItems)
{
task["Status"] = "Completed";
task["TaskOutcome"] = "Approved";
task["PercentComplete"] = 1.0;
task["Checkmark"] = 1;
task.Update();
}
ctx.ExecuteQuery();

We needed to do the same thing and have found that there are no event handlers on the workflow tasks list in SharePoint 2013. I know that there is a SPWorkflowAutostartEventReceiver on lists that have workflows auto start on add or update, so I assumed this same approach would be done for workflow tasks as well, but it is not. Since there are no event handlers on the workflow tasks list, I surmise that all workflow triggers are initiated from the server-side UI code on the task list (horrible design).
For us we need to work completely client side with no farm solution or sandboxed code. So our only solution has been to screen scrape URLs and then open pages or dialogs for the user to do things like cancel all tasks for an approval workflow. Granted, this approach still does requires user input. I suppose you could screen scrape the whole page and play back the action of hitting buttons on a task page or cancel task page if you needed to avoid user input. That would be a pain, though.

Related

Best approach to create a background task

I'm currently developing a Ruby on Rails application that on certain moment has to import a (at least for me) medium-large dataset using a third-party API. It has to do an average of 6000 API calls. One after another. It lasts about 20 minutes.
Right now I have made a rails task that does everything as I want (calls, write to db, etc). But now I want this task/code to be ALSO called from a button on the web. I know it's not a good approach to let the controller call the task so that's why I'm asking.
I want this import code to be available to be called from a controller and a task, because later I want to be able to call this task from a cronjob, and even if it's possible to have callbacks on the progress of the task on the controller, i.e. know how many calls are left.
I know it's not a good approach to let the controller call the task
There's nothing wrong with having a button trigger a background task like this, but of course you need to do so with care. For example, perhaps:
If the task is already running, don't let a second instance overlap.
If the task runs for too long, automatically kill it.
Carefully restrict who can trigger this.
There are many libraries available for implementing a progress bar, or you could even write a custom implementation. For example, see this blog post - which works by polling the current progress:
// app/views/exports/export_users.js.haml
:plain
var interval;
$('.export .well').show();
interval = setInterval(function(){
$.ajax({
url: '/progress-job/' + #{#job.id},
success: function(job){
var stage, progress;
// If there are errors
if (job.last_error != null) {
$('.progress-status').addClass('text-danger').text(job.progress_stage);
$('.progress-bar').addClass('progress-bar-danger');
$('.progress').removeClass('active');
clearInterval(interval);
}
progress = job.progress_current / job.progress_max * 100;
// In job stage
if (progress.toString() !== 'NaN'){
$('.progress-status').text(job.progress_current + '/' + job.progress_max);
$('.progress-bar').css('width', progress + '%').text(progress + '%');
}
},
error: function(){
// Job is no loger in database which means it finished successfuly
$('.progress').removeClass('active');
$('.progress-bar').css('width', '100%').text('100%');
$('.progress-status').text('Successfully exported!');
$('.export-link').show();
clearInterval(interval);
}
})
},100);
An variant approach you could consider is to use a websocket to see progress, rather than polling.
Convert the specific tasks into background jobs, i.e. (active job, sideqik), so your system can continue working while it's doing the tasks. Create classes for each task and call those classes within your background jobs or cronjobs.
One design pattern that could fit here is the "command" pattern, I gave you a list of things you can Google :).
Just move most of the code from the task to a module or method in a model. You can call this code from the task (as your do it now) or from a background job that would start through a controller when you press a button on a view.

refresh every 5 minutes en asp.net mvc

The controller display the data from the excel sheet.
I need that the controller check the excel sheet every 1 hour, also the views should be updated.
This is my controller code:
string path3 = "D:/Project/Sesame Incident Dump_20160317.xls";
Excel.Application application3 = new Excel.Application();
Excel.Workbook workbook3 = application3.Workbooks.Open(path3);
Excel.Worksheet worksheet3 = workbook3.ActiveSheet;
Excel.Range range3 = worksheet3.UsedRange;
List<SesameIncident> ListSesameIncident = new List<SesameIncident>();
for (int row = 2; row <= range3.Rows.Count; row++)
{
SesameIncident S = new SesameIncident();
S.Number = (((Excel.Range)range3.Cells[row, 1]).Text);
S.AssignedTo = (((Excel.Range)range3.Cells[row, 5]).Text);
S.Opened = (((Excel.Range)range3.Cells[row, 6]).Text);
S.Status = (((Excel.Range)range3.Cells[row, 7]).Text);
S.Priority = (((Excel.Range)range3.Cells[row, 10]).Text);
S.AssignedGroup = (((Excel.Range)range3.Cells[row, 12]).Text);
ListSesameIncident.Add(S);
}
ViewBag.ListSesameIncidents = ListSesameIncident
.Where(x => x.Status == "Pending Customer").Take(13);
You can add a Header to your HttpContext.Response in your controller
HttpContext.Response.Headers.Add("refresh", "300; url=" + Url.Action("Index"));
<script type="text/javascript">
setTimeout(function () {
location.reload();
}, 5 * 60 * 1000);
</script>
refer Refresh Page for interval using js
You can refresh the page this way
for the controller you might need a table in database to refer, when was last updated, for reference you will have to store reference data permanently , this is my opinion, I never had such requirement
To run something periodically without user interaction (that is, without a request to initiate it), a web application isn't what you want. Instead, you're looking for either a Windows Service or perhaps a simple Console Application scheduled to run at regular intervals by the host system's scheduling software (Windows Task Scheduler, cron, etc.). See How to execute a method in Asp.net MVC for every 24 hours
I would rather think about caching that could potentially save reading xls every time. See How to cache data in a MVC application
To update the client every X second is quite simple. Just use a
meta
http-equiv
With the value refresh in you page's Header.
This solution is clean and easy to read and you will not be depending of a simple JavaScript loop.
To update your excel sheet every X, you need another app with a
Timer. You can do whatever you want, if you're using .net, a simple console application will do the work. If you are using Azure you could just use a worker role, that is exactly what a worker
Is about ;p

Quartz.Net job doesn't fire continuously

I have a job scheduled in Application_start event using quartz.net, the trigger is fired every 1 min given by the variable repeatDurationTestData = "0 0/1 * * * ?";
The triggering starts when I first open the site, But stops after some random time when I close the browser and starts again when I open the site. Following is the code
IMyJob testData = new SynchronizeTestData();
IJobDetail jobTestData = new JobDetailImpl("Job", "Group", testData.GetType());
ICronTrigger triggerTestData = new CronTriggerImpl("Trigger", "Group", repeatDurationTestData);
_scheduler.ScheduleJob(jobTestData, triggerTestData);
DateTimeOffset? nextFireTime = triggerTestData.GetNextFireTimeUtc();
What Am i doing wrong here, Is this because of some misfire. Please suggest.
Thanks
At First I would use a simple trigger in this case as it takes a repeat interval and seems to fit better than the cron trigger would (from lesson 5 quartz.net website) :
SimpleTrigger trigger2 = new SimpleTrigger("myTrigger",
null,
DateTime.UtcNow,
null,
SimpleTrigger.RepeatIndefinitely,
TimeSpan.FromSeconds(60));
I would also recommend you don't put the quartz scheduler within the website. the main purpose of a job system is to work independently of anyother system so it generally fits naturally into a windows service. By putting it as part of the website you arn't guaranteed its going to keep going. If you loose the app pool or it restarts, you wont get a reliable result.
There is an example with the quartz.net download.
hope that helps.

JIRA / Greenhopper update stories when sub tasks are updated

In my JIRA/Greenhopper, when i move a subtask under story to "In Progress" can I automatically move my story to "In Progress"?
Also when I've closed all the tasks in my story can it automatically move my a story to close.
What you want to do is add post-function to the task's workflow transition from "Open" to In Progress". The post-function should transition the parent User Story from "Open" to In Progress". I used the Jira Scripting Suite plugin and a Jython script to do something similar.
Your algorithm would go something like this:
parentUserStory = task.getParentObject()
if (parentUserStory.getStatusObject().getName() == "Open"):
inProgressTransitionID = 41 # This is the id of the transition from Open -> In Progress in the User Story workflow*
workflowManager = ComponentManager.getInstance().getWorkflowManager()
userStoryWorkflow = workflowManager.getWorkflow(parentObject)
usCurrentStep = userStoryWorkflow.getLinkedStep(parentObject.getStatus())
listOfActions = usCurrentStep.getActions()
for act in listOfActions:
if str(act) == "In Progress":
break
else:
log.debug("No match: " + str(act))
iIP = IssueInputParametersImpl()
issueService = ComponentManager.getInstance().getIssueService()
transitionValidationResult = issueService.validateTransition(issue.getAssignee(),parentObject.getId(),act.getId(),iIP)
Key points:
You don't want to arbitrarily change the issue status. That way madness lies. Instead, transition the issue through its workflow.
The actual code for making the transition happen is dependent on your Jira version and the language you choose. It can be complex. Copy-and-pasting the above will doubtless fail. Hopefully it's enough to get you started.
Extra resource: answers.atlassian.com.
currUser = ComponentManager.getInstance().getJiraAuthenticationContext().getUser()
currUserName = currUser.getName()
issueServiceObj = ComponentManager.getInstance().getIssueService()
issueParamImpl = IssueInputParametersImpl()
issueParamImpl.setAssigneeId(currUserName)
issueId = issue.getId()
transValiRes = issueServiceObj.validateTransition(currUser,issueId,91,issueParamImpl)
if(transValiRes.isValid()):
System.out.println("Transition validated")
transitionResult = issueServiceObj.transition(currUser,transValiRes)
else:
System.out.println("in else")
Please let me know , if I am missing something
Install a free JIRA Misc Workflow Extensions plugin
Edit your "In Progress" transition to add a Post Function to transition parent issue using the same "In Progress" transition (kind of a reference to itself).
Note: Prefer using transition id, as it silently fails if you have several transitions with the same name.

SPListItem.Update and SPFile.Update fail

We are running one MOSS application as below:-
1. user use InfoPath request form to trigger workflow attached to SharePoint document library
2. all sub-sequent tasks are performed by users by InfoPath task form within SharePoint site through "Workflow Task" list (open, checkout, approve or reject) till the task completed.
3. all request form submitted could be viewed as xml file in the document library through "Explorer View"
My quesiton is why I cannot update the item located in the document library, basically open the SPListItem:-
SPSite thisSite = new SPSite("http://server")
{
SPWeb thisWeb = thisSite.OpenWeb("/web")
{
thisSite.AllowUnsafeUpdates = true;
thisWeb.AllowUnsafeUpdates = true;
SPDocumentLibrary library = (SPDocumentLibrary)thisWeb.Lists["DocLib"];
foreach (SPListItem item in library.Items)
{
SPFile file = item.File;
I tried almost all ways I could find:-
item["Customer Name"] = "123456";
item.Update();
// or item.SystemUpdate();
file.Item["Customer Name"] = "123456";
file.Update();
After each update, the value resumed when reopen or visit through the same code lines!
but when I view item properties, the "Last modified" is changed
Last modified at 6/8/2010 12:27 AM by Administrator
This do drive me cray, any help, please.
Thanks & best regards,
Leon
When you publish your form to a list, it asks you to choose the fields to be shown on that list. As you choose the item you want to update, click "Modify". Check the checkbox
at the bottom saying "Allow user to edit data in this field by using a datasheet or property page". This works for me.

Resources