Tuesday, April 8, 2014

SharePoint Designer 2013 Workflow changes

Already, there are so many articles published about the new features and changes in SharePoint Designer 2013 that it’s a little late to write about this. But I think this would be useful.

There are many new functionalities and enhancements added into SharePoint designer 2013.
Added features allow designers to do more with workflows without requiring a developer to write custom code.

If you select SharePoint 2013 option while creating workflow, you will get the following list of new features

1. Stages

With 2013, concept of stage is introduced. It acts as containers in workflow, which allows one to structure the workflow from one stage to the other. Stages can be added to a workflow by clicking on Stage icon.





Key points for Stages:


  • All actions in the workflow must be contained in a stage
  • A stage can hold one or more workflow actions, and will also have only one Transition to stage area. 
  • The Transition to stage area defines how the workflow exits the stage after its actions have been processed. The stage can be configured to transition to another stage, or to end the workflow.
  • Workflows must have at least one stage, and it is not possible to nest stages in a workflow.
2. Actions

In 2013 new workflow actions are also introduced and they can be used while designing workflow.



Adding this action to a workflow allows a designer to create a single task, assign it to a specific user, and save the Outcome and TaskID values to workflow variables.



3. Assign a Task

Click on "Assign a task" action from actions menu, and the container displayed in above image, will show up.
Now click on thisuser, which will open the following dialogue.




4. Start a Task Process:
This action is the same as “Assign a Task” action, with the difference being that multiple participants can be assigned to the task being created. The participants can be assigned to the task one at a time (serial, meaning the first participant must respond to the task before the next participant is assigned, and so on.), or all participants can be assigned to the task at the same time (parallel).

                                    


5. Loops

There are two types of looping available: 


  • Loop n Times: Loop type allows a designer to create a looping condition where the actions contained in the loop container are executed a specified number of times.
  • The Loop with Condition: Loop type allows a designer to create a looping condition where the actions contained in the loop container are executed until a specified condition is met.

Key points for loops:
  1. Loops must be contained within a stage.
  2. A stage can be added inside a loop.
  3. Loops can have only one entry and only one exit point.
  4. Nested loops are also supported.
6. Call HTTP Web Service

This action allows you to call a REST-based web service without writing custom code. You specify the URL to the web service you wish to call, along with the HTTP method (GET, PUT, POST, and DELETE).

7. Visual Designer
In SharePoint Designer 2013 the Visual Designer is also introduced. This designer is only available for workflows on the 2013 platform, and you will need Visio 2013 Professional installed on your PC to have this available in SharePoint Designer.
When creating a workflow, you can switch to the Visual Designer by selecting it from the ribbon:


 
This will switch the view of the workflow you are designing to a view that looks a lot like a diagram in Visio:
With all these new features in the SharePoint designer, it has now become more powerful and strong enough for developer to not want to go for custom coding!


Thursday, February 6, 2014

Workflow gets canceled automatically with (500) Internal Server Error.


Workflow is getting cancel with the HTTP 500 error. 

Problem:

