How to programmatically set the task outcome (task response) of a Nintex Flexi Task? - sharepoint-2010

Is there any way of set a Nintex Flexi task completion through Sharepoint's web services? We have tried updating the "WorkflowOutcome", "ApproverComments" and "Status" fields without success (actually the comments and status are successfully updated, however I can find no way of updating the WorkflowOutcome system field).
I can't use the Nintex Web service (ProcessTaskResponse) because it needs the task's assigned user's credentials (login, password, domain).
The Asp.net page doesn't have that information, it has only the Sharepoint Administrator credentials.
One way is to delegate the task to the admin first, and then call ProcessTaskResponse, but it isn't efficient and is prone to errors.
In my tests so far, any update (UpdateListItems) to the WorkflowOutcome field automatically set the Status field to "Completed" and the PercentComplete field to "1" (100%), ending the task (and continuing the flow), but with the wrong answer: always "Reject", no matter what I try to set it to.

Did you try this code: (try-cacth block with redirection does the trick)
\\set to actual outcome id here, for ex. from OutComePanel control
taskItem[Nintex.Workflow.Common.NWSharePointObjects.FieldDecision] = 0;
taskItem[Nintex.Workflow.Common.NWSharePointObjects.FieldComments] = " Some Comments";
taskItem.Update();
try
{
Nintex.Workflow.Utility.RedirectOrCloseDialog(HttpContext.Current, Web.Url);
}
catch
{
}
?

Here are my code to change outcome of nintex flexi task. My problem is permission. I had passed admin token to site. It's solve the problem.
var siteUrl = "...";
using (var tempSite = new SPSite(siteUrl))
{
var sysToken = tempSite.SystemAccount.UserToken;
using (var site = new SPSite(siteUrl, sysToken))
{
var web = site.OpenWeb();
...
var cancelled = "Cancelled";
task.Web.AllowUnsafeUpdates = true;
Hashtable ht = new Hashtable();
ht[SPBuiltInFieldId.TaskStatus] = SPResource.GetString(new CultureInfo((int)task.Web.Language, false), Strings.WorkflowStatusCompleted, new object[0]);
ht["Completed"] = true;
ht["PercentComplete"] = 1;
ht["Status"] = "Completed";
ht["WorkflowOutcome"] = cancelled;
ht["Decision"] = CommonHelper.GetFlexiTaskOutcomeId(task, cancelled);
ht["ApproverComments"] = "cancelled";
CommonHelper.AlterTask((task as SPListItem), ht, true, 5, 100);
task.Web.AllowUnsafeUpdates = false;
}
}
}
}
}
}
public static string GetFlexiTaskOutcomeId(Microsoft.SharePoint.Workflow.SPWorkflowTask task, string outcome)
{
if (task["MultiOutcomeTaskInfo"] == null)
{
return string.Empty;
}
string xmlOutcome = HttpUtility.HtmlDecode(task["MultiOutcomeTaskInfo"].ToString());
if (string.IsNullOrEmpty(xmlOutcome))
{
return string.Empty;
}
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlOutcome);
var node = doc.SelectSingleNode(string.Format("/MultiOutcomeResponseInfo/AvailableOutcomes/ConfiguredOutcome[#Name='{0}']", outcome));
return node.Attributes["Id"].Value;
}
public static bool AlterTask(SPListItem task, Hashtable htData, bool fSynchronous, int attempts, int milisecondsTimeout)
{
if ((int)task[SPBuiltInFieldId.WorkflowVersion] != 1)
{
SPList parentList = task.ParentList.ParentWeb.Lists[new Guid(task[SPBuiltInFieldId.WorkflowListId].ToString())];
SPListItem parentItem = parentList.Items.GetItemById((int)task[SPBuiltInFieldId.WorkflowItemId]);
for (int i = 0; i < attempts; i++)
{
SPWorkflow workflow = parentItem.Workflows[new Guid(task[SPBuiltInFieldId.WorkflowInstanceID].ToString())];
if (!workflow.IsLocked)
{
task[SPBuiltInFieldId.WorkflowVersion] = 1;
task.SystemUpdate();
break;
}
if (i != attempts - 1)
{
Thread.Sleep(milisecondsTimeout);
}
}
}
var result = SPWorkflowTask.AlterTask(task, htData, fSynchronous);
return result;
}

