F# compile code at runtime ends in missing assemblies - f#

I have a question related to the code provided in an answer to this question.
The problem I have is that the three referenced assmeblies (System.dll, FSharp.Core.dll, FSharp.Powerpack.dll) that are passed to CompilerParameters are not found at runtime. The error I get is:
unknown-file(0,0) : error 0: error FS0218: Unable to read assembly
'c:\user s\utente\documents\visual studio
2010\Projects\TrashSolution\TrashSolution\bin\D ebug\FSharp.Core.dll'
How do I tell the compiler to search for these assemblies in the GAC, instead of the project's bin directory? If I open a namespace in the code provided as a string, how do I know which assemblies to add? Where can I get this information?

In the code from the answer you linked, there's a line towards the bottom:
let asm = Reflection.Assembly.LoadFrom(fileinfo.Value.FullName)
If you call Reflection.Load instead and pass it the fully-qualified assembly name, it'll try to load the assembly from the GAC (and a few other places, if the assembly isn't in the GAC).
let asm =
Assembly.Load "SampleAssembly, Version=1.0.2004.0, Culture=neutral, PublicKeyToken=8744b20f8da049e3"
If you don't know the fully-qualified assembly name you have to create an AssemblyName with the simple name of the assembly, then call the Reflection.Load overload which takes an AssemblyName instead of a string.
let asmName = AssemblyName "Your.Assembly.Name"
let asm = Assembly.Load asmName
As far as knowing which assemblies to load -- I don't think there's a simple way to determine that programmatically. The only two solutions I can think of right now:
If you have some knowledge about the code you're being given (as a string), you could parse it with the FSharpCodeProvider and look at which namespaces/modules are opened and which types are used. If you're looking to see if some particular namespace or type is used (i.e., that you would need to include an assembly reference for when compiling the code), you could create a Map (in your .fsx which is doing the compilation) of namespaces and/or type names to assembly names and use it to reference the appropriate assemblies.
You could "brute-force" search the GAC, by using the semi-documented Fusion API to enumerate all of the assemblies installed in the GAC, then using Reflection to examine each assembly and determine if it's one you require. This is likely to be extremely slow, so I'd avoid it at all costs. If you do decide to go this route, you must also use the Assembly.ReflectionOnlyLoad method to load the assemblies! This allows the assemblies to be unloaded after you finish examining them -- if you use normal Reflection the assemblies can't be unloaded and your program will likely crash with an OutOfMemoryException or similar.
EDIT: Turns out that loading the assembly by its simple name succeeds in fsi and not in normal F# code because fsi automatically installs a handler for the AppDomain.AssemblyResolve event. This event is triggered by the CLR when you try to load an assembly and it can't be resolved; the event provides a way for you to "manually" resolve the assembly and/or generate an assembly dynamically and return it.
If you look at the FileNotFoundException raised when you try to run the code in an F# project, you'll see something like this in the Fusion Log property of the exception:
=== Pre-bind state information ===
LOG: User = Jack-Laptop\Jack
LOG: DisplayName = System
(Partial)
WRN: Partial binding information was supplied for an assembly:
WRN: Assembly Name: System | Domain ID: 1
WRN: A partial bind occurs when only part of the assembly display name is provided.
WRN: This might result in the binder loading an incorrect assembly.
WRN: It is recommended to provide a fully specified textual identity for the assembly,
WRN: that consists of the simple name, version, culture, and public key token.
WRN: See whitepaper http://go.microsoft.com/fwlink/?LinkId=109270 for more information and common solutions to this issue.
LOG: Appbase = file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/
LOG: Initial PrivatePath = NULL
Calling assembly : StackOverflow1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null.
===
LOG: This bind starts in default load context.
LOG: No application configuration file found.
LOG: Using host configuration file:
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\config\machine.config.
LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind).
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System.DLL.
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System/System.DLL.
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System.EXE.
LOG: Attempting download of new URL file:///C:/Users/Jack/Documents/Visual Studio 2010/Projects/StackOverflow1/StackOverflow1/bin/Debug/System/System.EXE.
Looking towards the bottom of that log, you'll see where the CLR searched for the assembly before it gave up.
Here's a simple handler to give you an idea of how to use the AppDomain.AssemblyResolve handler to manually resolve the assembly. (NOTE: The handler needs to be added before the code that attempts to load the assembly!)
System.AppDomain.CurrentDomain.add_AssemblyResolve (
System.ResolveEventHandler (fun _ args ->
let resolvedAssembly =
System.AppDomain.CurrentDomain.GetAssemblies ()
|> Array.tryFind (fun loadedAssembly ->
// If this assembly has the same name as the one we're looking for,
// assume it's correct and load it. NOTE : It may not be the _exact_
// assembly we're looking for -- then you'll need to adjust the critera below.
args.Name = loadedAssembly.FullName
|| args.Name = loadedAssembly.GetName().Name)
// Return null if the assembly couldn't be resolved.
defaultArg resolvedAssembly null))
If you add that code to a new F# console project, followed by the code which uses AssemblyName with Assembly.Load, you should be able to load the System assembly because it's referenced by default in an F# project and it'll be loaded when you run the project. If you try to resolve System.Drawing, it'll fail because our custom event handler can't find the assembly. Obviously, if you need some more complicated assembly-resolving logic, you should build that into the event handler in whatever way makes sense for your application.
Finally, here's a link to the MSDN whitepaper mentioned in the exception message: Best Practices for Assembly Loading. It's worth a read if you get stuck and can't figure out how to resolve the assemblies you need.

