Similar presentations:
NET Code hot reload
1.
.NET code hot reloadАсадуллин Тимур
Directum, Уфа
2.
Что за «Code hot reload»?Обновление кода приложения без перезапуска этого
приложения.
.NET Framework (4.6 +)
Надеюсь такие слова вас не пугают:
CLR, MSIL, Assembly, указатель.
2
3.
DirectumRX – ECM-система3
4.
DirectumRX Development Studio4
5.
Прикладная разработка DirectumRXЛокальный сервер
приложений
Development Studio
(IDE)
Новый
прикладной код
compile
Deploy (dll)
Прикладной код
Код платформы
(framework)
restart
5
6.
Зачем нам HotReloadЛокальный сервер
приложений
Development Studio
(IDE)
Новый
прикладной код
Deploy
Прикладной код
Код платформы
(framework)
compile
restart
6
7.
Дополнительные ограничения и пожеланияЕсли поменялась структура БД, одним HotReload не
обойтись.
HotReload и отладка в Dev Studio (breakpoints, watch).
Подходит и для серверного, и для клиентского кода
(у нас есть Desktop-клиент).
7
8.
Основная идеяИзбавиться от перезапуска сервера.
Встраивать код напрямую в работающее приложение.
Локальный сервер
приложений
Прикладной код
Development Studio (IDE)
Новый
прикладной код
8
Исходник
или Assembly
inject
Код платформы
9.
Решения в лобReflection – LoadAssembly
(Shadow Copy Assemblies)
Managed Extensibility Framework (MEF, VS-MEF)
Mono.Cecil
9
10.
Решения в лоб. ПроблемыНе повлияем на уже существующие в памяти объекты.
Новые объекты, создаваемые через new будут
ссылаться на старые типы.
В случае с MEF прикладной код придётся переписать
особым образом (атрибуты, интерфейсы).
10
11.
EmitCodeDom – компиляция С# в
Assembly сразу в память в
AppDomain.
Прикладной код
Emit – генерация IL-кода.
compile
Development Studio (IDE)
Новые прикладные
исходники
11
Локальный сервер приложений
C#
emit
Платформа
12.
Emit. ПроблемыEmit работает только с DynamicAssembly.
А при компиляции CodeDom’a мы получаем обычную
Assembly.
Чтобы «завести» динамический класс,
нужно вызвать у него CreateType().
Это блокирует его дальнейшие модификации.
12
13.
Edit and ContinueВстроенный в Visual Studio хитрый механизм,
генерирующий некоторые дельты.
Общедоступного API нет.
Даже в самой VS механизм не работает в ряде
случаев.
13
14.
1415.
Method Injectv1
15
16.
Method Inject v1Суть – замена указателя на метод.
MethodInfo methodToReplace = … ;
MethodInfo methodToInject = … ;
unsafe
{
long* target = (long*) methodToReplace.MethodHandle.Value.ToPointer();
long* inject = (long*) methodToInject.MethodHandle.Value.ToPointer();
*target = *inject;
}
В реальности чуток сложнее, потому
что надо учесть x86/x64, Debug/Release.
16
17.
Как хранятся описания классов в .NETObjectInstance
Заголовок
MethodTable ptr
Field value 1
Field value 2
…
17
MethodTable
…
ToString() ptr
Equals() ptr
….
MyMethod1() ptr
…
{
Console.WriteLine(1);
}
18.
Method Inject v1. СутьObjectInstance
Заголовок
MethodTable ptr
Field value 1
Field value 2
…
MethodTable
{
Console.WriteLine(1);
…
}
ToString() ptr
Equals() ptr
….
MyMethod1() ptr
…
{
Console.WriteLine(2);
}
18
19.
Method Inject v1. Проверяем на практикеЕсть два класса…
Target
TargetMethod()
Injector
Injection
InjectionMethod()
19
20.
Method Inject v1.Проверяем на практике
WinDbg + SOS
Исходный MethodTable
TestClasses.Target.Test()
TestClasses.Target.TargetMethod()
TestClasses.Target.get_Value()
TestClasses.Target..ctor (System.String)
20
21.
Method Inject v1.Проверяем на практике
MethodTable после Inject
TestClasses.Target.Test()
TestClasses.Injection.InjectionMethod()
TestClasses.Target.get_Value()
TestClasses.Target..ctor (System.String)
21
22.
Method Inject v1. Дополнительные работыСравнить прикладные исходники и найти
изменившиеся методы.
Передать исходники методов на сервер.
Создать новый класс, засунуть в него методы и
скомпилировать в память.
Найти старый метод и сделать MethodInject на новый.
22
23.
Method Inject v1. ПРОБЛЕМА!Прекрасно работает
пока мы не вызвали подменяемый метод.
23
24.
Method Inject v1. ПРОБЛЕМА!compileMethod
PreJitStub
MethodTable
…
….
MyMethod1() ptr
…
native machine
code
Stub
….
Code ptr
…
MethodDesc
24
Write jmp
to jitted code
{
Console.WriteLine(1);
}
25.
Method Injectv2
25
26.
Method Inject v2public static class InjectionHelper
{
...
public static void Initialize()
public static void UpdateILCodes(MethodInfo method, byte[] ilCodes)
...
}
26
27.
Method Inject v2compileMethod
PreJitStub
MethodTable
…
….
MyMethod1() ptr
…
Stub
….
Code ptr
…
MethodDesc
27
Write jmp
to jitted code
machine code
IL
28.
Method Inject v2Injector
hook
MethodDesc.Reset()
compileMethod
PreJitStub
MethodTable
…
….
MyMethod1() ptr
…
Stub
….
Code ptr
…
MethodDesc
28
Write jmp
to jitted code
machine code
IL
29.
Method Inject v2. ПроблемкиНормально заработало только
на .NET Framework 2.0 - 4.0
Inline маленьких методов.
Лезем внутрь CLR.
Слишком рискованно для продакшена.
29
30.
Давайте вспомним, с чего мы началиЕсть платформа.
Она исполняет прикладной код.
Мы хотим подменять прикладной код.
30
31.
Что за прикладной код?ClientHandlers
ServerHandlers
BeforeSave()
AfterSave()
…
ServerFunctions
ServerFoo()
…
31
Document
Name
Author
Created
…
Showing()
…
ClientFunctions
ClientFoo()
…
32.
Class swapПлатформенный код создаёт прикладные объекты
(Dependency Injection).
Не возимся с методами – заменяем сразу весь объект.
IDocument1ServerFunctions
Document1
Name
…
32
IDocument1ServerFunctions
Document1ServerFunctions
Foo()
…
Foo()
…
33.
Class swapIDocument1ServerFunctions
Document1ServerFunctions
Document1
Foo()
Implementation
Create
ServerFunctions ()
33
AppTypesManager
34.
Class swapIDocument1ServerFunctions
Document1ServerFunctions
Document1
Create
ServerFunctions ()
Foo()
AppTypesManager
…
Create type
C# sources
34
Injector
35.
Class swapIDocument1ServerFunctions
Document1ServerFunctions
Document1
Foo()
IDocument1ServerFunctions
Create
ServerFunctions ()
AppTypesManager
Implementation
Document1ServerFunctions
Foo()
Register
Create type
C# sources
35
Injector
36.
ЗаключениеВ продакшен это не пошло :(
Деплой мы ускорили иначе – оптимизации.
Исследования – круто.
Погружение в детали инструмента – интересно.
36
37.
().net core
JIT disable
Custom .NET CLR
37
38.
THE ENDАсадуллин Тимур
Directum, Уфа
[email protected]
39.
СсылочкиMethodInject v1 https://www.codeproject.com/Articles/37549/CLR-Injection-Runtime-MethodReplacer
MethodInject v2
https://www.codeproject.com/Articles/463508/NET-CLR-Injection-Modify-IL-Code-during-Run-time
EasyHook
https://easyhook.github.io
Отладка WinDbg + SOS
https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/debugging-managed-code
.net core
«How to use and debug assembly unloadability in .NET Core»
https://docs.microsoft.com/ru-ru/dotnet/standard/assembly/unloadability