Страницы

Поиск по вопросам

среда, 18 декабря 2019 г.

Подключение DLL расположенную на сервере в свою программу C#

#c_sharp #dll


Возникла потребность вынести часть кода на сервер в виде библиотеки DLL. Задача скачать
DLL в память, и из памяти использовать методы DLL.
По своей задаче нашёл один ответ, но как вызвать свой метод мне не понятно.

WebClient webClient = new WebClient();
byte[] assemblyBytes = webClient.DownloadData("https://mysite.com");
var assembly = Assembly.Load(assemblyBytes);
var types = assembly.DefinedTypes;


Как вызвать методы DLL скачанной в память ?
К примеру DLL написан на C# и имеет такою структуру.

class myClass
{
    public static int GetSum(int arg)
    {
        return arg;
    }

    public static int GetNum(int arg)
    {
        return arg;
    }

    public static int GetId(int arg)
    {
        return arg;
    }
}

    


Ответы

Ответ 1



Пример вызова статического метода: var type = assembly.GetType("Namespace.TypeName"); var method = type.GetMethod("StaticMethod"); var result = method.Invoke(null, new object[] { param1, param2 }); Но лучше всего будет задать некий интерфейс/базовый класс в вашей программе, а класс в скачиваемой длл должен реализовать интерфейс/наследовать класс. Например вот так: // интерфейс в вашей программе public interface IRemote { int DoSomething(string param1, int param2); } // его реализация в скачиваемой длл, она должна иметь референс на вашу программу public class RemoteClass : IRemote { public int DoSomething(string param1, int param2) { Console.WriteLine(param1); } } И дальше вы делаете так: var type = assembly.GetType("Namespace.RemoteClass"); var remote = (IRemote)Activator.CreateInstance(type); remote.DoSomething("qwerty", 100); Преимущества этого подхода в том, что вам не нужно каждый метод получать при помощи GetMethod, и исключаются ошибки, когда передаются неправильные параметры при вызове MethodInfo.Invoke.

Ответ 2



Если с задачей загрузки DLL в память вы уже справились, то дело осталось за малым. Предположим, что пример кода, приведенный вами рабочий: WebClient webClient = new WebClient(); byte[] assemblyBytes = webClient.DownloadData("https://mysite.com"); var assembly = Assembly.Load(assemblyBytes); И в результате выполнения данного кода мы получили сборку в переменную assembly. Теперь, основываясь на знании имени типа и вызываемого метода, можно получить тип и вызвать из него метод следующим образом: // получим тип (мы знаем его имя - myClass) Type type = assembly.GetType("myClass"); // создадим экземпляр объекта заданного типа var obj = Activator.CreateInstance(type); // вызовем метод из полученного экземпляра у заданного типа type.InvokeMember( "GetSum", BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, null, obj, new Object[] {5} ); Чтобы все отработало успешно, нужно учитывать некоторые нюансы. У типа myClass либо не должно быть вообще конструкторов, чтобы беспараметрический конструктор по умолчанию за нас создала CLR, либо должен быть один беспараметрический конструктор, чтобы Activator.CreateInstance смог зоздать экземпляр объекта. Также, имена типов должны быть корректны, при несовпадении будет ошибка. Последний параметр у метода Type.InvokeMember - это массив с аргументами, передаваемыми вызываемому члену (методу).

Ответ 3



Если нужная библиотека известна на этапе компиляции - на нее можно сослаться точно так как как и на любую другую. Только не забудьте удалить ее из выходной директории (например, через Post Build Event) когда компилятор ее туда автоматически скопирует. Или, для тех кто знаком с MSBuild, можно поиграться с метаданными Reference. Чтобы загрузить такую сборку с сервера, вам нужно будет: подписаться на событие AppDomain.CurrentDomain.AssemblyResolve и вернуть сборку когда CLR попытается загрузить ее и не найдет; убедиться что ни один из ваших методов, вызываемых до загрузки сборки, не ссылается на классы из той сборки. Вот так работать не будет: void Foo() { AppDomain.CurrentDomain.AssemblyResolve += ...; myClass.getId(0); } А вот так - будет: void Foo() { AppDomain.CurrentDomain.AssemblyResolve += ...; Bar(); } void Bar() { myClass.getId(0); }

Комментариев нет:

Отправить комментарий