RequestorId: 9dea9a29-bb82-214a-0000-000000000000. Details: RequestorId: 9dea9a29-bb82-214a-0000-000000000000. Details: An unhandled exception occurred during the execution of the workflow instance. Exception details: System.ApplicationException: HTTP 500 {"Transfer-Encoding":["chunked"],"X-SharePointHealthScore":["0"],"SPClientServiceRequestDuration":["30"],"SPRequestGuid":["9dea9a29-bb82-214a-92f0-943af4411ac2"],"request-id":["9dea9a29-bb82-214a-92f0-943af4411ac2"],"X-FRAME-OPTIONS":["SAMEORIGIN"],"MicrosoftSharePointTeamServices":["15.0.0.4420"],"X-Content-Type-Options":["nosniff"],"X-MS-InvokeApp":["1; RequireReadOnly"],"Cache-Control":["max-age=0, private"],"Date":["Fri, 31 Jan 2014 20:19:03 GMT"],"Server":["Microsoft-IIS\/7.5"],"X-AspNet-Version":["4.0.30319"],"X-Powered-By":["ASP.NET"]} at Microsoft.Activities.Hosting.Runtime.Subroutine.SubroutineChild.Execute(CodeActivityContext context) at System.Activities.CodeActivity.InternalExecute(ActivityInstance instance, ActivityExecutor executor

Probable solution/findings to verify:

1. Generally occurs with send email functionality in workflow.
2. Check outgoing email settings for the farm are correct.
3. Disabled firewall on the Exchange/SMTP server.
4. Check App management service is running, UPA is set up and  completed sync such that the user running the workflow has a profile.

Monday, December 9, 2013

Custom action to a callout in SharePoint 2013


During my POC, I was trying to add custom action to a callout same like, Share and follow.found easy way to do it with following script.

 SP.SOD.executeFunc("callout.js", "Callout", function () {  
  var itemCtx = {};  
  itemCtx.Templates = {};  
  itemCtx.BaseViewID = 'Callout';  
  // Define the list template type  
  itemCtx.ListTemplateType = 101;  
  itemCtx.Templates.Footer = function (itemCtx) {  
    
   return CalloutRenderFooterTemplate(itemCtx, AddCustomAction, true);  
  };  
  SPClientTemplates.TemplateManager.RegisterTemplateOverrides(itemCtx);  
 });  
 function AddCustomAction (renderCtx, calloutActionMenu) {     
  // Add custom action  
  calloutActionMenu.addAction (new CalloutAction ({  
   text: "Custom Action",  
   tooltip: 'This is your custom action',  
   onClickCallback: function() { console.log('Alert from custom action'); }  
  }));  
 }  




We are good to go!!

Sunday, December 8, 2013

PowerShell to Cancel All SharePoint Workflows in Progress

I was struck with requirement were having big list and workflow attached to it, need to cancel all running workflows. 
It could be either manually traverse all the way and stop it, was next to impossible.
Following script helped me to save my time!


$web = Get-SPWeb "http://mysharepointserver.com/subsite";
$web.AllowUnsafeUpdates = $true;    

$list = $web.Lists["CustomListName"];
$count = 0

foreach ($listItem in $list.Items) 
{
 foreach ($workflow in $listItem.Workflows) 
 {
 
  if(($listItem.Workflows | where 
  {$_.InternalState -ne "Completed"}) -ne $null)
  {
   #Cancel Workflows        
   [Microsoft.SharePoint.Workflow.SPWorkflowManager]::
     CancelWorkflow($workflow);      
   write-output "Workflow cancelled for : 
     " $listItem.Title;  
  }
 }
}
$web.Dispose();
Hope this will save your time!

Monday, September 30, 2013

SP2013 : Task list not visible to other users

I came across weird issue, I created a task list with the system account.
This list is not able to view by any other users.
Spent enough time on finding a cause. It was all due to IE, it was working fine with Chrome and other browsers.

To make it work with IE:
1.  Active x and JS permissions has to be enabled.
2. The site has to be in the trusted pool of you internet explorer. 
3. Disable any extra add-ons.

Hope this small piece of information will save time

Wednesday, September 11, 2013

Create a custom view on Workflow Task Status

I came across to the requirement to create a custom view based on workflow status.

Requirement was to show all the approved items.


I found a interesting stuff, Filter will not work if we use words like below image:


we would need use the number rather than the words (e.g. 2 instead of In Progress, 4 instead of Cancelled etc)

Following list might help for this kind of requirement:

Status
Value
Not Started
0
Failed on Start
1

In Progress
2

Error Occurred
3

Canceled
4

Completed

5
Failed on Start (retrying)

6
Error Occurred (retrying)
7

Canceled
15

Approved
16

Rejected

17

Hope this will save your time!


Sunday, June 23, 2013

Provider Hosted App - Azure and Read, Write to SharePoint List with real example

Hi,

After my first blog on simple app,
http://anujabhojani.blogspot.in/2013/06/step-by-step-sharepoint-2013-provider.html

Now will go in detail about how to read and write SharePoint list with Provider Hosted App.

Here to cover all the scenario implementing it with real example by creatingvTrello App.

http://www.trello.com is basically a task management tool. I am developing app which will have following functionality,
1. App will take user token (oauth) from Trello to read all the cards  for current logged in user.
2. Trello will return token, which our app will store in one SharePoint list so next time when user visit the app, will get the token from list and directly get all the cards from trello.

Now, lets start and build this app.

1. Having Default.aspx in my solution, adding following code in page_load to get the access token


  1. public partial class Default : System.Web.UI.Page
  2. {
  3. public static string userToken = string.Empty;
  4. Uri appWeb;
  5. string myAccessToken;
  6. ClientContext clientContext;
  7. protected void Page_Load(object sender, EventArgs e)
  8. {
  9. if (!IsPostBack)
  10. {
  11. TokenHelper.TrustAllCertificates();
  12. var contextToken = TokenHelper.GetContextTokenFromRequest(Page.Request);
  13. HttpCookie cookie = new HttpCookie("AccessToken");
  14. SharePointContextToken spContextToken = TokenHelper.ReadAndValidateContextToken(contextToken, Request.Url.Authority);
  15. appWeb = new Uri(Page.Request["SPHostUrl"]);
  16. myAccessToken = TokenHelper.GetAccessToken(spContextToken, appWeb.Authority).AccessToken;
  17. cookie.Value = myAccessToken;
  18. Response.Cookies.Add(cookie);
  19. ReadListItems(appWeb.ToString(), myAccessToken);
  20. }
  21. }

2.  Here in SharPoint site I have created one list named "usertoken", with UserName and Token, In ReadListItems will check the Trello token is present for current logged in user or not, if it will be there will get it directly and display the Trello cards assigned to Logged in user.
For Reading List item using REST API to get list items. 

  1. private void ReadListItems(string webUrl, string myAccessToken)
  2. {
  3. string oDataUrl = "/_api/Web/lists/getbytitle('UserToken')/items?$select=Token,UserName";
  4. var requestUrl = new Uri(string.Format("{0}{1}", webUrl, oDataUrl));
  5. HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(requestUrl);
  6. Response.Write(webUrl.ToString() + oDataUrl);
  7. request.Method = "GET";
  8. request.Accept = "application/atom+xml";
  9. request.ContentType = "application/atom+xml;type=entry";
  10. request.Headers.Add("Authorization", "Bearer " + myAccessToken);
  11. HttpWebResponse response = (HttpWebResponse)request.GetResponse();
  12. XDocument oDataXML = XDocument.Load(response.GetResponseStream(), LoadOptions.None);
  13. XNamespace atom = "http://www.w3.org/2005/Atom";
  14. XNamespace d = "http://schemas.microsoft.com/ado/2007/08/dataservices";
  15. XNamespace m = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata";
  16. List<XElement> entries = oDataXML.Descendants(atom + "entry")
  17. .Elements(atom + "content")
  18. .Elements(m + "properties")
  19. .ToList();
  20. var entryFieldValues = from entry in entries
  21. select new
  22. {
  23. Token = entry.Element(d + "Token").Value,
  24. UserName = entry.Element(d + "UserName").Value
  25. };
  26. var itemCOllection = entryFieldValues.ToList();
  27. clientContext = TokenHelper.GetClientContextWithAccessToken(webUrl, myAccessToken);
  28. Web web = clientContext.Web;
  29. clientContext.Load(web);
  30. clientContext.ExecuteQuery();
  31. clientContext.Load(web.CurrentUser);
  32. clientContext.ExecuteQuery();
  33. var currentUser = clientContext.Web.CurrentUser.Title;
  34. for (int i = 0; i < itemCOllection.Count; i++)
  35. {
  36. Response.Write(itemCOllection[i].Token);
  37. if (itemCOllection[i].UserName == currentUser & itemCOllection[i].Token != string.Empty)
  38. {
  39. userToken = itemCOllection[i].Token.ToString();
  40. }
  41. }
  42. if (userToken == string.Empty)
  43. {
  44. Response.Redirect("https://trello.com/1/authorize?key=fd43232051021f33680eb2c6cf3125b3&name=TrellSharepoint&expiration=never&response_type=token&return_url=<SiteName>/Home.aspx?FromTrello=yes&Web=" + appWeb);
  45. }
  46. else
  47. {
  48. Response.Redirect("<SiteName>/Home.aspx?FromTrello=No&token=" + userToken);
  49. }
  50. }
3. Now as you see, we are moving to Home.aspx with Trello userToken if it will be there in list.
If not present in list will redirect to trello site and get authentication token from there,
In home.aspx we have to add script to get UserToken from trello return url.
 function GetUserToken() {
            var token;
            var url = document.location;
            var strippedUrl = url.toString().split("#");
            if (strippedUrl.length > 1) {
                self.location = strippedUrl[0] + "?" + strippedUrl[1];
            }
        }
will call this function on Body onload.

4. For reading trello cards, I have used Chello.dll which is .net wrapper for trello development.
Add reference of chello in solution.
  1. protected void Page_Load(object sender, EventArgs e)
  2. {
  3. if (Request.QueryString != null && Request.QueryString.Count > 0 && Request.QueryString.AllKeys.Contains("token"))
  4. {
  5. ChelloClient chelloClient = new ChelloClient(System.Configuration.ConfigurationManager.AppSettings["TrelloAppKey"], Request.QueryString["token"]);  
  6. IEnumerable<Board> boards = chelloClient.Boards.ForUser("my");
  7. boardGrid.DataSource = boards;
  8. boardGrid.DataBind(); 
  9. }
  10. if (Request.QueryString.AllKeys.Contains("FromTrello"))
  11. {
  12. var IsRedirectfromTrello = Request.QueryString["FromTrello"];
  13. if (IsRedirectfromTrello == "yes")
  14. {
  15. AddToken();
  16. }
  17. }
  18. }

This will display the boards available for current logged in user, And as you see I have took grid to bind it.  
  1. <ItemTemplate>
  2. <tr style="height:50px;">
  3. <td>
  4. <asp:LinkButton runat="server" ID="linkBoardName" Text="" CommandName="borad"><%#Eval("Name") %></asp:LinkButton></td>
  5. </tr>
  6. </ItemTemplate>
         

This will display the boards available for current logged in user, And as you see I have took grid to bind it.  
  1. <ItemTemplate>
  2. <tr style="height:50px;">
  3. <td>
  4. <asp:LinkButton runat="server" ID="linkBoardName" Text="" CommandName="borad"><%#Eval("Name") %></asp:LinkButton></td>
  5. </tr>
  6. </ItemTemplate>
            
5. Here in grid we are binding boards name into link button, and on button click having following code
  1. protected void boardGrid_ItemCommand(object sender, ListViewCommandEventArgs e)
  2. {
  3. if (e.CommandName == "borad")
  4. {
  5. LinkButton btn = e.CommandSource as LinkButton;
  6. ChelloClient chelloClient = new ChelloClient(System.Configuration.ConfigurationManager.AppSettings["TrelloAppKey"], Request.QueryString["token"]);
  7. IEnumerable<Chello.Core.List> list = chelloClient.Lists.ForBoard("513584cbf885e0711c0007fe");
  8. IEnumerable<Card> cards = chelloClient.Cards.ForBoard("513584cbf885e0711c0007fe");
  9. myListView.DataSource = list.Take(3);
  10. myListView.DataBind();
  11. ListView1.DataSource = cards.Where(t => t.IdList == list.First().Id);
  12. ListView1.DataBind();
  13. boardGrid.Visible = false;
  14. }
  15. } 
6. As in code I have took Listview to bind cards, Now its time to write Trello token back to list,
So next time when user come will not redirect to Trello site for getting user token. I am writing to SharePoint list by ClientContext to cover both the scenarios:
In page_load we have call AddToken(); 
  1. private void AddToken()
  2. {
  3. var appWeb = new Uri("<Siteurl>");
  4. HttpCookie cookie = new HttpCookie("AcessToken");
  5. cookie = Request.Cookies["AccessToken"];
  6. var myAccessToken = cookie.Value;  
  7. ClientContext clientContext = TokenHelper.GetClientContextWithAccessToken(appWeb.ToString(), myAccessToken);
  8. Web web = clientContext.Web;
  9. clientContext.Load(web);
  10. clientContext.ExecuteQuery();
  11. clientContext.Load(web.CurrentUser);
  12. clientContext.ExecuteQuery();
  13. var currentUser = clientContext.Web.CurrentUser.Title;
  14. Microsoft.SharePoint.Client.List oList = web.Lists.GetByTitle("UserToken");
  15. ListItemCreationInformation itemCreation = new ListItemCreationInformation();
  16. Microsoft.SharePoint.Client.ListItem listItem = oList.AddItem(itemCreation);
  17. listItem["UserName"] = currentUser;
  18. listItem["Token"] = Request.QueryString["token"];
  19. listItem.Update();
  20. clientContext.ExecuteQuery();
  21. }
We are done! Just publish the solutions and will get trello cards on our Azure hosted app.
While publishing I came across few bugs which resolved and described in following blogs which might be helpful :

http://anujabhojani.blogspot.in/2013/06/error-web-deployment-task-failed.html

http://anujabhojani.blogspot.in/2013/06/the-parameter-token-cannot-be-null-or.html

Happy Coding!