Динамический метод IL вызывает “Операция может дестабилизировать среду выполнения”.

StackOverflow https://stackoverflow.com/questions/5324871

Вопрос

Система.Безопасность.Исключение VerificationException:Операция может дестабилизировать среду выполнения .при подключении.CommunicatorApi.ReportApiClient.Подтверждающий вызовsasyncdynamichandler(объект , подтверждающий вызовscompletedeventargs )

Это ошибка, которую я получаю.То, что я пытаюсь сделать (фоновый), - это создать глобальный обработчик событий для класса методов.Я работаю со статическим прокси-сервером в WCF, и мне нужно создать слой, который отслеживает все вызовы и возвращает результаты ко всем веб-методам WCF.К сожалению, WCF строго вводит EventArgs "Завершенных" событий, что делает это практически невозможным.

Я решил кое-что попробовать.Если событие является EventHandler<SomeSpecificEventArgs>, я все еще могу зарегистрировать метод подписи void Method(object, object) чтобы обработать событие.Отлично.Поэтому я приступил к созданию DynamicMethod который назвал бы мой глобальный обработчик и регистрируйте его для каждого события.

Я попробовал два способа:

1) DynamicMethod имеет тип void (объект, object)

2) типа void (object, SomeSpecificEventArgs) - я использую универсальный метод для этого, чтобы получить тип.

Только когда я пытаюсь вызвать метод, либо вручную, либо для события, я получаю приведенное выше исключение.

Вот мой код:

    // The handler for all callbacks.
// in the example it does nothing.
public void Handler(object sender, object e)
{
    dynamic evtArgs = e;
    object userState = evtArgs.UserState;
}

private string GetIdentifier(Delegate d)
{
    return string.Concat(d.Method.DeclaringType, '.', d.Method.Name);
}

// Method to register an event handler
public void Register<T> (Delegate o) where T : EventArgs
{
    // get some info
    /* snip. code to get method name, and calculate name of event */

    var eventInst = ownerType.GetEvent(eventName);

    // The following works, for example:
    // someObj.MethodCompleted += Handler;
    // even though MethodCompleted is an event of type EventHandler<SomeSpecialEventArgs>

    // get the actual type of handler
    var handlerType = eventInst.EventHandlerType;
    EventHandler evtHandler = new EventHandler(Handler);    

    DynamicMethod dm = new DynamicMethod(
        GetIdentifier(o) + "DynamicHandler", // set the name
        typeof(void),                        // return void
        new[] { typeof(object), typeof(T) });// params object and type of event args

    ILGenerator gen = dm.GetILGenerator();

    gen.Emit(OpCodes.Ldarg_0); // load first arg to stack for calling
    gen.Emit(OpCodes.Ldarg_2); // load second arg to stack for calling

    gen.Emit(OpCodes.Call, evtHandler.Method); // call method

    gen.Emit(OpCodes.Ret); // return

    // this is the final delegate
    var superdlg = dm.CreateDelegate(handlerType);

    // the problem beings here:
    // when the event is raised and the delegate is invoked
    // of if I dynamicInvoke it, I get the error
    eventInst.AddEventHandler(ownerInst, superdlg);
}

Редактировать:Я понимаю.Оказывается, у меня есть еще одна проблема.Я работаю в Silverlight.Мне удалось воспроизвести мой сценарий в отдельном проекте, и я заставил его работать, используя перегрузку DynamicMethod который позволяет вам установить владельца.Затем я уточняю

DynamicMethod dm = new DynamicMethod("TestMethod2", typeof(void), new[] { typeof(MyClass), typeof(string), typeof(string) }, typeof(MyClass));,

и использовать ldarg.0, ldarg.1, и ldarg.2.Но это критичный для безопасности конструктор, и он не будет запускаться в silverlight.Я просто не уверен, как мне тогда нужно это настроить.Делаю ли я то, что Handler общедоступные статические и загрузочные аргументы 0-1?В итоге я получаю сообщение об ошибке, подобное этому:

Попытка с помощью метода 'DynamicClass.TestMethod 2 (System.String, System.String)' получить доступ к методу 'dynamicass.MyClass.Обработчик (System.String, System.Строка)"сбой".}

Это было полезно?

Решение 2

Итак, то, что я придумал, было вот что.

Сделайте так, чтобы Handler используйте метод экземпляра и добавьте другой тип аргумента для DynamicMethod конструктор типа класса, которому он принадлежит (для неявного this аргумент).

тогда вы делаете dm.CreateDelegate(_args_, this)

Другие советы

Аргументы метода индексируются нулем - используйте ldarg.0 и ldarg.1 вместо того, чтобы ldarg.1 и ldarg.2

Также существует проблема с вызовом метода обработчика событий - вы не указываете this указатель для метода (Delegate.Target).Вам необходимо предоставить this указатель, который может быть статическим, а может и не быть, в зависимости от того, что зарегистрировано.

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

.method public static CallEventHandler(EventHandlerType ev, object sender, EventArgsType e) {
    ldarg.0   // the Invoke 'this' pointer
    ldarg.1
    ldarg.2
    callvirt instance void EventHandlerType::Invoke(object, EventArgsType)
    ret
}

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top