4

In the construction of the internal representation for a provided type, I call indirectly in the quotation for the internal representation of my type, another dll, whose code I can modify.

Currently, when I consume the type provider, tells me it can't find such dll:

"Could not load file or Assembly xxxx or one of its dependency"

When I inspect VS using Process Explorer, though, I can see the dll XXX loaded... Are there anything to do to have the code in quotations accept code from outside dll ?

** update **

I tried with a simplified example, and it seems that it is possible to call such outside dll without any special thing to do. In my case, all the dll XXX depends on are loaded, I see them in Process explorer as well as in the modules windows when I debug devenv.exe itself....

I have no idea where to look to. Here is the inner exception.

** update **

If I copy the xxx dll and its dependencies in one of this path, the compiler works fine. I still wonder what can trigger devenv.exe to correctly show them loaded but not accessible.

=== Pre-bind state information ===
LOG: User = xxx\Administrator
LOG: DisplayName = bloombergapi, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
 (Fully-specified)
LOG: Appbase = file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/
LOG: Initial PrivatePath = NULL
Calling assembly : (Unknown).
===
LOG: This bind starts in default load context.
LOG: Using application configuration file: C:\Users\Administrator\AppData\Local\Microsoft\VisualStudio\11.0\devenv.exe.config
LOG: Using host configuration file: 
LOG: Using machine configuration file from C:\Windows\Microsoft.NET\Framework\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:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PublicAssemblies/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PublicAssemblies/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PrivateAssemblies/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PrivateAssemblies/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Microsoft/TemplateProviders/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Microsoft/TemplateProviders/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Platform/Debugger/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/CommonExtensions/Platform/Debugger/bloombergapi/bloombergapi.DLL.
LOG: Attempting download of new URL file:///C:/Program Files (x86)/Microsoft Visual Studio 11.0/Common7/IDE/PrivateAssemblies/DataCollectors/bloombergapi.DLL.

...

ANSWER

It seems impossible to call a function that takes as an argument a Type from another library. A union type works, but not a type proper... This is illustrated below

--Library.dll

namespace Library

module SampleModule = 
     type LocalUnion = | LocalUnion  of int

     type Localtype() = 
        member x.value = 2

--LibraryTP.dll

namespace LibraryTP

module Module =
   open System.Reflection
   open Samples.FSharp.ProvidedTypes
   open FSharpx.TypeProviders.DSL
   open Microsoft.FSharp.Core.CompilerServices

   let f a = 
     Library.SampleModule.sampleFunction a a 

   let g (a:Library.SampleModule.LocalUnion) = 
      let (Library.SampleModule.LocalUnion(v)) = a
      v

   let ftype (a:Library.SampleModule.Localtype) = 
        a.value

   let createTP ns =
       erasedType<obj> (Assembly.GetExecutingAssembly()) ns "Outside"
       |> staticParameter "file"
          (fun typeName (parameterValues:string) ->
               erasedType<obj> (Assembly.GetExecutingAssembly()) ns typeName
               |+!> (   provideProperty 
                           "test"                             //OK
                           typeof<float>                   
                           (fun args -> <@@  g ( f 2 ) @@>)      
                         |> makePropertyStatic
                     )
               |+!> (   provideProperty 
                           "test2"                             //KO
                           typeof<int>                   
                           (fun args -> <@@ ftype ( Library.SampleModule.Localtype())  @@>)   
                        |> makePropertyStatic   
                     )
                  )

   [<TypeProvider>]
   type public CustomTypeProvider(cfg:TypeProviderConfig) as this =
      inherit TypeProviderForNamespaces()

      do this.AddNamespace("TP", [createTP "TP"])

   [<TypeProviderAssembly>]
   do()

--Program.fs

   type sampleValue = TP.Outside<""> 

   [<EntryPoint>] 
   let main(args) = 
      let t = sampleValue.Test        //OK
      let tt = sampleValue.Test2      //KO 
nicolas
  • 9,549
  • 3
  • 39
  • 83

1 Answers1

10

Your assembly may be loaded into the different binding context. When quotation is deserialized it may try to load the assembly to the one binding context and this attempt may fail even if assembly was already loaded to another context. As workaround in your type provider design time assembly you can add handler to the AssemblyResolve event and try to find target assembly in the list of already loaded assemblies.

    do System.AppDomain.CurrentDomain.add_AssemblyResolve(fun _ args ->
        let name = System.Reflection.AssemblyName(args.Name)
        let existingAssembly = 
            System.AppDomain.CurrentDomain.GetAssemblies()
            |> Seq.tryFind(fun a -> System.Reflection.AssemblyName.ReferenceMatchesDefinition(name, a.GetName()))
        match existingAssembly with
        | Some a -> a
        | None -> null
        )
desco
  • 16,642
  • 1
  • 45
  • 56
  • That was it. thank you *very* much for the suggestion, I would not have thought of that in a million years. you are not so bad with those new typing machines. – nicolas Apr 29 '12 at 10:31
  • When I tried this, the needed assemblies were (apparently) not loaded, so I extended this idea to have the ResolveEventHandler also look for the "packages" folder in parent directories and look for a matching DLL in there. – Overlord Zurg Nov 08 '17 at 22:10