Related

Using MQTT ManagedClient with ASP NET API, how to?

I'm currently working on a project that has to rely heavily on MQTT - one of the parts that needs to utilize MQTT is a ASP Net API, but I'm having difficulties receiving messages.
Here is my MQTTHandler:
public MQTTHandler()
{
_mqttUrl = Properties.Resources.mqttURL ?? "";
_mqttPort = Properties.Resources.mqttPort ?? "";
_mqttUsername = Properties.Resources.mqttUsername ?? "";
_mqttPassword = Properties.Resources.mqttUsername ?? "";
_mqttFactory = new MqttFactory();
_tls = false;
}
public async Task<IManagedMqttClient> ConnectClientAsync()
{
var clientID = Guid.NewGuid().ToString();
var messageBuilder = new MqttClientOptionsBuilder()
.WithClientId(clientID)
.WithCredentials(_mqttUsername, _mqttPassword)
.WithTcpServer(_mqttUrl, Convert.ToInt32(_mqttPort));
var options = _tls ? messageBuilder.WithTls().Build() : messageBuilder.Build();
var managedOptions = new ManagedMqttClientOptionsBuilder()
.WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
.WithClientOptions(options)
.Build();
_mqttClient = new MqttFactory().CreateManagedMqttClient();
await _mqttClient.StartAsync(managedOptions);
Console.WriteLine("Klient startet");
return _mqttClient;
}
public async Task PublishAsync(string topic, string payload, bool retainFlag = true, int qos = 1)
{
await _mqttClient.EnqueueAsync(new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(payload)
.WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)qos)
.WithRetainFlag(retainFlag)
.Build());
Console.WriteLine("Besked published");
}
public async Task SubscribeAsync(string topic, int qos = 1)
{
var topicFilters = new List<MQTTnet.Packets.MqttTopicFilter>
{
new MqttTopicFilterBuilder()
.WithTopic(topic)
.WithQualityOfServiceLevel((MQTTnet.Protocol.MqttQualityOfServiceLevel)(qos))
.Build()
};
await _mqttClient.SubscribeAsync(topicFilters);
}
public Status GetSystemStatus(MqttApplicationMessageReceivedEventArgs e)
{
try
{
var json = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
var status = JsonSerializer.Deserialize<Status>(json);
if (status != null)
{
return status;
}
else
{
return null;
}
}
catch (Exception)
{
throw;
}
}
The above has been tested with a console app and works as it should.
The reason I need MQTT in the APi is that a POST method has to act on the value of a topic;
In particular I need to check a systems status before allowing the post;
[HttpPost]
public async Task<ActionResult<Order>> PostOrder(Order order)
{
if (_lastStatus != null)
{
if (_lastStatus.OpStatus)
{
return StatusCode(400, "System is busy!");
}
else
{
var response = await _orderManager.AddOrder(order);
return StatusCode(response.StatusCode, response.Message);
}
}
return StatusCode(400, "Something went wrong");
}
So I will need to set up a subscriber for this controller, and set the value of _lastStatus on received messages:
private readonly MQTTHandler _mqttHandler;
private IManagedMqttClient _mqttClient;
private Status _lastStatus;
public OrdersController(OrderManager orderManager)
{
_orderManager = orderManager;
_mqttHandler = new MQTTHandler();
_mqttClient = _mqttHandler.ConnectClientAsync().Result;
_mqttHandler.SubscribeAsync("JSON/Status");
_mqttClient.ApplicationMessageReceivedAsync += e =>
{
_lastStatus = _mqttHandler.GetSystemStatus(e);
return Task.CompletedTask;
};
}
However, it's behaving a little odd and I'm not experienced enough to know why.
The first time I make a POST request, _lastStatus is null - every following POST request seem to have the last retained message.
I'm guessing that I am struggling due to stuff being asynchronous, but not sure, and every attempt I've attempted to make it synchronous have failed.
Anyone have a clue about what I'm doing wrong?

