We have a few standalone programs that use Epicor DLLs when writing back to the database. However, my current methods kill the active client session is the user has one open. We are license constrained, so enabling users to use multiple sessions isn’t a viable options. Are there any options that don’t require a user license, or is there a way to piggy back the current active session?
ERP10.1.500.18, single sign on
-- here's one way that we have used to get a XFileRef object for attaching docs
epiSession = new Ice.Core.Session(gUsername, gPassword, Ice.Core.Session.LicenseType.DataAdministration, gSysConfigFile);
oTrans = new ILauncher(epiSession);
x = new XFileRefAdapter(oTrans);
x.BOConnect();
-- here's another that creates a Labor object
SessionModImpl sessionModImpl = CreateBusObj<SessionModImpl>(Guid.Empty, SessionModImpl.UriPath);
Guid sessionId = sessionModImpl.Login();
sessionModImpl.SessionID = sessionId;
sessionModImpl.SetCompany("my company", out companyName, out plantID, out plantName, out workstationID, out workstationDescription, out employeeID, out countryGroupCode, out countryCode, out tenantID);
ClassAttributeImpl classAttributes = CreateBusObj<ClassAttributeImpl>(sessionId, ClassAttributeImpl.UriPath);
LaborImpl laborImpl = CreateBusObj<LaborImpl>(sessionId, LaborImpl.UriPath);
Any thought on redesigning your standalone as a web application? Users submit transactions to your webapp, the app logs in, performs the transaction, and logs out (or just changes users and leaves the session open).
Once you upgrade to newer releases, you can refactor this for REST calls instead of using the DLLs, which will be easier to maintain as you upgrade.
Looking at what Epicor is doing now with Active Desktop and Mobile CRM, this seems to be the new model. Just a thought…
I am not the client customization expert by any means but definitely can talk to the wire, back end and the Session handling
If you can obtain the current SessionID from the client you should be able to pass that to the server and piggy back on the existing session. That can be done in a variety of ways based upon legacy ‘Impl’ approach shown above or via REST as mentioned by Mark.
The server simply sees a call, looks if there is a sessionid, looks up the session in cache and compares credentials (To limit someone stealing your credentials). If the session matches, it restores the cached state from memory (Current company, plant, employee, etc) and moves on with the call.
If you are getting a second session stood up on the server then something is out of sync. Are you sure that you are simply not cleaning up the session? For example, if this was truly a stand alone client.exe you threw together, you would have to dispose the Session or call ‘logout’ on the server to reclaim the session.
I recommend turning on the session trace in appserver.config and monitor what is happening on the server - check for the commented out ‘session’ trace entry in appserver.config in your server.
It seems passing the session ID would be the easiest fix. I can see the session list in the table Ice.SessionState, but I can’t seem to figure out where it indicates which is active. For now, I’m just using the one with the latest expiration date for a given user.
@Bart_Elia - I want to make sure we’re on the same page because I think your suggestion is my ticket past this issue. My intent is to let the Epicor.exe continue to do its thing while the user uses the custom app to do other things. They can both use the same session concurrently, right? In some preliminary testing, users are still getting their current Epicor client session invalidated. I’m not sure if I’m passing the wrong session ID or if I’m making some wrong assumptions as to what I can and can’t do.
From my previous code, I’m passing in a session ID in to the SessionModImpl declaration if one is available.
private Guid GetCurrentSession()
{
string sql = string.Format("SELECT TOP 1 SessionID FROM ERP101500.Ice.SessionState WHERE UserID = '{0}' AND SessionType = '{1}' ORDER BY LicenseExpirationTime DESC",
Environment.UserName.Replace(@"MyDomain\", ""), ConfigurationManager.AppSettings["ERP_DefaultUser_GUID"]); // ERP_DefaultUser_GUID = 00000003-B615-4300-957B-34956697F040 - from Ice.SessionState
string result = SqlExecuteScalar(sql);
gSessionPiggyBack = false;
if (result != null && result != "")
{
gSessionPiggyBack = true;
return new Guid(result);
}
return Guid.Empty;
}
One option would be for your DLL to implement iLaunch and be Launched from within the Epicor menu and pass the current license in? Would this be something that could work for you?
This is a standalone executable - Epicor DLLs are compiled in (not the best option for upgradability, but it’s what we have right now). I’ve never dabbled in creating DLLs, but I assume that’s probably a bit beyond what I’m trying to do here. ??
I mean DLL and an Exe are essentially the same thing. Just a bit of compiled code. If you write a DLL which takes in and implements iLaunch interface and iTransaction you can pass in the session directly from Epicor…
If you are NOT running ‘allow multiple sessions’ then the second session replaces the first - that’s by design in case the first session crashes. We had users crash a client, get disconnected, whatever and then they were locked out.So we moved to a ‘replace’ algorithm to be more end user friendly.
The Session State table is a cache - it is optional to be honest. The real authority of what is in Session is in the app server(s) themselves. The notification system keeps them in sync. We even played with adding a real external cache - App Fabric caching or memcached but dropped due to complexity (complexity/reward showed a bad result). The table cache is not intended for direct use as in E9/V8 days. The old approach was too hard on the db and could not scale.
On the client, you have a sessionID. Use it when standing up new Impls. On the server, you can find your sessionID but you don’t need it. If you want to invoke other services, use the ServiceRenderer hepler.
Hey @steve_j check out this quick video I put together about how to do this
I just uploaded this so it’ll take a few mins to be available in HD
You’ll need these 3 classes
Launch.cs
using Ice.Lib.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ice.Lib.App
{
public class Launch : EpiBaseLaunch
{
protected override void InitializeLaunch()
{
base.lTrans = new EpicorCustomDLL.Transaction(this);
base.lForm = new EpicorCustomDLL.MyCustomForm(base.lTrans);
}
}
}
Transaction.cs
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace EpicorCustomDLL
{
public class Transaction : Ice.Lib.Framework.EpiSingleViewTransaction
{
public Transaction(object Sender): base(Sender)
{
}
public override void TransactionLoad()
{
;
}
protected override void Delete(DataRow dr)
{
throw new NotImplementedException();
}
protected override void GetByID(string id)
{
throw new NotImplementedException();
}
protected override void GetNew()
{
throw new NotImplementedException();
}
protected override void Update()
{
throw new NotImplementedException();
}
}
}
MyCustomForm.cs
using Ice.Lib.Framework;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace EpicorCustomDLL
{
public partial class MyCustomForm : EpiBaseForm
{
EpiTransaction oTrans;
Ice.Core.Session _currSession;
public MyCustomForm(EpiTransaction iTrans):base(iTrans)
{
InitializeComponent();
oTrans = iTrans;
_currSession = (Ice.Core.Session)iTrans.Session;
}
private void btnMyCustomButton_Click(object sender, EventArgs e)
{
MessageBox.Show($"Current User:{_currSession.UserID} Current Session ID:{_currSession.SessionID} Current Plant:{_currSession.PlantID}");
}
}
}
I hope this helps, note this is way more advanced than a standard customization and I recommend you try and do all your projects within the bounds of the standard framework. Having a custom DLL to lug around is annoying at best and a maintenance nightmare.
@josecgomez Is it possible to get the EpiTransaction without using a form in a custom dll that is executed in a data directive in order to send it to my API? I need to use the DynamicQueryImpl BO in my server app. or I can use the DynamicQueryImpl without with just normal session object?
We had the same problem with an integration hogging sessions. The key is that Ice.Core.Session implements Disposable. Our problem was solved by changing
var session = EpicorClient.EpicorGlobals.GenerateSession();
...