powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
19 сообщений из 19, страница 1 из 1
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39806975
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго времени суток.

.Net Framework 4.8. Можно ли как-то сделать так, чтобы прокси, получаемые для объектов, инициализированных в другом домене (AppDomain), имитировали не только методы и свойства целевого объекта, но и предоставляли информацию о пользовательских атрибутах класса?

Я объявил атрибут:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
// Сборка AntCore.dll (для совместного использования приложением и плагинами)
using System;

namespace Ant.Core
{
    [Serializable]
    [AttributeUsage(AttributeTargets.Class)]
    public sealed class CommandIdAttribute: Attribute
    {
        public CommandIdAttribute(string guid)
        {
            Id = Guid.Parse(guid);
        }

        public Guid Id { get; }
    }
}



Затем класс, его использующий:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
// Сборка AntPluginExample1.dll
using System;
using System.Threading;
using Ant.Core;
using static System.Console;
namespace AntPluginExample1
{
    [Serializable]
    [CommandId("{382F5A14-9A96-4A05-80B3-10FE170B59DE}")]
    public sealed class HelloWorld : MarshalByRefObject, ICommand
    {
        public void Dispose()
        {
            WriteLine("Command disposed");
        }

        public void Execute()
        {
            WriteLine($"Domain: {Thread.GetDomain().FriendlyName}");
        }
    }
}



В консольном приложении загружаю сборку AntPluginExample1.dll в отдельный домен. Затем создаю экземпляр ICommand и пытаюсь посмотреть кастомные атрибуты у типа:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
// Приложение, загружающее каждый плагин в свой AppDomain 
// и использующий его команды.
using System;
using System.Linq;
using System.Threading;
using Ant.Core;
using static System.Console;

namespace Ant.CLI
{
    class Program
    {
        static void Main(string[] args)
        {
            Title = "Ant CLI";
            WriteLine($"Current domain: {Thread.GetDomain().FriendlyName}");
            var domain = AppDomain.CreateDomain("AD #2", null, null);
            using (var command = (ICommand)domain.CreateInstanceAndUnwrap(
                "AntPluginExample1, version=1.0.0, culture=neutral, PublickKeyTocken=null",
                "AntPluginExample1.HelloWorld"))
            {
                command.Execute();
                var t = command.GetType();
                WriteLine($"command type: {t}");
                WriteLine("Attributes:");
                foreach(var att in t.CustomAttributes)
                {
                    WriteLine($"\t{att.AttributeType.Name}");
                }
            }
            AppDomain.Unload(domain);
            WriteLine("Press ENTER for exit...");
            ReadKey();
        }
    }
}



Однако вижу, что по факту у сгенерированного прокси присутствует только один атрибут - SerializableAttribute:

Код: powershell
1.
2.
3.
4.
5.
6.
7.
Current domain: AntCLI.exe
Domain: AD #2
command type: AntPluginExample1.HelloWorld
Attributes:
        SerializableAttribute
Command disposed
Press ENTER for exit...



Можно ли как-то сделать так, чтобы прокся имитировала и атрибуты?

С уважением, Андрей
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39807245
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Нет. Вы грузите из внешней сборки конкретный тип по текстовому полному имени. Атрибут это тоже конкретный тип, который мало того, что вы не грузите, так и ещё не знаете о нём, он может лежать где угодно.

Во-вторых, решение лежит на поверхности:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
    public interface ICommand
    {
        public void Dispose();
        public void Execute();
        public Guid GetCommandId();
    }

    public abstract class CommandBase : MarshalByRefObject, ICommand
    {
       public virtual Guid GetCommandId()
       {
           this.GetType().GetCustomAttribute<CommandIdAttribute>()?.Id ?? default(Guid);
       }

       public abstract void Dispose();
       public abstract void Execute();
    }


    [Serializable]
    [CommandId("{382F5A14-9A96-4A05-80B3-10FE170B59DE}")]
    public sealed class HelloWorld : CommandBase
    {
        public override void Dispose()
        {
            WriteLine("Command disposed");
        }

        public override void Execute()
        {
            WriteLine($"Domain: {Thread.GetDomain().FriendlyName}");
        }
    }