Flurl Post Not Returning from Web Api

I've got a Xamarin application using Flurl, with the following post to a Web Api
Xamarin App:
private async Task<LoginResponse> processLogin()
{
try
{
return await "http://192.168.0.12:60257/api/loginapi/Login".WithTimeout(10).PostJsonAsync(new { username = "fsdafsd", password = "gdfgdsf" }).ReceiveJson<LoginResponse>();
}
catch (Exception e)
{
return new LoginResponse { ResponseStatusCode = -1 };
}
}
Web Api:
public LoginResponse Login([FromBody]LoginRequest loginRequest)
{
var result = new LoginResponse();
try
{
var user = this.UserManager.FindAsync(loginRequest.username, loginRequest.password);
if (user != null)
{
result.ResponseStatusCode = 1;
}
else
{
result.ResponseStatusCode = 0;
}
}
catch (Exception e)
{
result.ResponseStatusCode = -1;
}
return result;
}
I can see my Web Api method getting hit, and it returns the expected object type, not my Xamarin application continues to wait on the Flurl Post.
Can anyone advise what I might be doing wrong?
UPDATE:
I have noticed that the following does work, but it's not ideal:
dynamic result = await "http://192.168.0.12:60257/api/loginapi/Login".PostJsonAsync(new { username = "fsdafsd", password = "gdfgdsf" }).ReceiveJson();
Fixed it. For whatever reason, it was the type I was trying to return. Changing the object variable type to "dynamic" fixed this, and allowed me to deserialise the object correctly.
dynamic result = await "http://192.168.0.12:60257/api/loginapi/Login".PostJsonAsync(new { username = "fsdafsd", password = "gdfgdsf" }).ReceiveJson();
Returns a dynamic object with the properties I'd expect in the normal structure.
If anyone can enlighten my why I couldn't do:
LoginRequest result = ...
It'd be appreciated.

return login success from a web api to an mvc 4 application

