Assembly.LoadFrom fails but only sporadically - .net-core
I want to write a program that watches a .dll for changes. When a change happens, it should load the assembly and invoke the foo function inside.
I have some code that should implement this, but it behaves strangely. Sometimes it works. Sometimes the assembly it loads will be an old version. Sometimes it will throw a BadImageFormatException exception.
Here is my program code (it is F# but I think this is a general .NET Core question):
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
I then have a very simple library to be watched in another project like this:
module HotReload
let foo () =
123456
To test it, I launch the "watcher" program. It successfully loads and invokes foo.
Then, I modify my library (e.g. to return a different number) and build it with dotnet build.
The watcher detects the change, loads the assembly again and invokes foo, but it prints the number from before the change!
Then, I modify the library again with a different number. It detects the change but crashes:
...
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)
...
What is going on here?
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
Related
OCaml - Error: Module `Unix' is unavailable [closed]
Closed. This question needs debugging details. It is not currently accepting answers. Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question. Closed last year. Improve this question I have been working through Harvard's CS51 class using materials available online. I'm trying to start the final project and downloaded the necessary files, but when I try to compile them I get the following error: Error: Module `Unix' is unavailable (required by `Thread') Command exited with code 2. Compilation unsuccessful after building 18 targets (15 cached) in 00:00:00. I have not made any changes to the code I downloaded yet and supposedly I should be able to compile it successfully in its current state. Any ideas why I might be getting this error? EDIT: Below is the code from the file I downloaded and am trying to compile. module Ev = Evaluation ;; module MP = Miniml_parse ;; module ML = Miniml_lex ;; module Ex = Expr ;; open Printf ;; (* str_to_exp str -- Returns the expression specified by `str` using the MiniML parser. *) let str_to_exp (str: string) : Ex.expr = let lexbuf = Lexing.from_string str in let exp = MP.input ML.token lexbuf in exp ;; (* repl () -- Read-eval-print loop for MiniML, which prompts for and evaluates MiniML expressions, printing the resulting value. Exits the loop and terminates upon reading an end-of-file (control-d). *) let repl () = (* lexical analyzer buffer from stdin *) let lexbuf = Lexing.from_channel stdin in (* set up the initial environment *) let env = Ev.Env.empty () in (* the main LOOP *) while true do (try (* prompt *) printf "<== %!"; (* READ and parse an expression from the input *) let exp = MP.input ML.token lexbuf in (* EVALuate it *) let res = Ev.evaluate exp env in (* PRINT the result; in this initial version, the trivial evaluator just returns the expression unchanged as an element of the `Env.value` type (found in `expr.ml`), so we just extract the expression back out and print it *) match res with | Val resexp -> printf "==> %s\n" (Ex.exp_to_abstract_string resexp) | _ -> failwith "not handling other cases yet" with | MP.Error -> printf "xx> parse error\n" | Ev.EvalError msg -> printf "xx> evaluation error: %s\n" msg | Ev.EvalException -> printf "xx> evaluation exception\n" | End_of_file -> printf "Goodbye.\n"; exit 0 ); flush stdout done ;; (* Run REPL if called from command line *) try let _ = Str.search_forward (Str.regexp "miniml\\.\\(byte\\|native\\|bc\\|exe\\)") (Sys.argv.(0)) 0 in repl () with Not_found -> () ;; If I add open Unix it does take care of the error above, but I then get a different error: 26 | let lexbuf = Lexing.from_channel stdin in ^^^^^ Error: This expression has type Unix.file_descr but an expression was expected of type in_channel Command exited with code 2.
Generally, you have to explicitly ask to be linked to the Unix module. The following program: $ cat main.ml Unix.gethostname () |> print_endline would need to be built like this: $ ocamlfind opt -linkpkg -package unix -o main main.ml; echo $? 0 whereas the bare minimum would fail with a similar error as yours: $ ocamlopt -o main main.ml; echo $? File "main.ml", line 1: Error: No implementations provided for the following modules: Unix referenced from main.cmx 2 That said, it looks like you're using Core, in which case (as well as most other cases, actually) you're probably better off with dune: $ cat dune (executable (name main) (libraries unix)) $ dune build main.exe $ ./_build/default/main.exe amam-oy However, if you ask Dune to link you to Core, Unix is already included automatically, so the following dune file would also work for the above program: $ cat dune (executable (name main) (libraries core))
Just add open Unix;; at the very start of your .ml file
Trying to use `NativePtr.toVoidPtr` or `NativeInt.ToPointer` causes `System.TypeLoadException`
So I was trying to do some OpenGl with silk.net and .net core 3.1. When I try to convert nativeptr<int> to voidptr I get weird error. Below is minimal example to reproduce error. #nowarn "9" open FSharp.NativeInterop [<EntryPoint>] let main argv = let numbers = [| 1..10 |] use v = fixed numbers let v' = NativePtr.toVoidPtr v printfn "void = %A" v' 0 // return an integer exit code This code when run generates: $ dotnet run Unhandled exception. System.TypeLoadException: The generic type 'Microsoft.FSharp.Core.FSharpFunc`2' was used with an invalid instantiation in assembly 'FSharp.Core, Version=4.7.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. at Program.main(String[] argv) What am I doing wrong?
Issues with reading file in erlang
So, I am trying to read and write into a file. While writing into the file, I need to check if a particular index exist in file then I don't write and throw error. The data in file will look like this: {1,{data,dcA,1}}. {2, {data, dcA, 2}}. {3,{data,dcA,3}}. I added the dot at the end of each line because file:consult() needs the file like this. Which is in this format. {Index, {Data, Node, Index}} When I have to add a new file, I check with this Index. Here's what I have tried so far - https://pastebin.com/apnWLk45 And I run it like this: 193> {ok, P9} = poc:start(test1, self()). {ok,<0.2863.0>} 194> poc:add(P9, Node, {6, data}). In poc:add/3, P9 is the process id from the file:open. I defined before in shell as dcA And the third is the data - which is in this format - {Index, data} Since I am using file:consult/1, it takes the filename as parameter. At that point, I only have process id. So I take the name from file:pid2name(_Server). This runs perfectly when I run it for the first time. When I run this again - poc:add(P9, Node, {6, data2}), I get an error in this line file:pid2name(_Server). exception error: no match of right hand side value undefined How can I solve this issue? I am new to Erlang. Just been a week that I started learning.
I am trying to read and write into a file. While writing into the file, I need to check if a particular index exist in file then I don't write and throw error. A DETS table can easily do what you want: -module(my). -compile(export_all). open_table() -> dets:open_file(my_data, [{type, set}, {file, "./my_data.dets"}]). close_table() -> dets:close(my_data). clear_table() -> dets:delete_all_objects(my_data). insert({Key, _Rest}=Data) -> case dets:member(my_data, Key) of true -> throw(index_already_exists); false -> dets:insert(my_data, Data) end. all_items() -> dets:match(my_data, '$1'). In the shell: ~/erlang_programs$ erl Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false] Eshell V9.2 (abort with ^G) 1> c(my). my.erl:2: Warning: export_all flag enabled - all functions will be exported {ok,my} 2> my:open_table(). {ok,my_data} 3> my:clear_table(). ok 4> my:all_items(). [] 5> my:insert({1, {data, a, b}}). ok 6> my:insert({2, {data, c, d}}). ok 7> my:insert({3, {data, e, f}}). ok 8> my:all_items(). [[{1,{data,a,b}}],[{2,{data,c,d}}],[{3,{data,e,f}}]] 9> my:insert({1, {data, e, f}}). ** exception throw: index_already_exists in function my:insert/1 (my.erl, line 15) When I run this again - poc:add(P9, Node, {6, data2}), I get an error in this line file:pid2name(_Server): exception error: no match of right hand side value undefined When a process opens a file, it becomes linked to a process that handles the file I/O, which means that if the process that opens the file terminates abnormally, the I/O process will also terminate. Here is an example: -module(my). -compile(export_all). start() -> {ok, Pid} = file:open('data.txt', [read, write]), spawn(my, add, [Pid, x, y]), exit("bye"). add(Pid, _X, _Y) -> timer:sleep(1000), %Let start() process terminate. {ok, Fname} = file:pid2name(Pid), io:format("~s~n", [Fname]). In the shell: 1> c(my). my.erl:2: Warning: export_all flag enabled - all functions will be exported {ok,my} 2> my:start(). ** exception exit: "bye" in function my:start/0 (my.erl, line 7) 3> =ERROR REPORT==== 25-Jun-2018::13:28:48 === Error in process <0.72.0> with exit value: {{badmatch,undefined},[{my,add,3,[{file,"my.erl"},{line,12}]}]} According to the pid2name() docs: pid2name(Pid) -> {ok, Filename} | undefined the function can return undefined, which is what the error message is saying happened.
SBT Migration: How to replace Command.process
I have a statement in my 0.13x build.sbt file that composes a sbt.Command with the onLoad function: onLoad in Global := (Command.process("project server", _: State)) compose (onLoad in Global).value Now when updating to SBT 1.1.0 the Command.process method does not exist anymore, neither exists a method with the same signature. So how can I achieve the same effect?
Command.process was moved to MainLoop.processCommand API reference - MainLoop.processCommand You migrate to as below. onLoad in Global := (MainLoop.processCommand(Exec("project server", None), _: State)) compose (onLoad in Global).value
onLoad in Global := (onLoad in Global).value andThen ("project server" :: _) or if you fancy the even terser: onLoad in Global ~= (_ andThen ("project server" :: _))
Ejabberd: error in simple module to handle offline messages
I have an Ejabberd 17.01 installation where I need to push a notification in case a recipient is offline. This seems the be a common task and solutions using a customized Ejabberd module can be found everywhere. However, I just don't get it running. First, here's me script: -module(mod_offline_push). -behaviour(gen_mod). -export([start/2, stop/1]). -export([push_message/3]). -include("ejabberd.hrl"). -include("logger.hrl"). -include("jlib.hrl"). start(Host, _Opts) -> ?INFO_MSG("mod_offline_push loading", []), ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10), ok. stop(Host) -> ?INFO_MSG("mod_offline_push stopping", []), ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10), ok. push_message(From, To, Packet) -> ?INFO_MSG("mod_offline_push -> push_message", [To]), Type = fxml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 16.04 %Type = xml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 13.XX %Type = xml:get_tag_attr_s("type", Packet), %Type = xml:get_tag_attr_s(list_to_binary("type"), Packet), ?INFO_MSG("mod_offline_push -> push_message", []), ok. The problem is the line Type = ... line in method push_message; without that line the last info message is logged (so the hook definitely works). When browsing online, I can find all kinds of function calls to extract elements from Packet. As far as I understand it changed over time with new releases. But it's not good, all variants lead in some kind of error. The current way returns: 2017-01-25 20:38:08.701 [error] <0.21678.0>#ejabberd_hooks:run1:332 {function_clause,[{fxml,get_tag_attr_s,[<<"type">>,{message,<<>>,normal,<<>>,{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},[],[{text,<<>>,<<"sfsdfsdf">>}],undefined,[],#{}}],[{file,"src/fxml.erl"},{line,169}]},{mod_offline_push,push_message,3,[{file,"mod_offline_push.erl"},{line,33}]},{ejabberd_hooks,safe_apply,3,[{file,"src/ejabberd_hooks.erl"},{line,382}]},{ejabberd_hooks,run1,3,[{file,"src/ejabberd_hooks.erl"},{line,329}]},{ejabberd_sm,route,3,[{file,"src/ejabberd_sm.erl"},{line,126}]},{ejabberd_local,route,3,[{file,"src/ejabberd_local.erl"},{line,110}]},{ejabberd_router,route,3,[{file,"src/ejabberd_router.erl"},{line,87}]},{ejabberd_c2s,check_privacy_route,5,[{file,"src/ejabberd_c2s.erl"},{line,1886}]}]} running hook: {offline_message_hook,[{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},{message,<<>>,normal,<<>>,{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},[],[{text,<<>>,<<"sfsdfsdf">>}],undefined,[],#{}}]} I'm new Ejabberd and Erlang, so I cannot really interpret the error, but the Line 33 as mentioned in {mod_offline_push,push_message,3,[{file,"mod_offline_push.erl"}, {line,33}]} is definitely the line calling get_tag_attr_s. UPDATE 2017/01/27: Since this cost me a lot of headache -- and I'm still not perfectly happy -- I post here my current working module in the hopes it might help others. My setup is Ejabberd 17.01 running on Ubuntu 16.04. Most stuff I tried and failed with seem to for older versions of Ejabberd: -module(mod_fcm_fork). -behaviour(gen_mod). %% public methods for this module -export([start/2, stop/1]). -export([push_notification/3]). %% included for writing to ejabberd log file -include("ejabberd.hrl"). -include("logger.hrl"). -include("xmpp_codec.hrl"). %% Copied this record definition from jlib.hrl %% Including "xmpp_codec.hrl" and "jlib.hrl" resulted in errors ("XYZ already defined") -record(jid, {user = <<"">> :: binary(), server = <<"">> :: binary(), resource = <<"">> :: binary(), luser = <<"">> :: binary(), lserver = <<"">> :: binary(), lresource = <<"">> :: binary()}). start(Host, _Opts) -> ?INFO_MSG("mod_fcm_fork loading", []), % Providing the most basic API to the clients and servers that are part of the Inets application inets:start(), % Add hook to handle message to user who are offline ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10), ok. stop(Host) -> ?INFO_MSG("mod_fcm_fork stopping", []), ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10), ok. push_notification(From, To, Packet) -> % Generate JID of sender and receiver FromJid = lists:concat([binary_to_list(From#jid.user), "#", binary_to_list(From#jid.server), "/", binary_to_list(From#jid.resource)]), ToJid = lists:concat([binary_to_list(To#jid.user), "#", binary_to_list(To#jid.server), "/", binary_to_list(To#jid.resource)]), % Get message body MessageBody = Packet#message.body, % Check of MessageBody is not empty case MessageBody/=[] of true -> % Get first element (no idea when this list can have more elements) [First | _ ] = MessageBody, % Get message data and convert to string MessageBodyText = binary_to_list(First#text.data), send_post_request(FromJid, ToJid, MessageBodyText); false -> ?INFO_MSG("mod_fcm_fork -> push_notification: MessageBody is empty",[]) end, ok. send_post_request(FromJid, ToJid, MessageBodyText) -> %?INFO_MSG("mod_fcm_fork -> send_post_request -> MessageBodyText = ~p", [Demo]), Method = post, PostURL = gen_mod:get_module_opt(global, ?MODULE, post_url,fun(X) -> X end, all), % Add data as query string. Not nice, query body would be preferable % Problem: message body itself can be in a JSON string, and I couldn't figure out the correct encoding. URL = lists:concat([binary_to_list(PostURL), "?", "fromjid=", FromJid,"&tojid=", ToJid,"&body=", edoc_lib:escape_uri(MessageBodyText)]), Header = [], ContentType = "application/json", Body = [], ?INFO_MSG("mod_fcm_fork -> send_post_request -> URL = ~p", [URL]), % ADD SSL CONFIG BELOW! %HTTPOptions = [{ssl,[{versions, ['tlsv1.2']}]}], HTTPOptions = [], Options = [], httpc:request(Method, {URL, Header, ContentType, Body}, HTTPOptions, Options), ok.
Actually it fails with second arg Packet you pass to fxml:get_tag_attr_s in push_message function {message,<<>>,normal,<<>>, {jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>, <<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>}, {jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>, <<"xxx.xxx.xxx.xxx">>,<<>>}, [], [{text,<<>>,<<"sfsdfsdf">>}], undefined,[],#{}} because it is not xmlel Looks like it is record "message" defined in tools/xmpp_codec.hrl with <<>> id and type 'normal' xmpp_codec.hrl -record(message, {id :: binary(), type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal', lang :: binary(), from :: any(), to :: any(), subject = [] :: [#text{}], body = [] :: [#text{}], thread :: binary(), error :: #error{}, sub_els = [] :: [any()]}). Include this file and use just Type = Packet#message.type or, if you expect binary value Type = erlang:atom_to_binary(Packet#message.type, utf8)
The newest way to do that seems to be with xmpp:get_type/1: Type = xmpp:get_type(Packet), It returns an atom, in this case normal.