Получаем ID:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
using System;
using System.Linq;
using System.Threading;
using Ant.Core;
using static System.Console;

namespace Ant.CLI
{
    class Program
    {
        static void Main(string[] args)
        {
            Title = "Ant CLI";
            WriteLine($"Current domain: {Thread.GetDomain().FriendlyName}");
            var domain = AppDomain.CreateDomain("AD #2", null, null);
            using (var command = (ICommand)domain.CreateInstanceAndUnwrap(
                "AntPluginExample1, version=1.0.0, culture=neutral, PublickKeyTocken=null",
                "AntPluginExample1.HelloWorld"))
            {
                command.Execute();
                var commandId = command.GetCommandId();
            }
            AppDomain.Unload(domain);
            WriteLine("Press ENTER for exit...");
            ReadKey();
        }
    }
}



Попробуйте, я не проверял :)
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39807281
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttАтрибут это тоже конкретный тип, который мало того, что вы не грузите, так и ещё не знаете о нём, он может лежать где угодно.
Ну почему же не знаю? Ведь я же сборку, в которой определены атрибут CommandIdAttribute и интерфейс ICommand , загружаю как в основной домен приложения (в методе Main() я выполнял явное приведение прокси к типу ICommand ), так и в тот AppDomain , с которым взаимодействую посредством прокси. Т.е. эти типы известны по обе стороны.

hVosttПопробуйте, я не проверял :)

Спасибо, :) Я тоже думал о подобном решении, но надеялся, что получать информацию об атрибутах из проксей каким-то образом всё же можно. Да, наверное так и придётся поступать. Ещё раз спасибо за ответ :)
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39807327
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumТ.е. эти типы известны по обе стороны.

Известен интерфейс на уровне ссылке на общую сборку.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39807403
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хм. FW 4.7.1, всё в точности так, как описано выше, только для чистоты эксперимента интерфейс ICommand вынесен еще в одну сборку, и главный проект имеет референс только на неё, на сборку с классом атрибута у главного проекта референса нет:
Консольный вывод:

Код: plaintext
1.
2.
3.
4.
5.
6.
Current domain: test3.exe
Domain: AD #2
command type: AntPluginExample1.HelloWorld
Attributes:
        SerializableAttribute
        CommandIdAttribute
Command disposed
hVostt
Код: c#
1.
2.
3.
4.
5.
6.
    public interface ICommand
    {
        public void Dispose();
        public void Execute();
        public Guid GetCommandId();
    }


Попробуйте, я не проверял :)
Это видно :)
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808014
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны
Код: plaintext
1.
SerializableAttribute
        CommandIdAttribute

Ого... Подтверждаю. Странно... Вот уж не ожидал такого сюрприза.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808015
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры ПавловныХм. FW 4.7.1
В 4.7.2 тоже всё норм. Проблема только в 4.8.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808024
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

На этом странности не закончились: переключился обратно на .Net 4.8 и... Всё работает! Я не знаю что это было.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808078
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumЯ не знаю что это было.
Можно попробовать воспроизвести начальную ситуацию (когда искомого атрибута нет), и распотрошить сборку плагина ildasm'ом.
У меня это выглядит так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
.class public auto ansi sealed serializable beforefieldinit AntPluginExample1.HelloWorld
    extends [mscorlib]System.MarshalByRefObject
    implements [Ant.Interfaces]Ant.Interfaces.ICommand,
               [mscorlib]System.IDisposable
{
    .custom instance void [Ant.Core]Ant.Core.CommandIdAttribute::.ctor(string) = (
        01 00 26 7b 33 38 32 46 35 41 31 34 2d 39 41 39
        36 2d 34 41 30 35 2d 38 30 42 33 2d 31 30 46 45
        31 37 30 42 35 39 44 45 7d 00 00
    )
    ................
}