my colleague and myself are working on an application form with login functionality the user logs in from the mvc 4 app and there details are submitted to the web api to be checked against the values held in the database once verified the web api returns a loginResult class that contains the error message (if any) and a bool for stating whether it has been successful or not.
at the mvc 4 application level the code below is used to submit the login details to the web api:
Login Action
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(AccountViewModel model)
{
if (!ModelState.IsValid) return View("Login", model);
await _client.PostAsJsonAsync("api/Applicant/CheckApplicant", model)
.ContinueWith((postTask) => postTask.Result.EnsureSuccessStatusCode());
var service = DependencyResolver.Current.GetService<IApplyService>();
var loginResult = service.GetLoginResult();
var loginSuccess = loginResult.LoginSuccess;
if (loginSuccess != null && (bool) loginSuccess)
{
FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe);
return RedirectToRoute("Terms And Conditions");
}
return View("Login");
}
the login details are then received at the web api in this method:
Check Applicant Method
public String CheckApplicant(Applicant applicant)
{
Int32 passwordFailureTimeoutMins = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["PasswordFailureTimeoutMins"]);
Int32 passwordFailureAttempts = Convert.ToInt32(System.Configuration.ConfigurationSettings.AppSettings["PasswordFailureAttempts"]);
ApplicantRepository applicantRepository = new ApplicantRepository();
Applicant applicantDB = applicantRepository.GetById(applicant.Email);
LoginResult loginResult = new LoginResult();
PasswordHelper passwordHelper = new PasswordHelper();
if (applicantDB == null)
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "Your password or login may not be correct.";
}
else
{
bool loginFailureCheck;
if (applicantDB.LoginFailureCount > passwordFailureAttempts)
{
System.TimeSpan diffResult = DateTime.Now.Subtract(Convert.ToDateTime(applicantDB.LastLoginFailure));
if (diffResult.Minutes < passwordFailureTimeoutMins)
{
loginFailureCheck = false;
}
else
{
loginFailureCheck = true;
}
}
else
{
loginFailureCheck = true;
}
if (passwordHelper.CheckPassword(applicant.Password, applicantDB.Password))
{
if(loginFailureCheck)
{
if(applicantDB.AccountActive)
{
loginResult.LoginSuccess = true;
loginResult.LoginError = "Login Successful.";
applicantDB.LastLoginFailure = null;
applicantDB.LastLoginSuccess = DateTime.Now;
applicantDB.LoginFailureCount = 0;
applicantRepository.Update(applicantDB);
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "This account has been permanently banned.";
}
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "This account is now temporarily disabled please wait " + passwordFailureTimeoutMins + " minutes before trying again";
applicantDB.LastLoginFailure = DateTime.Now;
applicantDB.LoginFailureCount = applicantDB.LoginFailureCount + 1;
applicantRepository.Update(applicantDB);
}
}
else
{
loginResult.LoginSuccess = false;
loginResult.LoginError = "Your password or login may not be correct.";
applicantDB.LastLoginFailure = DateTime.Now;
applicantDB.LoginFailureCount = applicantDB.LoginFailureCount + 1;
applicantRepository.Update(applicantDB);
}
}
return JsonConvert.SerializeObject(loginResult);
}
as you can see it returns a JsonConvert.SerializeObject(loginResult).
when this is done the process returns to the Login ActionResult as above it then moves to the GetLoginResult() method as shown below:
GetLoginResult
public LoginResult GetLoginResult()
{
const string uri = "http://localhost:55830/api/Applicant/CheckApplicant";
using (var httpClient = new HttpClient())
{
var response = httpClient.GetStringAsync(uri);
return JsonConvert.DeserializeObject<LoginResult>(response.Result);
}
}
when it get to this point it returns an error 405 method not allowed.
How do I consume the loginResult at the mvc 4 app level and what is the best way of sending the loginResult from the web api?
Any advice would be greatly appreciated.
Not sure what exactly you are trying to do but are you making a GET to read the result of the previous POST? You can read the response message of POST to get the result, like this.
public async Task<ActionResult> Login(AccountViewModel model)
{
if (!ModelState.IsValid) return View("Login", model);
var message = await _client.PostAsJsonAsync
("api/Applicant/CheckApplicant", model);
message.EnsureSuccessStatusCode();
LoginResult result = await message.Content.ReadAsAsync<LoginResult>();
// do other stuff here
}
Change the web API action method to return LoginResult directly. The framework will serialize it for you.
public LoginResult CheckApplicant(Applicant applicant)
{
}

The security validation for this page is invalid error trying to add sharepoint approval workflow to List in ListAdded eventreceiver