Related

How do I subscribe to an event implemented in F# from a C# client?

How do I subscribe to an event implemented in F# from a C# client?
I have the following code:
_dispatcher.SignInRequested += StartActivity(typeof(SignInActivity));
This line results in the following error:
Error CS0012 The type 'FSharpHandler<>' is defined in an assembly that
is not referenced. You must add a reference to assembly 'FSharp.Core,
Version=3.3.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
I attempted to troubleshoot and found this:
However, I do not understand the answer. My events are defined under a namespace and not a module. Hence, me not understanding the reasoning of that discussion.
I then tried adding the following reference to my C# project:
FSharp.Core 4.0.0.1
and
FSharp.Core 3.1.2.5
However, I still receive the same error.
When managing Nuget packages, I do not see the version "3.3.1.0" listed as an option.
Implementation Details:
The signature of the signin event from the C# client is the following:
public event FSharpHandler<Unit> SignInRequested;
I actually declare the event as the following:
let signInRequested = new Event<_>()
Any suggestions?
You need to have a look at the CLIEventAttribute . Events declared from F# cannot be used from C# unless they are declared with this attribute.

Using System.Collections.Immutable with F# and Mono

I am trying to make use of the ImmutableDictionary in F# using Mono. I'm using the Xamarin IDE.
I have set my target framework to Mono/.Net4.5 and imported the System.Collections.Immutable using the built in Nuget package manager.
The following line
open System.Collections.Immutable
is generating the following two errors
'/Users/UserName/Projects/Xamarin/OrderInfer/OrderInference/MyTest.fs(34,34): Error FS1109: A reference to the type 'System.Collections.Generic.IEnumerable'1' in assembly 'System.Runtime' was found, but the type could not be found in that assembly (FS1109) (MyTest)'
/Users/UserName/Projects/Xamarin/OrderInfer/OrderInference: Error FS1108: The type 'Lazy'2' is required here and is unavailable. You must add a reference to assembly 'System.ComponentModel.Composition, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089'. (FS1108) (OrderInference)
The 2nd error suggests I need to reference System.ComponentModel.Composition. Am I able to use it in Mono? If so, is there another assembly I need to reference?
EDIT:
Solution removed and reposted below as an answer
This problem can be solved by adding a reference to: 'System.ComponentModel.Composition'. In Xamarin's IDE, this is done by using the Edit References Dialog which can be found by right-clicking on the reference in your project. Go to the All tab and search for System.ComponentModel and just add the System.ComponentModel.Composition assembly.
I now have the following two assemblies installed:
System.Collections.Immutable.dll
System.ComponentModel.Composition.dll
My code now reads:
open System
open System.ComponentModel.Composition
open System.Collections.Immutable
type wordPairs = { pairs:ImmutableDictionary<string, string>; count:int}
let myPairs = {pairs = ImmutableDictionary.Create<string, string>(); count = 0}
Note: As gradbot pointed out (and Immo Landwerth later nitpicked about ;>> ), ImmutableDictionary is a abstract sealed class. And as such, it has no public constructors. So you need to use the .Create method.
ImmutableDictionary is abstract so new won't work. It does however provide a number of create methods.
ImmutableDictionary.Create<string, string>()

Getting Migrate.exe to work