и в метаданных сборки

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
TypeRef #16 (01000010)
-------------------------------------------------------
Token:             0x01000010
ResolutionScope:   0x23000002
TypeRefName:       Ant.Core.CommandIdAttribute
	MemberRef #1 (0a00000f)
	-------------------------------------------------------
		Member: (0a00000f) .ctor: 
		CallCnvntn: [DEFAULT]
		hasThis 
		ReturnType: Void
		1 Arguments
			Argument #1:  String

- т.е. всё на своих местах, и этого атрибута просто не может не быть. Возможно, в изначально описываемом случае это могло выглядеть как-то иначе.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808141
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Сон Веры Павловны,

Я уверен в том, что это я где-то накосячил и затем исправил (сам не заметив как). :) Правда я так и не понял в чём был этот самый "косяк"... Ну ок, главное - это то, что теперь всё работает.

Вы не в курсе, какой механизм в .NET Core пришёл на смену AppDomain?

В .Net Framework я загружаю каждый плагин в отдельный AppDomain. Это позволяет мне управлять настройками безопасности для каждого плагина индивидуально (если это понадобится), а так же выгружать плагин, если он начтёт работать криво, без необходимости перезагрузки приложения в целом. Хотелось бы такой подход применять и в .Net Core, но, насколько сейчас помню, я получал сообщение о том, что не может быть более одного AppDomain...

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
using System;
using System.Threading;
using Ant.Core;
using System.Linq;
using static System.Console;
using System.Reflection;

namespace Ant.CLI {
    class Program {
        static void Main(string[] args) {
            Title = "Ant CLI";
            var currentMethodName = MethodBase.GetCurrentMethod().Name;

            WriteLine($"Method: {currentMethodName} is working in the " +
                $"'{Thread.GetDomain().FriendlyName}' domain.");

            var domain = AppDomain.CreateDomain("AppDomain #2", null, null);
            var asm = domain.Load("AntPluginExample1, version=1.0.0, " +
                "culture=neutral, PublickKeyTocken=null");
            var cmdInterfaceName = "Ant.Core.ICommand";

            foreach (var tc in asm.ExportedTypes.Where(
                n => n.IsClass && !n.IsAbstract &&
                null != n.GetInterface(cmdInterfaceName))) {
                using (var command = (ICommand)domain.CreateInstanceAndUnwrap(
                        asm.FullName, tc.FullName)) {
                    var t = command.GetType();
                    var cmdAttrib = Attribute.GetCustomAttribute(t,
                        typeof(CommandAttribute)) as CommandAttribute;
                    WriteLine($"Class '{t}':");
                    WriteLine($"\tCommand id: {cmdAttrib.Id}");
                    WriteLine($"\tCommand logical name: {cmdAttrib.LogicalName}");
                    command.Execute();
                }
            }
            AppDomain.Unload(domain);
            WriteLine("Press ENTER for exit...");
            ReadKey();
        }
    }
}
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808159
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumВы не в курсе, какой механизм в .NET Core пришёл на смену AppDomain?
Ответ нашёл у Майкрософта здесь .
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808161
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Не пробовали поработать c MEF, если хочется загружать сборки динамически?

Всё же, несмотря на то, что атрибут таки получить можно, от себя рекомендовал бы работать по контрактам. Хотите, например, получать каталог команд (Type, Id), лучше это делать через выделенный провайдер.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808164
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,
Core это кроссплатформенное приложение. Вроде под десктоп MS еще ничего не сообразил как будет. Поэтому у нас пишут на С++ и Qt.
Про безопасность, то в линуксе она решается другими мерами. Например сертифицированная Ось астра производстра РФ и мандатная система безопасности.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808169
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttНе пробовали поработать c MEF, если хочется загружать сборки динамически?
Не пробовал. :)

