Epicor Rest Helper - Static Class

I have created a Blazor Server application using the Epicor Rest Helper. Since EpicorRest is a static class, a scoped instance can not be created and this has led to the settings being shared between users, matching the last user logged in. Transactions are being saved to the db under the last user login instead of the current user. Any suggestions to separate the calls with Blazor Server app?

program.cs

var appSettings = builder.Configuration.GetSection("ServerSettings");
EpicorRest.AppPoolHost = appSettings["Host"];
EpicorRest.Company = appSettings["Company"];
EpicorRest.APIKey = appSettings["APIKey"];

loginService

public async Task<AppSession> GetAppSession(LoginModel loginModel, AppSession appSession)
{
    EpicorRest.UserName = loginModel.UserName;
    EpicorRest.Password = loginModel.Password;
    EpicorRest.AppPoolInstance = loginModel.Instance;
    try
    {
        if (await EpicorRest.CreateBearerTokenAsync())
        {
            EpicorRest.EpiSession = new EpicorRestSession();
            appSession.UserName = loginModel.UserName;
            appSession.IsAuthenticated = true;
        }
        return appSession;
    }
    catch (Exception)
    {
        throw;
    }
}

You are setting a username
And password and also generating a token which an async call

Try using a session for the call and setting just the username and password then wrapping the session in a using statement

Thanks for the reply, @josecgomez .

Please excuse my ignorance, but won’t placing the session in a using statement dispose of that session at the end of the function and require a new session each time a function call is placed to EpicorRest? If the EpicorRest.UserID and .Password are revised each time a user logs in, and possibly the .AppPoolInstance (Production vs Test), will it not result in the same behavior?

Thanks for your help.

If you are using a session (which you don’t need) yes you should be making a new one for each user on each call

Otherwise just don’t use session at all username and password is plenty

I have uploaded a video of what I am experiencing. After a second user logs on, the EpicorRest.UserID, EpicorRest.Password and EpicorRest.AppPoolInstance are updated to the last users login information. Creating a new EpicorRestSession would be based on the other user given the current state of EpicorRest. To avoid this without being able to scope an instance of EpicorRest, I would have to reassign the userID and password before each EpicorRest call.

Yes you need to do that re-assign the username and password on every call. I can look into turning it into an instance class but even if I did its a single backend so you would still have to do somehow keep track of who the user is and swap user’s or class instance

Having the class not be static wouldn’t really help you here

Dependency Injection as a scoped service?

AH got it hmm ok well…

Short answer maintain the username / password as a scoped variable and raplce it on the calls…

Longer answer we’ve already been considering moving to an instance class

How are you maintaining the uusername / password between calls for a user right now? are you storing that in a session variable?

No, and that seems to be the issue. On login, the userID and password are stored to EpicorRest and then used for subsequent calls. Problem is the next user login overwrites the previous credentials and next calls are written under those user details. I need a scoped instance to keep the calls separate.

However here’s what I recommend instead. User an impersonation header

  1. Establish a server side username / password config for an account that has impersonation rights
  2. for the Login screen (only) use the provided username / password to validate / authenticate. Establish a user session which keeps the username as part of the state
  3. For every subsequent call use the impersonation header to make any rest calls simply apply the impersonate property before every call with the username from the request using the configured account with impersonation rights.

Something like this, mind you this is pseudo code

EpicorRest.AppPoolHost = Settings.Default.Host; //TLD to your Epicor Server
EpicorRest.AppPoolInstance = Settings.Default.Instance; //Epicor AppServer Insdtance
EpicorRest.UserName = Settings.Default.User; //Epicor Username
EpicorRest.Password = Settings.Default.Password; //Epicor Password
EpicorRest.APIKey =Settings.Default.API; //API key required with V2
EpicorRest.APIVersion = EpicorRestVersion.V2; //Defaults to V2

Session = new Session(); //Scoped Session variable

public Login(stirng user, string password)
{
    EpicorRest.UserName = user; //Epicor Username
    EpicorRest.Password = password; //Epicor Password

    var getEnvironemtn = EpicorRest.GetEnvironment();
    if (all is good)
    {
        Session.CurrentUser = user;
    }
    //Reset Class Back to Impesonation Account
    EpicorRest.UserName = Settings.Default.User; //Epicor Username
    EpicorRest.Password = Settings.Default.Password; //Epicor Password

}


public MakeACall()
{
    EpicorRest.ImpersonateUser = Session.CurrentUser;
    var result = EpicorRest.BaqGet("zCustomer01");
}
1 Like

I can think of (2) instances where this may not work. Both are timing issues.

More than 1 user logging in at the same time (low probability)
More than 1 user making rest calls at the same time while logged into different instances - Production vs Test environments (higher probability especially during program changes / testing)

A scoped instance would solve both of these.

If you are going to be connecting to multiple Epicor instances I’d recommand two running instances of the app
prod.app.tld, and dev.app.tld

Much easier to manage than also passing in the Epicor / Host and API keys on every call… That failing

You can make your own HTTP calls and deal with the Epicor stuff directly too if that’s the case, it isn’t hard the library is just making it easier (for some) but if it doesn’t work for what you need then implement HttpClient

That is my next direction. Thanks for your help.

Truly appreciate you @josecgomez !

Where can I find more information about impersonation? What does it show in changelogs?

The Office Wig GIF

In the change logs it shows the user that was impersonated in my experience but I’d test it throughly or be sure

1 Like

Your Task Agent does impersonation. If you check what is logged on jobs, I’m sure it will confirm Jose’s statement.

Hm, I guess that means if I ever have time I could make my REST based configurator have it show the user running the configurator changing the price/description,etc. Learn something every day