We just went live with a rather complex integration between our online ordering portal and Epicor ERP.
This integration makes heavy use of Epicor functions.
All is working well, ordering are coming through to hit the function and create orders (well, in this case it was creating a quote, but alas) until I saw one order on our portal that was not showing as being linked to Epicor.
I correlated the event logs in the application server with the same time the order was submitted to us and I saw to interesting logs.
The first log was generated from a parsing error on Newtonsoft, which makes sense because I consume some serialized JSON in this function.
First error:
Newtonsoft.Json.JsonReaderException: After parsing a value an unexpected character was encountered: {. Path '[0]', line 5, position 0.
at Newtonsoft.Json.JsonTextReader.ParsePostValue(Boolean ignoreComments) in /_/Src/Newtonsoft.Json/JsonTextReader.cs:line 1480
at Newtonsoft.Json.JsonTextReader.Read() in /_/Src/Newtonsoft.Json/JsonTextReader.cs:line 426
at Newtonsoft.Json.JsonWriter.WriteToken(JsonReader reader, Boolean writeChildren, Boolean writeDateConstructorAsDate, Boolean writeComments) in /_/Src/Newtonsoft.Json/JsonWriter.cs:line 663
at Newtonsoft.Json.JsonWriter.WriteToken(JsonReader reader, Boolean writeChildren) in /_/Src/Newtonsoft.Json/JsonWriter.cs:line 514
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateJToken(JsonReader reader, JsonContract contract) in /_/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:line 232
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id) in /_/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:line 918
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent) in /_/Src/Newtonsoft.Json/Serialization/JsonSerializerInternalReader.cs:line 196
at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType) in /_/Src/Newtonsoft.Json/JsonSerializer.cs:line 907
at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings) in /_/Src/Newtonsoft.Json/JsonConvert.cs:line 828
at EFx.EpicorBridge.Implementation.Order_CreateQuoteImpl.A005_CustomCodeAction()
at EFx.EpicorBridge.Implementation.Order_CreateQuoteImpl.RunStep(Int32 workflowStep)
at Epicor.Functions.FunctionBase`3.Run() in C:\_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionBase.cs:line 90
at Epicor.Functions.FunctionBase`3.Run(TInput input) in C:\_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionBase.cs:line 75
at Epicor.Functions.FunctionRestAdapter`2.Run(IFunctionRestHost host, JObject input) in C:\_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionRestAdapter.cs:line 46
at Epicor.RESTApi.Functions.Controllers.EpicorFunctionController.Post(Boolean production, String company, String library, String function, JObject data) in C:\_Releases\ICE\UD10.2.600.10FW\Source\Server\Internal\RESTApi.Plugins\Epicor.RESTApi.EFxPlugin\Controllers\EpicorFunctionController.cs:line 69
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_2.<GetExecutor>b__2(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.HttpServer.<SendAsync>d__24.MoveNext()
The second error was even less descriptive and simple was an “Ice.Common.BusinessObjectException: Error int he application”. Surely related, not sure how.
Ice.Common.BusinessObjectException: Error in the application.
at Epicor.Functions.FunctionBase`3.ProcessRecordedExceptions() in C:\_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionBase.cs:line 134
at Epicor.Functions.FunctionBase`3.Run(TInput input) in C:\_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionBase.cs:line 77
at Epicor.Functions.FunctionRestAdapter`2.Run(IFunctionRestHost host, JObject input) in C:\_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionRestAdapter.cs:line 46
at Epicor.RESTApi.Functions.Controllers.EpicorFunctionController.Post(Boolean production, String company, String library, String function, JObject data) in C:\_Releases\ICE\UD10.2.600.10FW\Source\Server\Internal\RESTApi.Plugins\Epicor.RESTApi.EFxPlugin\Controllers\EpicorFunctionController.cs:line 69
at lambda_method(Closure , Object , Object[] )
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass6_2.<GetExecutor>b__2(Object instance, Object[] methodParameters)
at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__15.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.HttpServer.<SendAsync>d__24.MoveNext()
The function itself isn’t fancy, but it appears the first error choked on the custom code block as shown:
The code is as follows:
//iterate over incoming params to add part lines
dynamic prodList = Newtonsoft.Json.JsonConvert.DeserializeObject(productList);
//msg = prodList.ToString();
int rowCnt = 0;
foreach(var product in prodList)
{
//Get New Quote Dtl
this.CallService<Erp.Contracts.QuoteSvcContract>(qs =>{
qs.GetNewQuoteDtl(ref tsQuote, quoteNum);
//ChangePartNumMaster
string partNum = product.PartNum.ToString();
bool lIsPhantom = false;
bool lIsSalesKit = false;
string uomCode = "";
string rowType = "";
Guid SysRowID = Guid.Empty;
bool salesKitView = false;
bool removeKitComponents = false;
bool suppressUserPrompts = false;
bool runChkPrePartInfo = true;
string vMessage = "";
string vPMessage = "";
string vBMessage = "";
bool vSubAvail = false;
string vMsgType = "";
bool getPartXRefInfo = true;
bool checkChangeKitParent = true;
string cDeleteComponentsMessage = "";
bool multipleMatch = false;
bool promptToExplodeBOM = false;
string explodeBOMerrMessage = "";
tsQuote.QuoteDtl[rowCnt].PartNum = product.PartNum.ToString();
tsQuote.QuoteDtl[rowCnt].RowMod = "A";
qs.ChangePartNumMaster(ref partNum, ref lIsPhantom, ref lIsSalesKit, ref uomCode, rowType, SysRowID, salesKitView, removeKitComponents, suppressUserPrompts,runChkPrePartInfo, out vMessage,out vPMessage, out vBMessage, out vSubAvail, out vMsgType, getPartXRefInfo, checkChangeKitParent,out cDeleteComponentsMessage, out multipleMatch, out promptToExplodeBOM, out explodeBOMerrMessage, ref tsQuote);
//ChangePartNum
bool lSubstitutePartsExist = false;
tsQuote.QuoteDtl[rowCnt].RowMod = "A";
qs.ChangePartNum(ref tsQuote, lSubstitutePartsExist, uomCode);
//Update
tsQuote.QuoteDtl[rowCnt].RowMod = "A";
qs.Update(ref tsQuote);
rowCnt++;
}
);
//msg += product.PartNum.ToString()+ ": ";
}
This simple deserializes a string which looks something like this depending on the order submitted:
"productList": "[\r\n{\"PartNum\": \"32247001\"},\r\n{\"PartNum\":\"45647010\"}\r\n]",
and breaks it apart into a list and iterates over it creating Quote lines.
I have not encountered this error before in any testing nor have I seen it in any other cases (so far).
The first thing I will check tomorrow is to see if we can reproduce the error. The second will be to see if I can replicate what data was being passed to me and if that produces the error.
Is there anything else that is obvious to others that might have caused such a failure?
The other interesting thing is that even if it did choke on the serialization, it did not create the quote head, which comes first prior to any custom code block. It’s like the whole thing blew up…
Appreciate the second look, I’ve been up too long as it is