Epicor Rest Helper (Nuget) Updated (1.1.11)

I’ve updated the Rest Nuget Helpers below and added some new functionality so I figured I’d document i there for those that are using it.
Enhancements include CallContext Handling, Epicor Session Info and Specific License Type (Web Service License vs Default etc)
I have also deprecated most calls that aren’t the dynamic ones it just doesn’t make a lot of sense to have BO specific calls. So you should be using Dynamic Get, Post, Patch and Delete almost exclusively though the old calls still remain in the library (though deprecated)

https://www.nuget.org/packages/EpicorRestAPI/

https://www.nuget.org/packages/EpicorRESTAPICore/

https://www.nuget.org/packages/EpicorRESTAPIStandard/

1. License Type
When setting up the Epicor Rest Helper you can now specify the license type you’d like to consumme

EpicorRest.AppPoolHost = "yourdomain.yourhosting.tld";
EpicorRest.AppPoolInstance = "EpicorDemo10";
EpicorRest.UserName = "manager";
EpicorRest.Password = "manager";
EpicorRest.IgnoreCertErrors = true;
EpicorRest.License = EpicorLicenseType.WebService; // You can now specify the license type, it default to "Default" if not specified
EpicorRest.CallSettings = new CallSettings("EPIC03", string.Empty, string.Empty, string.Empty);

2. Call Context Support
You can now get and pass in CallContext (BPMData, and CallContextClient) with your requests. It is an optional parameter on all Dynamic calls (DynamicGet, DynamicPost, DynamicPatch, DynamicDelete)
You must pass an instance in, in order to get an instance back

EpicorRest.AppPoolHost = "yourdomain.yourhosting.tld";
EpicorRest.AppPoolInstance = "EpicorDemo10";
EpicorRest.UserName = "manager";
EpicorRest.Password = "manager";
EpicorRest.IgnoreCertErrors = true;
EpicorRest.License = EpicorLicenseType.WebService; // You can now specify the license type, it default to "Default" if not specified
EpicorRest.CallSettings = new CallSettings("EPIC03", string.Empty, string.Empty, string.Empty);

//Instanciate an Empty Call Context
CallContextHeader callContext = new CallContextHeader();
 Dictionary<string, string> dic = new Dictionary<string, string>();

dic.Add("$filter", $"Key1 eq 'Larry-Top' and Key5 eq 'Larry-Top'");
dic.Add("$top", "1");


newObj = EpicorRest.DynamicGet("Ice.BO.UD01Svc", "UD01s", dic, null, callContext); //Pass Call Context in and it Updates in place with the response.

Console.WriteLine(callContext.Context.BpmData[0].Character01);

3. HttpStatus Codes
You can now also return the HTTPStatus code of each dynamic call simply (as with CallContext) instantiate a EpicorRestStatusCode and pass it in, the call with update the object with the call result.

EpicorRest.AppPoolHost = "yourdomain.yourhosting.tld";
EpicorRest.AppPoolInstance = "EpicorDemo10";
EpicorRest.UserName = "manager";
EpicorRest.Password = "manager";
EpicorRest.IgnoreCertErrors = true;
EpicorRest.License = EpicorLicenseType.WebService; // You can now specify the license type, it default to "Default" if not specified
EpicorRest.CallSettings = new CallSettings("EPIC03", string.Empty, string.Empty, string.Empty);

//Instanciate an Empty Call Context
CallContextHeader callContext = new CallContextHeader();
 Dictionary<string, string> dic = new Dictionary<string, string>();

dic.Add("$filter", $"Key1 eq 'Larry-Top' and Key5 eq 'Larry-Top'");
dic.Add("$top", "1");

EpicorRestStatusCode statusCode = new EpicorRestStatusCode();
newObj = EpicorRest.DynamicGet("Ice.BO.UD01Svc", "UD01s", dic, statusCode , callContext); //Pass in an instance of status code and it will be returned to you for error checking.

if(statusCode.RestCallStatusCode == System.Net.HttpStatusCode.OK) //See SWAGGER for expected codes on each call
{
//Good!
}
else {
//Bad
}

4. Session Info
Up until now REST Calls have not carried session specific headers now if you want to use an actual session (server side) you can do so, simply wrap any of the REST calls in an EpicorSession instance and the session information will be passed to the server with each call, and it will be disposed Logged out when the using finishes.

