Assembly.LoadFrom терпит неудачу, но только спорадически

Я хочу написать программу, которая следит за изменениями .dll. Когда происходит изменение, он должен загрузить сборку и вызвать функцию foo внутри.

У меня есть код, который должен реализовать это, но он ведет себя странно. Иногда это работает. Иногда загружаемая сборка будет старой версии. Иногда это вызывает исключение BadImageFormatException.

Вот код моей программы (это F#, но я думаю, что это общий вопрос .NET Core):

module HotReloadDemo

open System
open System.IO
open System.Reflection

[<EntryPoint>]
let main argv =
  let assemblyPath = argv.[0] // Path to the .dll to watch

  let mutable lastWriteTime = DateTime.MinValue

  while true do

    let writeTime =
      if File.Exists assemblyPath
      then
        File.GetLastWriteTimeUtc assemblyPath
      else
        lastWriteTime

    if writeTime > lastWriteTime
    then
      lastWriteTime <- writeTime

      try
        printfn "Last write time: %O " lastWriteTime

        printfn "Waiting for the build to finish (this is a hack)... "
        Threading.Thread.Sleep 10000 // 10s is plenty long enough for the build to finish

        printfn "Loading assembly path from: %s " assemblyPath

        let assembly = Assembly.LoadFrom assemblyPath

        printfn "Got assembly: %O" (assembly.GetName ())

        let foo : (Unit -> int) option =
          assembly.GetExportedTypes()
          |> Array.tryHead
          |> Option.bind (fun t -> t.GetMethod "foo" |> Option.ofObj)
          |> Option.map (fun m -> (fun () -> m.Invoke (null, Array.empty) :?> int))

        match foo with
        | Some foo ->
          printfn "foo () = %O" (foo ())
        | None ->
          printfn "foo not found"

      with exn ->
        printfn "%O" exn

    else
      ()

  Threading.Thread.Sleep 1000

  0

Затем у меня есть очень простая библиотека для просмотра в другом проекте, например:

module HotReload

  let foo () =
    123456

Чтобы проверить это, я запускаю программу «наблюдатель». Он успешно загружает и вызывает foo.

Затем я модифицирую свою библиотеку (например, чтобы вернуть другое число) и создаю ее с помощью dotnet build.

Наблюдатель обнаруживает изменение, снова загружает сборку и вызывает foo, но печатает номер до изменения!

Затем я изменяю библиотеку снова с другим номером. Он обнаруживает изменение, но вылетает:

...

Loading assembly path from: ../hot-reload-lib/bin/Debug/netstandard2.0/hot-reload-lib.dll 
System.BadImageFormatException: Could not load file or assembly '<Unknown>'. Index not found. (0x80131124)
File name: '<Unknown>'
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
   at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
   at System.Reflection.Assembly.LoadFrom(String assemblyFile)

...

Что здесь происходит?


dotnet  --version 
3.0.100

lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 18.04.3 LTS
Release:    18.04
Codename:   bionic

person sdgfsdh    schedule 06.02.2020    source источник
comment
Вы пытались добавить еще одну задержку в наблюдатель? Код выглядит так, как будто в нем могут быть гейзенбаги. BadImageFormatException может быть связано с тем, что наблюдатель за файлом сработал до завершения записи файла.   -  person Asti    schedule 07.02.2020
comment
@Asti да, пожалуйста, посмотрите код   -  person sdgfsdh    schedule 07.02.2020
comment
Вероятно, вам следует увеличить версию сборки или использовать отдельный домен приложения для загрузки. В противном случае сборка не будет загружена снова. См. stackoverflow.com/questions/30113525/   -  person gnud    schedule 24.02.2020