I have been struggling on executing EF Migrate.exe to work.
My Solution has couple of projects. The migrations and the entities live in the project Data. The controllers and views live in Web.
I tried using the migrate.exe - however I am struggling getting the first argument (assembly) to be accepted. Documentations says:
Assembly: Specifies the name of the assembly that contains the
migrations configuration type.
I have tried:
migrate.exe "MySolution\DataProject\bin\Debug\Data.dll"
ERROR: Could not load file or assembly 'D:\\MySolution\\Data\\bin\\Debug\\Data' or one of its dep
endencies. The given assembly name or codebase was invalid. (Exception from HRES
ULT: 0x80131047)
Any idea what is going wrong?
After reading this, this, and this
I have (I think) what you need :
If you use migrate.exe against a .NET 4 assembly you NEED to rename the Redirect.config available in packages\EntityFramework.5.0.0\tools to migrate.exe.config and copy this to the SAME directory as migrate.exe. For running migrate.exe against a .NET 4.5 assembly you DO NOT NEED this copy, the migrate.exe.config must not exist.
The correct version of entity framework DLL must be in the SAME directory as migrate.exe. Correct version is packages\EntityFramework.5.0.0\lib\net40\ for running migrate.exe against a .NET 4 assembly. Correct version is packages\EntityFramework.5.0.0\lib\net45\ for running migrate.exe against a .NET 4.5 assembly
If you specify /StartUpDirectory= do not specify the path for /assembly example : C:\Tools\migrate.exe some.dll /StartUpDirectory=C:\Project\bin\.
If you don't specify a startup directory, then you need to specify the full path in the /assembly example : C:\Tools\migrate.exe C:\Project\bin\some.dll - In this scenario migrate.exe will not be able to load the some.dll's dependencies, unless you put all some.dll's dependencies and put it in the SAME directory as migrate.exe.
If you put the migrate.exe in the same path as your some.dll, then migrate.exe will be able to use the same EntityFramework.dll which your app uses, and can load all dependencies, and can load the some.dll without any path like C:\Tools\migrate.exe some.dll
If you put the migrate.exe in a separate tools folder like Im doing it needs the correct version of the EntityFramework.dll in the SAME directory as migrate.exe, it will need the /StartUpDirectory=<the path where you target dll is present> clause, and you should specify the name of the assembly without the path like : C:\Tools\migrate.exe some.dll /StartUpDirectory=C:\Project\bin\
Heres the powershell commmand I use :
$SolutionPath = (Resolve-Path '..').Path
$ToolsPath = "$SolutionPath\Build\Lib\"
task db {
$migrator = $ToolsPath + 'Migrations\migrate.exe'
$migrateCommand = "$migrator zasz_me.dll /StartUpDirectory=$SolutionPath\zasz.me\bin\ /connectionStringName:FullContext /startUpConfigurationFile:$SolutionPath\zasz.me\Web.config /verbose"
Write-Host $migrateCommand
Invoke-Expression $migrateCommand
}
I answered a similar question here on how to override connectionstring through parameters to migrate.exe. I have yet to get it working without specifying a web/app.config file.
https://stackoverflow.com/a/14138797/134761

Activation error occured while trying to get instance of type LogWriter, key ""

