Company Change Approaches on the Server


(Haso Keric) #41

It seems so and here we are doing Service Connect and dropping single-line .csv’s for “Simple Stuff”. Like go to Company 004 and Update 1 Column. Sigh :slight_smile: good to know… I tried Db.Validate() and it works.

It makes sense, when you run it in LINQPad you technically run as NO User. I didnt know if Epicor was wrapping in some Security around Db Context like it does with Cross-Company BAQs.


(Jose C Gomez) #42

Yeah Db is just the EF Context it has no security around companies as far as I can tell. it is straight up EF with some sprinklings of Epicor… that’s why they don’t let you anywhere near that in SaaS MT (I even tried via reflection cough… but those clever clever epicor boys block access to GetType() and all other Reflection functions specifically. :cry:


(Bart Elia) #43

Correct on all the above. DBContext is evil and powerful.

It’s why I encourage REST / OData type semantics for doing things. DBContext is too powerful to leave lying around in ignorant hands :slight_smile:


(Haso Keric) #44

So back to the TemporarySession code, that is only handy if you are calling “Business Objects” if you are directly going to the Db Context then no need to switch session?


(Jose C Gomez) #45

Bingo! though you should only “Read” in that context and “write” to UD fields/tables… but anything beyond that makes me a sad panda
image


(Haso Keric) #46

Agreed, you shouldn’t be inserting Part’s and ShipHead Rows via Db Context - because the BO usually triggers other BPMs which you don’t trigger by using Db Context and it may cause corrupt db… typically okay to update a Description or a UD Field or Insert UD100 Rows.

In that case us a TemporarySession or Service Connect and do so via the proper BO Calls.


(Bart Elia) #47

Don’t forget service renderer. That allows you encapsulation and optional firing of bpm based on your needs


(Haso Keric) #48

You mean by enabling/disabling triggers? or simply calling EngWkBenchService.Update(ref EngWorkBenchDataSet);


(Haso Keric) #49

@Bart_Elia Back to the TemporarySession:

CallContext.Current.TemporarySessionCreator.SetUserID("manager").SetCompanyID("00300000").Create()

This code above works if the CallContextClient User has access to 00300000. Also Impersonation must be allowed to impersonate manager. However, when a user does not have access, despite having Impersonation rights it will complain that xxx does not have access. I assume the only way to execute a “BO” as a different user, in my case a Service Account User is to create a new Session via Ice.Lib.SessionMod? (Cant use TemporarySession). [ Just Testing the Mechanics of it ]

SetUserID just Impersonates, but does not actually log-in as that user.


One thing to note is that TemporarySessionCreator executes fine when running your BPM as “ASYNC” and letting the Task agent via user Print execute it.

CallContext.Current.TemporarySessionCreator.SetUserID("manager").SetCompanyID("00300000").Create()

So only question remains is, how to do it as synchronous?


Perhaps I don’t use SetCompanyID:

        public TemporarySessionFluentFactory SetCompanyID(string companyID)
        {
            if (SysUserCompCache.GetSysUserComp(this._parentSession.UserID, companyID) == null)
            {
                throw new EpicorServerException(Strings.InvalidCompanyForUser(companyID, this._parentSession.UserID));
            }
            this.Settings.CompanyID = companyID;
            return this;
        }

Settings is public, perhaps just set it myself avoiding the exception.


(Haso Keric) #50

Awww same Error… :smiley:

var s = CallContext.Current.TemporarySessionCreator;
s.Settings.CompanyID = "00300000";

using (s.Create()) { }

2018-09-07_1600

I’ll keep trying a few more things such as using:

        public Epicor.Hosting.Session StartTemporarySession(SessionSettings settings)
        {
            Epicor.Hosting.Session item = new Epicor.Hosting.Session(Current.Session.Settings, settings);
            this.sessions.Push(item);
            return item;
        }

By the way Bart i see the Push and Pop - showing as you stated before that it just pushes it on the Stack.


(Bart Elia) #51

I mean when you call ServiceRenderer you can bypass Method Directives by ignoring the facades:

public interface IEpicorServiceRenderer
{
TService GetService(IceDataContext context, bool ignoreFacade = false)

Sometimes you need to, sometimes not. Depends on the use case.


(Bart Elia) #52

Yea if you don’t have access to the company, you are not getting in period. You need either impersonation or some kind of process to act as a proxy to get in.

What’s the use case?


(Haso Keric) #53

So I could use SessionMod and instantiate a brand new session object? Just the usual use-case, I need to simply as a User do something very simple in a “Main Company” without giving the User full access to our Master Company… Something that can be done via Service Connect, but if I run the BPM as “async” it can also be done in a BPM just fine. I was just wondering If I could do it in a “synchronous” BPM and provide the user “instant feedback” of success or failure. I can read “Main Company” data via DbContext which is cool. I can also update minor fields such as certain boolean fields just fine via DbContext. But when it comes to actually running several BO Methods through then I need a session.

Again having a “Master Company” with Master Data and not everything can feed up or down via Multi-Company process, this is where it would come in-handy (use case).

I think I have enough info to go with. Async will work, Service Connect is an option, DbContext in many cases is an option.


(Haso Keric) #54

@Bart_Elia By the way these methods work perfect in a Customization and they are fast, little to no session initialization (loading): which is also an option

Prototype Code, Needs a little Refactoring… but gist:
Runs BAQ via BO or Adapter as a SA_GLOBAL User… License is requested and also released properly.

public System.Data.DataSet GetBAQDataSetDataTagFromMainCompany_BO(string partNum, string partRev)
{
	System.Data.DataSet results = null;

	try
	{

		using (var newSession = new Ice.Core.Session("SA_GLOBAL", "ChrisConnPie!"))
		{
			removeEventhandlers(newSession);

			// Declare and Initialize Variables
			string BAQName = "SMI-zGetDataTagByPartRev";
			Ice.BO.QueryExecutionDataSet ds = new Ice.BO.QueryExecutionDataSet();

			// Add Parameter Rows
			ds.ExecutionParameter.AddExecutionParameterRow("PartNum", partNum, "nvarchar", false, Guid.Empty, "A");
			ds.ExecutionParameter.AddExecutionParameterRow("RevisionNum", partRev, "nvarchar", false, Guid.Empty, "A");

			// Use Business Object Directly
			Ice.Proxy.BO.DynamicQueryImpl dynamicQuery = Ice.Lib.Framework.WCFServiceSupport.CreateImpl<Ice.Proxy.BO.DynamicQueryImpl>(newSession, Epicor.ServiceModel.Channels.ImplBase<Ice.Contracts.DynamicQuerySvcContract>.UriPath);
			results = dynamicQuery.ExecuteByID(BAQName, ds);

			// var mod =(Ice.Proxy.Lib.SessionModImpl)sessionx.Variable("sessionMod");
			// mod.Logout();

		}

	}
	catch (System.Exception ex)
	{
		ExceptionBox.Show(ex);
	}

	return results;
}

Adapter Version:

public System.Data.DataSet GetBAQDataSetDataTagFromMainCompany_ADAPTER(string partNum, string partRev)
{
	using (var newSession = new Ice.Core.Session("SA_GLOBAL", "ChrisConnPie!"))
	{

		ILauncher iLnch = new ILauncher( newSession );

		using (var newTransaction = new EpiTransaction(iLnch))
		using (var adapterDynamicQuery = new DynamicQueryAdapter(newTransaction))
		{
			adapterDynamicQuery.BOConnect();

			// Declare and Initialize Variables
			string BAQName = "SMI-zGetDataTagByPartRev";
			Ice.BO.QueryExecutionDataSet ds = new Ice.BO.QueryExecutionDataSet();

			// Add Parameter Rows
			ds.ExecutionParameter.AddExecutionParameterRow("PartNum", partNum, "nvarchar", false, Guid.Empty, "A");
			ds.ExecutionParameter.AddExecutionParameterRow("RevisionNum", partRev, "nvarchar", false, Guid.Empty, "A");

			// Call Adapter method
			adapterDynamicQuery.ExecuteByID(BAQName, ds);

			System.Data.DataSet results = adapterDynamicQuery.QueryResults;
			return results;
		}

		// Cleanup Adapter Reference
		//adapterDynamicQuery.Dispose();
	}


	return null;
}