How to call non public method of Acumatica

Hello everybody,

today I want to share with you how it's possible to call some methods of Acumatica, which are not public, and which you don't want to copy/paste completely into your source code. In that case reflection will save you. Consider calling of InsertSOAdjustments method of graph SOOrderEntry below.

MethodInfo invokeSOAdjustment = typeof(SOOrderEntry).GetMethod(
    "InsertSOAdjustments"BindingFlags.Instance | BindingFlags.NonPublic, Type.DefaultBinder,
    new[] { typeof(SOOrder), typeof(ARPaymentEntry), typeof(ARPayment) }, null);
 
invokeSOAdjustment.Invoke(Base, new object[] { orderdocgraphpayment });

Also I want to give you a word of warning, that such approach potentially will not be certified, and another way of usage will be the one below:

In extension of SOOrderEntry create lines like those:

[PXOverride]
public void InsertSOAdjustments(SOOrder orderARPaymentEntry docgraphARPayment payment,
    Action<SOOrderARPaymentEntryARPaymentbaseAction)
{
    baseAction(orderdocgraphpayment);
}

and then just call InsertSOAdjustments method whenever you'll have a need for this.

Summary

Because Acumatica is written with C# which is very powerful language which gives you a lot of features you can easily achieve a lot of thigs, also be careful with usage of reflection. Somtime even more then Acumatica team anticipated themselves.

How to create plugins that can be loaded/unloaded

Hello everybody,

today I want to show sample of code that you can use for your plugins.

Sometime it can happen that you have some application with it's dlls and you can decide to make ad hoc dlls.

In order to demonstrate how to do it I prepared following code:

Create first class library as BaseLib:

using System;
 
namespace BaseClass
{
    public class BaseClass : MarshalByRefObject
    {
        public virtual bool IsProcessable(string message)
        {
            return true;
        }
 
        public virtual void Process(string message)
        {
            
        }
    }
}

Then create following implementation:

using System;
namespace Ext1
{
    public class Extension1 : BaseClass.BaseClass
    {
        public override bool IsProcessable(string message)
        {
            return true;
        }
 
        public override void Process(string message)
        {
            message = message + " 1 " + message;
            Console.WriteLine(message);
        }
    }
}

And then code like this will give you possibility to load/unload dlls:

using System;
using System.IO;
using System.Reflection;
 
namespace MarshalByRef
{
    class Program
    {
        static void Main(string[] args)
        {
            AppDomain ad = AppDomain.CreateDomain("extensions");
            string testDlls = @"d:\sources\MarshalByRef\MarshalByRef\destDlls\";
            string dest = @"d:\sources\MarshalByRef\MarshalByRef\MarshalByRef\bin\Debug\" + "Ext1.dll";
            File.Copy(testDlls + "Ext1.dll", dest, true);
 
            Loader loader = (Loader)ad.CreateInstanceAndUnwrap(typeof(Loader).Assembly.FullName, typeof(Loader).FullName);
            loader.LoadAssembly(dest);
            loader.Execute();
            //if you try to delete Ext1.dll you'll got an error
            AppDomain.Unload(ad);
            //if you try to delete Ext1.dll now, you'll be successfull
            Console.ReadKey();
        }
    }
 
    class Loader : MarshalByRefObject
    {
        private Assembly _assembly;
 
        public void LoadAssembly(string path)
        {
            _assembly = Assembly.Load(AssemblyName.GetAssemblyName(path));
        }
 
        public void Execute()
        {
            var instance = _assembly.CreateInstance("Ext1.Extension1"as BaseClass.BaseClass;
            instance.Process("test");
        }
    }
}

How to check if type in Assembly implements particular Interface

Hello everybody,

today I want to give sample of reading available types from dll .net assembly, check if at least one of them implements interface, and if implements then to create instance of that type and return it. 

So, imagine you have such interface declaration in your code:

public interface ILogger
    {
        /// <summary>
        /// Convert <see cref="LoggerMessage"/> to string based on the formats specified.
        /// </summary>
        /// <param name="message">The message to be converted.</param>
        /// <returns>Converted <paramref name="message"/>.</returns>
        LoggerMessage Handle(LoggerMessage message);
 
        bool Handlable(LoggerMessage message);     
}

and following implementation of this interface:

public class LoggerDateTimeAdder : ILogger
    {
        public LoggerMessage Handle(LoggerMessage message)
        {
            message.AppendAdditionalInfo("start"DateTime.Now);
            return message;
        }
 
        public bool Handlable(LoggerMessage message)
        {
            return true;
        }
    }

Then you can use following function in order to read your dll and create instance of LoggerDateTimeAdder:

ILogger LoadFromAssembly(string assmFileName)
{
    ILoggerItemFormatter result = null;
    var assembly = Assembly.LoadFile(assmFileName);
 
    foreach (Type exportedType in assembly.ExportedTypes)
    {
        if(typeof(ILogger).IsAssignableFrom(exportedType))
        {
            result = assembly.CreateInstance(exportedType.FullName) as ILogger;
            break;
        }
    }
    return result;
}