What I am trying to do is to attach the OOTB sharepoint workflow [Approval Sharepoint - 2010] to each and every document library that ever gets created. To accomplish this I created a List Added event reciever and put this code in it -
public override void ListAdded(SPListEventProperties properties)
{
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPUtility.ValidateFormDigest();
using (SPSite site = new SPSite(properties.SiteId))
{
using (SPWeb web = site.OpenWeb())
{
try
{
base.ListAdded(properties);
if (currentList is SPDocumentLibrary)
{
SPDocumentLibrary docLib = (SPDocumentLibrary)properties.List;
//workflows need a tasks and history list. Here we assume they exist
SPList taskList = web.Lists["Tasks"];
SPList historyList = web.Lists["Workflow History"];
//loop through the workfows in the web and grab the one we want by name
SPWorkflowTemplate wfTemp = null;
foreach (SPWorkflowTemplate wt in web.WorkflowTemplates)
{
if (wt.Name == "Approval - SharePoint 2010")
{
wfTemp = wt;
Common.AddToLog(web, "Found " + wt.Name + " in current web " +
web.Url, false);
break;
}
}
//Now add the workflow to the doc library
SPWorkflowAssociation workFlow = SPWorkflowAssociation.CreateListAssociation(wfTemp, wfTemp.Name, taskList, historyList);
workFlow.AllowManual = true;
workFlow.AutoStartChange = false;
workFlow.AutoStartCreate = true;
workFlow.AssociationData = null;
web.AllowUnsafeUpdates = true;
web.ValidateFormDigest();
docLib.WorkflowAssociations.Add(workFlow);
docLib.EnableModeration = true;
docLib.Update();
web.Update();
web.AllowUnsafeUpdates = false;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
web.AllowUnsafeUpdates = false;
}
}
}
});
}
I am getting this error-
The security validation for this page is invalid. Click Back in your Web browser, refresh the page, and try your operation again.
at this line
docLib.WorkflowAssociations.Add(workFlow);
Any any have any suggestions please ? Thanks for your feedback.
Why do you need "SPUtility.ValidateFormDigest()" at all?
Your code was running in an event receiver, not on a form or aspx page, there is nothing to validate.
Could you remove this line and try again?
I believe updating this code block:
web.AllowUnsafeUpdates = true;
web.ValidateFormDigest();
docLib.WorkflowAssociations.Add(workFlow);
docLib.EnableModeration = true;
docLib.Update();
web.Update();
web.AllowUnsafeUpdates = false;
and replacing it with:
web.Site.WebApplication.FormDigestSettings.Enabled = false;
docLib.WorkflowAssociations.Add(workFlow);
docLib.EnableModeration = true;
docLib.Update();
web.Update();
web.Site.WebApplication.FormDigestSettings.Enabled = true;
Let me know if this works for you or if you still encounter the same error.

Set the value of custom webpart property in c#

How to set the value of custom webpart property Programatically in C#.
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite SiteCollection = new SPSite(mySiteGuid))
{
SPWeb myWeb = SiteCollection.OpenWeb(myWebGuid);
myWeb .AllowUnsafeUpdates = true;
Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager mgr = null;
mgr = myWeb.GetLimitedWebPartManager ("default.aspx",System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);
foreach (System.Web.UI.WebControls.WebParts.WebPart myWebPart in mgr.WebParts)
{
if (myWebPart.Title == "Other Webpart Name")
{
myWebPart.Visible = ! myWebPart.Visible;
myWeb.Update();
break;
}
}
}
});
I have a custom property in the webpart of type string to get the input from the user.
I wanted to updated the value of the property from c#.
Is there any way to set the value?
TIA
Try myWebPart.Update() instead of myWeb.Update().
Maybe it's a bit late for the answer, but here i let a piece of code i used for this.
var webCollection = new SPSite("http://mySharePointSite").AllWebs;
foreach (SPWeb web in webCollection)
{
var landingPageReference = #"/Pages/default.aspx";
var page = web.GetFile(landingPageReference);
if (!page.Exists)
continue;
page.CheckOut();
var spLimitedWebPartManager = web.GetLimitedWebPartManager(page.ServerRelativeUrl, PersonalizationScope.Shared);
foreach (WebPart webPartItem in spLimitedWebPartManager.WebParts)
{
if (webPartItem.Title.Equals("myWebPartTitle"))
{
// Specify Properties to change here
webPartItem.ChromeType = PartChromeType.Default;
webPartItem.Description = "AGAIN CHANGED";
// Save made changes
spLimitedWebPartManager.SaveChanges(webPartItem);
break;
}
}
page.CheckIn("Add Comment if desired");
page.Publish("Add Comment if desired");
web.Update();
web.Dispose();
}