Customization new extern alias

In 10.1.600.X Customization it includes this at the top of most every customization
image

Just wondering why they are there, and what they are for?

@Bart_Elia @Edge any insights?

1 Like

I tried internally and didn’t get that behaviour so can you confirm if it is in all forms or some? I have raised the question internally though.
What exact version are you seeing this on

1 Like

I made it show that by opening Cust Ship Entry switching to VB and then back to C#

10.1.600.6
Just happens on any customization, just go to code Editor (Top above usings) @Edge

1 Like

Below are the details and this should help those that have had the issue, note I will be asking our team to get this into a KB article.

SCR#190771 - Namespace Conflicts

Problem:
In Customer Shipment Entry, when the following line of code is added to the InitializeCustomCode Section:

Erp.BO.PackOutDataSet.PackOutRow test = null;

the following Compile Error is received when Tools > Test Code is selected:

Error: The type Erp.BO.PackOutDataSet’ exists in both Erp.Contracts.BO.CustShip.dll and Erp.Contracts.BO.PackOutSearch.dll

Root Cause:
The actual problem is with the automatic BO generator. Whenever a BO is generated, the business classes get generated under Erp.BO namespace. However, they should’ve been generated under assembly specific namespace (e.g. Erp.BO.CustShip). So, if two BO’s refer same table, then corresponding business type is generated in both BOs with same name. Due to the very same reason, PackOutDataSet class exists in both Erp.Contracts.BO.CustShip.dll as well as Erp.Contracts.BO.PackOutSearch.dll

Resolution:
The ideal solution is to move all types within their assembly specific namespaces. fix the BO generator code so that the types are generated under assembly specific namespaces instead of Erp.BO namespace. Then, in the above mentioned case, PackOutDataSet class would reside under different namespaces i.e. Erp.BO.CustShip.PackOutDataSet and Erp.BO.PackOutSearch.PackOutDataSet, so no conflict would occur.

But, at this time, that may not be possible because, it could break existing customizations.

So, the other solution would be to assign an alias to such assemblies which contain conflicting types. Then when refering to such types, use extern alias to resolve the ambiguity.

Design:
Assign the alias to assemblies: In CustomCodeManager class of EpiClientLib, after adding references to custom assembly, listout all assemblies that contain conflicting types. Then assign an alias to each of those assemblies via below compiler option:

/r:<alias>=<assemblyPath>

The alias name would be same as assembly name with dot(.) replaced by underscore(_).

For example, alias for Erp.Contracts.BO.CustShip.dll would be Erp_Contracts_BO_CustShip.

After this, generate the extern alias statements for each of the assemblies in custom code. These statements should be at the top of any code.

If an user gets an error like the one mentioned in problem statement, he/she has to just prepend the alias name to the type. For example, In the problem statement, Erp.BO.PackOutDataSet is confliting type. So, it has to be modified as:

Erp_Contracts_BO_PackOutSearch::Erp.BO.PackOutDataSetPackOutRow test = null;

OR

Erp_Contracts_BO_PackOutSearch.Erp.BO.PackOutDataSetPackOutRow test = null;

Other Design Considerations:
Assembly Reference Manager: If the user adds reference to the custom assembly via custom assembly manager, the system shall automatically validate for conflicting type(s). If yes, then system shall automatically assign alias nd generate the extern alias statement. Also, if the user removes a custom assembly reference, then if there are any corresponding extern alias statements, then they shall be removed from the custom code.

Toggle between VB.NET to C#: If the user switches from C# code to VB.NET, the all extern alias statements would removed from VB.NET custom code. And if the code is switch from C# to VB.NET, then the extern alias statements, if any, will be added to custom code.

Note:
VB.NET does not fully support extern aliasing. So, the above mentioned solution design works only if the selected customization language is C#.

References:
extern alias (C# Reference): https://msdn.microsoft.com/en-us/library/ms173212.aspx
compiler options: C# Compiler Options - input file options - C# | Microsoft Learn

7 Likes

Thank you @Edge!
Moving to experts corner
Cheers

Many thanks sir!

Following on to this - it’s not as simple as changing scopes on the datasets to :
Erp.BO.CustShip.PackOutDataSet and Erp.BO.PackOutSearch.PackOutDataSet

What happens when both CustShip service and PackOut service both call into an internal helper library and pass the PackOutDataSet?
e.g.
public class Foo
{
public void Bar(Erp.BO.[XYZ].PackOutDataSet ds) {}
}

Someone will get a type mismatch since dotnet will now note them as the different Types.

The ultimate solution is defining interfaces over the datasets and tables in system:
interface Epicor.IPackOutDataSet
{
//all the tables and columns
}

and implementing them on the sets:
public class Erp.BO.CustShip.PackOutDataSet : Epicor.IPackOutDataSet {}
public class Erp.BO.PackOutSearch.PackOutDataSet : Epicor.IPackOutDataSet {}

Then the internal library can consume either if it CHANGES the method signature to the new Type:
public class Foo
{
public void Bar(Epicor.IPackOutDataSet ds) {}
}

Note I emphasize the Change aspect. We’ll have to break some signatures so need to handle that carefully.with proper testing. Anyone using these libs in bpms and internal might be effected if we miss so scenarios need to be walked to ensure we don’t break customizations and people throw things at me :slight_smile:

4 Likes