EpicorRest.AppPoolHost = "yourdomain.yourhosting.tld";
EpicorRest.AppPoolInstance = "EpicorDemo10";
EpicorRest.UserName = "manager";
EpicorRest.Password = "manager";
EpicorRest.IgnoreCertErrors = true;
EpicorRest.License = EpicorLicenseType.WebService; // You can now specify the license type, it default to "Default" if not specified
EpicorRest.CallSettings = new CallSettings("EPIC03", string.Empty, string.Empty, string.Empty);
//Note you must setup the Rest Helper FIRST before instantiating a new EpicorSession
using (EpicorSession sess = new EpicorSession())
{
     //The call below will carry a valid EpicorSession ID which can be monitored server side
     Dictionary<string, string> dic = new Dictionary<string, string>();
     dic.Add("$filter", $"Key1 eq 'Larry-Top' and Key5 eq 'Larry-Top'");
     dic.Add("$top", "1");
     newObj = EpicorRest.DynamicGet("Ice.BO.UD01Svc", "UD01s", dic, statusCode, c);
     //Session info can be accessed via EpicorRest.EpiSession
     Console.WriteLine(EpicorRest.EpiSession.SessionID);
}


Update 6/2/2020 Release 1.1.11
Fixes a potential memory leak issue where the RequestLogger kept every request forever on a long running application this caused a huge inflated memmory footprint and would eventually cause a stack overflow if not manually cleared.
In this version we limit the amount of requests in the RequestLog to 25 but this can be overwritten by setting the MaxRequestLogLength property

 EpicorRest.MaxRequestLogLength = 900;
20 Likes

Jose, could you please provide documentation/install instructions/prerequisites for these packages? Also, is there a way to install extensions like these once for use in VS instead of installing on each solution?

No nuget is per project,
Pre-Reqs are listed in the nuget site.

OK… What about .Net Framework prerequisites? Tried to install the packages on a project with a Target Framework of 4.5.2 and failed

John

Not exactly, you could always build a copy yourself and then reference it for all your projects but you lose all the convenience of Nuget that way. (assuming Jose has it available on his Github) What part bothers you about per project? You could create a project template with the package included I suppose. I believe Nuget does a decent job caching so I doubt it will waste much internet re-downloading it.

It works with 4.7.2 if you have the choice. @josecgomez might be able to compile it for an older version depending on what features / dependencies he is using.

Thanks, Evan! I’m not stuck on 4.5.2, just didn’t know what the earliest version would be that would work . I was hoping to be able to install a package once, then
reference it in a project when needed. It does make sense to install per project to keep up with updates to the packages.

2 Likes

I can compile with an older version of .net… just not sure what version is “best”…
It is currently compiled with 4.6.1 which is fairly old. Not sure if going back to 4.5 is worth it.

I wouldn’t bother - its not like you have a legacy user base you have to keep happy. In this case @JMyers56 was able to change his project target anyway.

1 Like

@josecgomez … we’re not currently specifying any session data in our calls to the API. Are there any advantages to using that feature considering we are Epicor Cloud?

Hi @Jeff_Owens
That allows you to see server side the Session and address it , change it, etc using BPMs and such. It also gives you control of when the session is disposed etc can help with licensing

1 Like

I’m having trouble with EpicorRest.GetBAQResults - I get the following error:

Newtonsoft.Json.JsonReaderException: 'Unexpected character encountered while parsing value: <. Path '', line 0, position 0.'

I used GetBAQResultJSON to get the Json, and put it in an online validator, which says it is valid. However I noticed that the JSON from GetBAQResultJSON is still escaped:

"{\r\n  \"odata.metadata\":\"https://ausmtsapp01.epicorsaas.com/SaaS203/api/v1/BaqSvc/OEMSpecsMachineInfo/$metadata#Epicor.DynamicQuery.QueryResults\",\"value\":[\r\n    {\r\n      \"UD100_Key1\":\"\",\"UD100_Key2\":\"\",\"UD100_Key3\":\"\",\"UD100_Key4\":\"\",\"UD100_Key5\":\"\",\"UD100_Character10\":\"1f7a6678-2884-4baf-a30d-67987d6150d0\",\"UD100_Number01\":\"0.000000000\",\"UD100_Number02\":\"0.000000000\",\"UD100_Number03\":\"0.000000000\",\"UD100_Number04\":\"0.000000000\",\"UD100_Number05\":\"0.000000000\",\"UD100_CheckBox01\":false,\"UD100_Date01\":null,\"UD100_Character01\":\"\",\"UD39_CheckBox03\":null,\"UD40_CheckBox01\":null,\"UD40_CheckBox02\":null,\"UD40_ShortChar12\":null,\"UD40_ShortChar13\":null,\"UD39_ShortChar09\":null,\"Calculated_Compare\":false,\"Calculated_Nom\":\"0X0\",\"RowMod\":null,\"RowIdent\":\"41f8bade-6aaf-4be2-b3bb-e97db237626f\",\"SysRowID\":\"41f8bade-6aaf-4be2-b3bb-e97db237626f\"\r\n    },{\r\n      \"UD100_Key1\":\"Astec\",\"UD100_Key2\":\"5X12\",\"UD100_Key3\":\"Bottom\",\"UD100_Key4\":\"6x5\",\"UD100_Key5\":\"(Discharge Panel)\",\"UD100_Character10\":\"D0E3B38A-3032-430A-B411-97E900C787B3\",\"UD100_Number01\":\"6.000000000\",\"UD100_Number02\":\"5.000000000\",\"UD100_Number03\":\"6.000000000\",\"UD100_Number04\":\"5.000000000\",\"UD100_Number05\":\"1.000000000\",\"UD100_CheckBox01\":true,\"UD100_Date01\":\"2019-08-21T00:00:00\",\"UD100_Character01\":\"This specification is missing the following information: Crown\",\"UD39_CheckBox03\":false,\"UD40_CheckBox01\":false,\"UD40_CheckBox02\":false,\"UD40_ShortChar12\":\"Approved\",\"UD40_ShortChar13\":\"Approved\",\"UD39_ShortChar09\":\"Incomplete\",\"Calculated_Compare\":false,\"Calculated_Nom\":\"6X5\",\"RowMod\":null,\"RowIdent\":\"f8cbe1a7-3ef6-4161-8f13-e876610c5eae\",\"SysRowID\":\"f8cbe1a7-3ef6-4161-8f13-e876610c5eae\"\r\n    },{\r\n      \"UD100_Key1\":\"Astec\",\"UD100_Key2\":\"5X12\",\"UD100_Key3\":\"Bottom\",\"UD100_Key4\":\"6x5\",\"UD100_Key5\":\"(Feed Panel)\",\"UD100_Character10\":\"48F31B64-BB4B-4D3C-A2A4-B2A9C3E96876\",\"UD100_Number01\":\"6.000000000\",\"UD100_Number02\":\"5.000000000\",\"UD100_Number03\":\"6.000000000\",\"UD100_Number04\":\"5.000000000\",\"UD100_Number05\":\"1.000000000\", **<snip>**

I think that is probably the issue. Not sure if it started happening because I updated the Rest helper nuget package or if it was the last Epicor update we got… I think it needs to be double parsed.

@josecgomez Any chance you can publish these helpers to Github?

Most of these are deprecated @Evan_Purdy can you try using GetDynamic instead?
And let me know what you get? (no pun intended)

Seems to work, I will have to change my code as it kind of assumed a datatable and not a JObject or whatever that is returning. I didn’t realize the other methods were deprecated - maybe add the ObsoleteAttribute :stuck_out_tongue:

I did to most lol forgot this one

Update 6/2/2020 Release 1.1.11
Fixes a potential memory leak issue where the RequestLogger kept every request forever on a long running application this caused a huge inflated memmory footprint and would eventually cause a stack overflow if not manually cleared.
In this version we limit the amount of requests in the RequestLog to 25 but this can be overwritten by setting the MaxRequestLogLength property

EpicorRest.MaxRequestLogLength = 900;
1 Like

Note that this will very likely be the last release of the NuGet at v1. Our next release is intended to include v2 and backwards compatibility for v1. We intend to do a rewrite so there will very likely be breaking changes from our current v1 especially in regards to error handling, we intend to improve it greatly. We are aiming to keep signatures as much the same as we can and remove all deprecated methods that were originally very BO specific before the generalized methods were implemented.

2 Likes

@josecgomez, @jgiese.wci
Is there documentation for these nuget packages and maybe some examples? I am messing around with them and am not getting very far.

The OP Above has a bunch of examples. What are you not getting to work?

Just trying this simple call and i get a null ref at the DynamicGet.

EpicorRest.AppPoolHost = "https://site";
EpicorRest.AppPoolInstance = "EpicorTrain10";
EpicorRest.UserName = "manager";
EpicorRest.Password = "manager";
EpicorRest.IgnoreCertErrors = true;
EpicorRest.License = EpicorLicenseType.Default; // You can now specify the license type, it default to "Default" if not specified
EpicorRest.CallSettings = new CallSettings("EPIC06", string.Empty, string.Empty, string.Empty);

//Instanciate an Empty Call Context
CallContextHeader callContext = new CallContextHeader();
Dictionary<string, string> dic = new Dictionary<string, string>();

dic.Add("$top", "1");

var newObj = EpicorRest.DynamicGet("Erp.BO.CustomerSvc", "Customers", dic);