I am getting this error while loggin into eventviewer. I am looging the exception in event viewer as well as rolling flat file. If i remove the eventviewer section then rolling flat file works perfectly, but only when i add this it gives the exception
{"Resolution of the dependency failed, type =
\"Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter\", name =
\"(none)\".\r\nException occurred while: while resolving.\r\nException
is: InvalidOperationException - The type TraceListener cannot be
constructed. You must configure the container to supply this
value.\r\n-----------------------------------------------\r\nAt the
time of the exception, the container was:\r\n\r\n Resolving
Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterImpl,LogWriter.default
(mapped from Microsoft.Practices.EnterpriseLibrary.Logging.LogWriter,
(none))\r\n Resolving parameter \"structureHolder\" of constructor
Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterImpl(Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder
structureHolder,
Microsoft.Practices.EnterpriseLibrary.Logging.Instrumentation.ILoggingInstrumentationProvider
instrumentationProvider,
Microsoft.Practices.EnterpriseLibrary.Logging.ILoggingUpdateCoordinator
updateCoordinator)\r\n Resolving
Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder,LogWriterStructureHolder.default
(mapped from
Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder,
(none))\r\n Resolving parameter \"traceSources\" of constructor
Microsoft.Practices.EnterpriseLibrary.Logging.LogWriterStructureHolder(System.Collections.Generic.IEnumerable1[[Microsoft.Practices.EnterpriseLibrary.Logging.Filters.ILogFilter,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35]] filters,
System.Collections.Generic.IEnumerable1[[System.String, mscorlib,
Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]
traceSourceNames,
System.Collections.Generic.IEnumerable1[[Microsoft.Practices.EnterpriseLibrary.Logging.LogSource,
Microsoft.Practices.EnterpriseLibrary.Logging, Version=5.0.414.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35]] traceSources,
Microsoft.Practices.EnterpriseLibrary.Logging.LogSource
allEventsTraceSource,
Microsoft.Practices.EnterpriseLibrary.Logging.LogSource
notProcessedTraceSource,
Microsoft.Practices.EnterpriseLibrary.Logging.LogSource
errorsTraceSource, System.String defaultCategory, System.Boolean
tracingEnabled, System.Boolean logWarningsWhenNoCategoriesMatch,
System.Boolean revertImpersonation)\r\n Resolving
Microsoft.Practices.EnterpriseLibrary.Logging.LogSource,General\r\n
Resolving parameter \"traceListeners\" of constructor
Microsoft.Practices.EnterpriseLibrary.Logging.LogSource(System.String
name,
System.Collections.Generic.IEnumerable1[[System.Diagnostics.TraceListener,
System, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089]] traceListeners,
System.Diagnostics.SourceLevels level, System.Boolean autoFlush,
Microsoft.Practices.EnterpriseLibrary.Logging.Instrumentation.ILoggingInstrumentationProvider
instrumentationProvider)\r\n Resolving
System.Diagnostics.TraceListener,Event Log Trace Listener\r\n"}
I had the same problem and it was due to an error in my configuration file. I referenced trace listeners from my categorySources section which did not exist in my listeners section. I removed the categories and the mappings (i did not use them anyway) and then it worked. I guess you can validate your configuration file in the configuration console and then it will tell you what the problem is.
1 - Make sure you are referencing the correct DLLs
Microsoft.Practices.EnterpriseLibrary.Logging
Microsoft.Practices.EnterpriseLibrary.Common
2 - Make sure your configuration file is in the right location (in the same project or in a references project)
3 - Make sure your configuration file is correct. Editing it with the Enterprise Library Configuration Tool, nothing should be in red. Try expanding all trace listeners, categories, etc. The most common error is that one of the Special Categories is pointing to a non existing Listener.
I had a similar experience with ExceptionHanlder., I switched over to using Unity container directly after playing around with intro material re: logging.
I basically just copied the examples from the Help files and briefly wondered why it wasn't working and errored on Type Resolution; Could not resolve.
The answer was simple enough. I had only "played" with logging prior to switching to Unity container but the examples I was using/copying were using both Logging and Exception Handling injection.
Since I hadn't "played: with Exception Handling in 5.0, there were no entries for this in the configuration file, hence the reason why Unity could not resolve.
Solution: take 5 seconds to add the ExceptionHandling block into the config file using the tools and I was good to go and keep on "playing".
Unity needs the entries for each resolved block in the config file even if they are not Named / customised. This is rediculously obvious but easily overlloked if you are hacking away with example code for learning purposes.
I got this error because a database listener was set with a connection string that didn't exist.
To help diagnose, comment out the listener lines and then add them again one by one.
I got this error when moving the app to another server, and in my case, it was the initializeData field, which sets the path for the log file, was not valid, and it was not able to create the log file at startup.
When i edited and put a valid path for the log to be created, it worked ok.
Hope it helps someone.

Strange Fsi.exe behavior

I'm observing some strange behavior when using the F# interactive interpreter.
Running the following code:
let getType1 = Type.GetType("namespace.does.not.exist, doesntexistlib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",false);;
let getType2 = Type.GetType("namespace.does.not.exist, doesntexistlib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null",false);;
results in fsi catching a FileLoadException even though the throwOnError parameter is set to false. The first time it returns a null second time the exception occurs.
Running the same code in a regular program (not interactively) results in expected behavior where getType = null.
Does FSI.exe stop on all exceptions? Is it possible to set FSI to ignore these exceptions?
Based on the stack trace, it looks like FSI is hooking into its AppDomain's assembly resolution. Unfortunately FSI is throwing the exception itself when it can't resolve the assembly - this isn't being generated by framework code, and that's why your throwOnError parameter isn't being respected - FSI's exception is just propagating upwards and then being caught at the top level. To me, this looks like a bug in FSI, but it may be that the available hooks in the AppDomain's assembly resolution process don't provide FSI with enough information to determine when it's okay to throw.
EDIT - If you look into the source file fsi.fs (included in the F# distribution in the source/fsharp/Fsi directory), you can see where this handler is hooked up (it's in the frighteningly named MagicAssemblyResolution module). It appears that FSI needs to hook into the resolution process so that assemblies registered via the #r directive can be found, but I can't tell at a glance where things are going wrong, or why no exception is thrown all the way to the top level the first time you try to resolve an invalid assembly.

Resources