hVosttВсё же, несмотря на то, что атрибут таки получить можно, от себя рекомендовал бы работать по контрактам. Хотите, например, получать каталог команд (Type, Id), лучше это делать через выделенный провайдер.
Можете пояснить? У меня слово "контракты" ассоциируется либо как синоним слова "интерфейс", либо с WCF.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808170
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumВы не в курсе, какой механизм в .NET Core пришёл на смену AppDomain?


AssemblyLoadContext. Я уже даже делал простенькую плагинную систему для демо с ним. Каждая сборка-плагин грузится в свою "песочницу" и может иметь свои собственные зависимости, не конфликтуя с другими. Вроде бы в третей коре обещали все это даже упростить.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808179
Фотография Petro123
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttMEF
+1
[Exprort("Shell", typef(ConainerControl))]
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808180
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthatAssemblyLoadContext. Я уже даже делал простенькую плагинную систему для демо с ним. Каждая сборка-плагин грузится в свою "песочницу" и может иметь свои собственные зависимости, не конфликтуя с другими. Вроде бы в третей коре обещали все это даже упростить.

Да, я уже читал про AssemblyLoadContext:
MicrosoftСоздание дополнительных доменов приложений не поддерживается. И мы не планируем добавлять эту возможность в будущем. Вместо нее для изоляции кода мы рекомендуем использовать отдельные процессы или контейнеры. Для динамической загрузки сборок рекомендуется использовать новый класс AssemblyLoadContext.

В материале, касательно AssemblyLoadContext вижу такой фрагмент текста:
MicrosoftAssemblyLoadContext Представляет контекст загрузки. По существу контекст загрузки создает область для загрузки, разрешение и потенциально выгрузки набор сборок .

Не совсем понял слово "потенциально" в данном контексте. Да и "набор сборок" - тоже не совсем понятен. В .Net Framework сборку выгрузить нельзя - можно выгружать только домен целиком. Т.е. складывается впечатление, что на .Net Core можно выгружать отдельно сборку (если посмотреть на неё как на набор, состоящий из одного элемента).
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808190
fkthat
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumНе совсем понял слово "потенциально" в данном контексте. Да и "набор сборок" - тоже не совсем понятен. В .Net Framework сборку выгрузить нельзя - можно выгружать только домен целиком. Т.е. складывается впечатление, что на .Net Core можно выгружать отдельно сборку (если посмотреть на неё как на набор, состоящий из одного элемента).

Не знаю, у них сейчас все что связано с этим как-то почти что не задокументировано. Приходилось гуглить по всяким блогам. У меня было как-то так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
    public class PluginLoadContext : AssemblyLoadContext
    {
        private readonly string _dir;

        public PluginLoadContext(string dir)
        {
            _dir = dir ?? throw new ArgumentNullException(nameof(dir));
        }

        protected override Assembly Load(AssemblyName assemblyName)
        {
            var path = Path.Combine(_dir, assemblyName.Name) + ".dll";
            return File.Exists(path) ? LoadFromAssemblyPath(path) : null;
        }
    }
}


Затем:
Код: c#
1.
2.
3.
4.
var loadContext = new PluginLoadContext(plugin.FolderPath);
var assembly = loadContext.LoadFromAssemblyName(new AssemblyName(plugin.Assembly));
var pluginType = assembly.GetType(plugin.Type);
containerBuilder.RegisterType(pluginType).Named<IPlugin>(plugin.Name);


Я не знаю, насколько это все корректно, так как документации вообще нет, но оно работало. Я даже проверял на предмет возможного конфликта зависимостей - все было ок.
...
Рейтинг: 0 / 0
Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
    #39808195
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
fkthat,

Благодарю за код! Заодно узнал о существовании ContainerBuilder - буду читать про него. :)
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Возможно ли через прокси получать информацию о пользовательских атрибутах класса?
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]