Showing posts with label InfoPath 2013. Show all posts
Showing posts with label InfoPath 2013. Show all posts

Saturday, October 8, 2016

How to approve SharePoint Tasks from mobile devices?

Many have tried and offered options and workarounds which somewhat work. There are options like the "Lazy Approval" or paid apps. I am going to offer you my take on this issue.

THE PROBLEM 
You have on premise SharePoint 2013 farm and you are utilizing InfoPath forms for many different purposes. Some of these forms require approval and trigger an approval workflow which kicks out an email to end users. This is no problem on desktops and laptops with Outlook while in office or connected via VPN. The problem is with end users who are often on the go and would like to review and approve forms on their mobile devices such as IPhones/IPads and Androids. 

Side Problems: 
  • We need to convert specific links to FQDN links to ensure its accessible from the outside.
  • We need to force InfoPath forms to open in browser.
  • We need to force SharePoint to open in PC View.
THE SOLUTION
Prior to proceeding, I have created a simple Approval Workflow in SharePoint 2010 workflow format and specified my approves. In case of some InfoPath forms, approves are added on the fly when filling out a form,

InfoPath Forms Library Site Location: http://demo/subsite
  1. Edit the Approval Workflow in SharePoint Designer 2013
  2. Click on Change the behavior of a single task
  3. Click on Local Variables and create two variables.
    1. fqdnURL with type of String
    2. InfoPathMobileFQDN with type of String.
  4. Under When a Task is Pending window.
    1. Click on Action button in the ribbon.
      1. Select Extract Substring from Index of String. Had to do this in order to get part of the task URL that is needed later in the workflow to change the link to FQDN.
      2. Click on string and set it to Current Task:Form_URN
      3. It will output to Variable: substring2
    2. Click on Action button in the ribbon.
      1. Select Set Workflow Variable.
      2. Click on workflow variable and set it to Variable:fqdnURL.
      3. Click on value and set it to the site fully qualified domain name url, in my case its http://demo.whateverdomain.com/subsite
    3.  Click on Action button in the ribbon.
      1. Select Set Workflow Variable.
      2. Click on workflow variable and set it to Variable:InfoPathMobileFQDN.
      3. Click on value and set it to the site fully qualified domain name url used to open InfoPath form in browser, in my case its: "http://demo.whateverdomain.com/subsite/_layouts/15/FormServer.aspx?XmlLocation=/subite/[%TaskProcess:Item_URL%]&ClientInstalled=false&DefaultItemOpen=1"
      4. In red above please insert your own information.
      5. Should look like the following:
      6. Click on ...then Email task notification to Current Task: Assigned_To, number 4 in the above image.
      7. Highlight and edit link after the Review word in line #1, and set it to:
        1. Text to display: [%Task Process:Item_Title%]
        2. Address: set it to variable InfoPathMobileFQDN.
      8. Add If you don't see Open this task button, please click here text to the like line #3.
      9. Highlight the If you don't see Open this task button, please click here text and click on Edit HyperlLink button and set it to:
        1. Text to display: please click here
        2. Address: [%Variable: fqdnURL%]/[%Variable: substring2%]&OpenIn=Browser&Mobile=0
      10. Should look like the following:
      11. The added link in the line #3 in the screenshot above is to accommodate Non-Outlook users such as when checking webmail or using mobile devices. 
      12. Click OK and save and publish your workflow.
      13. Start a workflow with yourself and try it out on your mobile device.
NOTE: Please note that you will need to do this on few other places within this particular workflow and if you have more then one approval workflow, you will need to do this on every single one of them. There are also considerations such as if you are using UAG or some other method to publish your on premise SharePoint so that its accessible to the outside world.

This is a very first try and I plan to tweak it here and there using variables to reduce amount of typing the URLs and so on. Long story short, Approval workflows can be accessed and approved via mobile devices with few modifications mentioned above. I hope this helps someone.

Keep in mind,  you are using the above on your own risk. 

Wednesday, May 20, 2015

SharePoint 2013 List throws the "Value does not fall within the expected range." error when trying to submit a new item.

Recently, we had an issue with one of our custom lists. This list had a form customized with InfoPath 2013. Out of nowhere, one day we could not submit any new items and would get the following error message.


"Value does not fall within the expected range."
After checking ULS logs, we found the following:



System.ArgumentException: Value does not fall within the expected range., StackTrace:
at Microsoft.SharePoint.SPListItem.AddOrUpdateItem(Boolean bAdd, Boolean bSystem, Boolean bPreserveItemVersion, Boolean bNoVersion, Boolean bMigration, Boolean bPublish, Boolean bCheckOut, Boolean bCheckin, Guid newGuidOnAdd, Int32& ulID, Object& objAttachmentNames, Object& objAttachmentContents, Boolean suppressAfterEvents, String filename, Boolean bPreserveItemUIVersion)
at Microsoft.SharePoint.SPListItem.UpdateInternal(Boolean bSystem, Boolean bPreserveItemVersion, Guid newGuidOnAdd, Boolean bMigration, Boolean bPublish, Boolean bNoVersion, Boolean bCheckOut, Boolean bCheckin, Boolean suppressAfterEvents, String filename, Boolean bPreserveItemUIVersion)
at Microsoft.SharePoint.SPListItem.Update()
at Microsoft.SharePoint.SPListItem.ValidateUpdateListItem_Client(List`1 formValues, Boolean bNewDocumentUpdate)
at Microsoft.SharePoint.ServerStub.SPListItemServerStub.InvokeMethod(Object target, String methodName, XmlNodeList xmlargs, ProxyContext proxyContext, Boolean& isVoid)
at Microsoft.SharePoint.Client.ServerStub.InvokeMethodWithMonitoredScope(Object target, String methodName, XmlNodeList args, ProxyContext proxyContext, Boolean& isVoid)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.InvokeMethod(Object obj, String methodName, XmlNodeList xmlargs, Boolean& isVoid)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.ProcessMethod(XmlElement xe)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.ProcessOne(XmlElement xe)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.ProcessStatements(XmlNode xe)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.ProcessExceptionHandlingScope(XmlElement xe)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.ProcessOne(XmlElement xe)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.ProcessStatements(XmlNode xe)
at Microsoft.SharePoint.Client.ClientMethodsProcessor.Process()
at Microsoft.SharePoint.Client.ClientRequestServiceImpl.ProcessQuery(Stream inputStream, IList`1 pendingDisposableContainer)
at Microsoft.SharePoint.Client.ClientRequestService.ProcessQuery(Stream inputStream)
at SyncInvokeProcessQuery(Object , Object[] , Object[] )
at System.ServiceModel.Dispatcher.SyncMethodInvoker.Invoke(Object instance, Object[] inputs, Object[]& outputs)
at System.ServiceModel.Dispatcher.DispatchOperationRuntime.InvokeBegin(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage5(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.ImmutableDispatchRuntime.ProcessMessage31(MessageRpc& rpc)
at System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean isOperationContextSet)
at System.ServiceModel.Dispatcher.ChannelHandler.DispatchAndReleasePump(RequestContext request, Boolean cleanThread, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.HandleRequest(RequestContext request, OperationContext currentOperationContext)
at System.ServiceModel.Dispatcher.ChannelHandler.AsyncMessagePump(IAsyncResult result)
at System.Runtime.Fx.AsyncThunk.UnhandledExceptionFrame(IAsyncResult result)
at System.Runtime.AsyncResult.Complete(Boolean completedSynchronously)
at System.Runtime.InputQueue`1.AsyncQueueReader.Set(Item item)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(Item item, Boolean canDispatchOnThisThread)
at System.Runtime.InputQueue`1.EnqueueAndDispatch(T item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.SingletonChannelAcceptor`3.Enqueue(QueueItemType item, Action dequeuedCallback, Boolean canDispatchOnThisThread)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.CompleteParseAndEnqueue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EnqueueMessageAsyncResult.HandleParseIncomingMessage(IAsyncResult result)
at System.Runtime.AsyncResult.SyncContinue(IAsyncResult result)
at System.ServiceModel.Channels.HttpPipeline.EmptyHttpPipeline.BeginProcessInboundRequest(ReplyChannelAcceptor replyChannelAcceptor, Action dequeuedCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Channels.HttpChannelListener`1.HttpContextReceivedAsyncResult`1.ProcessHttpContextAsync()
at System.ServiceModel.Channels.HttpChannelListener`1.BeginHttpContextReceived(HttpRequestContext context, Action acceptorCallback, AsyncCallback callback, Object state)
at System.ServiceModel.Activation.HostedHttpTransportManager.HttpContextReceived(HostedHttpRequestAsyncResult result)
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.HandleRequest()
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.BeginRequest()
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequest(Object state)
at System.ServiceModel.AspNetPartialTrustHelpers.PartialTrustInvoke(ContextCallback callback, Object state)
at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.OnBeginRequestWithFlow(Object state)
at System.Runtime.IOThreadScheduler.ScheduledOverlapped.IOCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* nativeOverlapped)
at System.Runtime.Fx.IOCompletionThunk.UnhandledExceptionFrame(UInt32 error, UInt32 bytesRead, NativeOverlapped* nativeOverlapped)
at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32 errorCode, UInt32 numBytes, NativeOverlapped* pOVERLAP)


We figured it was a corrupted column but since this list has about 80 columns of different types we could not quite put a finger on which one was corrupted. After exhausting google search and million articles that led to mostly custom code, development, and people/groups column issues we submitted a ticket with Microsoft. However, Microsoft could not figure it out but agreed that its a corrupted column.

Our next step was to export the list and import it into another site and start deleting columns one by one until we find the one that is corrupted. After much trial and error we found that the issue was with a dropdown (choice column). If we deleted that particular choice column, we could submit new items with no problems.

So deleting this column in production list would be a big problem, hence deleting was not an option or at least not yet. Next, we realized that this column was indexed so we deleted its index and tried to submit new item...and it worked!!!

So it appears that its index was corrupted somehow, so simply deleting its index resolved the issue.