5 people like it.
Like the snippet!
AssemblyResolver.fs
Assembly resolver implementation required by .NET Framework MSBuild task to resolve different versions of assembly because of missing binding redirect functionality in MSBuild.
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
|
open System
open System.Diagnostics
open System.IO
open System.Reflection
module private ValueOption =
let mapNone initializer =
function
| ValueSome value -> ValueSome value
| ValueNone -> initializer ()
/// <summary>
/// Considers a path to load for satisfying an assembly ref and loads it
/// if the file exists and version is sufficient.
/// </summary>
/// <param name="filePath">Path to consider for load</param>
/// <param name="minimumVersion">Minimum version to consider</param>
/// <returns>loaded assembly voption</returns>
let private probe(filePath: string, minimumVersion: Version) : Assembly voption =
if File.Exists(filePath) then
let name = AssemblyName.GetAssemblyName(filePath)
if name.Version >= minimumVersion
then ValueSome (Assembly.Load(name))
else ValueNone
else ValueNone
let private loadFromCurrentDirectory fileName version =
Debug.WriteLine($"Considering {fileName}")
probe(fileName, version)
let private loadFromExecutingAssembly fileName version =
match Assembly.GetExecutingAssembly().Location with
| null -> ValueNone
| assemblyPath ->
let probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName)
Debug.WriteLine($"Considering {probingPath} based on ExecutingAssembly")
probe(probingPath, version)
let private loadFromAppDomain fileName version =
let probingPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName)
Debug.WriteLine($"Considering {probingPath} based on BaseDirectory")
probe(probingPath, version)
let private loadFromRequestingAssemblyPath version fileName assemblyPath =
let probingPath = Path.Combine(Path.GetDirectoryName(assemblyPath), fileName)
Debug.WriteLine($"Considering {probingPath} based on RequestingAssembly")
probe(probingPath, version)
let private onAssemblyResolve(args: ResolveEventArgs) : Assembly =
// apply any existing policy
let referenceName = new AssemblyName(AppDomain.CurrentDomain.ApplyPolicy(args.Name))
let version = referenceName.Version
let fileName = referenceName.Name + ".dll"
args.RequestingAssembly
|> ValueOption.ofObj
|> ValueOption.map (fun assemblyPath -> assemblyPath.Location)
|> ValueOption.bind (loadFromRequestingAssemblyPath version fileName)
|> ValueOption.mapNone (fun () -> loadFromAppDomain fileName version)
|> ValueOption.mapNone (fun () -> loadFromExecutingAssembly fileName version)
|> ValueOption.mapNone (fun () -> loadFromCurrentDirectory fileName version)
|> ValueOption.defaultValue null
[<CompiledName("Enable")>]
let public enable() = AppDomain.CurrentDomain.add_AssemblyResolve(fun _ args -> onAssemblyResolve(args))
|
namespace System
namespace System.Diagnostics
namespace System.IO
namespace System.Reflection
Multiple items
module ValueOption
from Microsoft.FSharp.Core
--------------------
[<Struct>]
type ValueOption<'T> =
| ValueNone
| ValueSome of 'T
member IsNone : bool
member IsSome : bool
member Value : 'T
static member Some : value:'T -> 'T voption
static member None : 'T voption
static member op_Implicit : value:'T -> 'T voption
val private mapNone : initializer:(unit -> 'a voption) -> _arg1:'a voption -> 'a voption
val initializer : (unit -> 'a voption)
union case ValueOption.ValueSome: 'T -> ValueOption<'T>
val value : 'a
union case ValueOption.ValueNone: ValueOption<'T>
val private probe : filePath:string * minimumVersion:Version -> Assembly voption
<summary>
Considers a path to load for satisfying an assembly ref and loads it
if the file exists and version is sufficient.
</summary>
<param name="filePath">Path to consider for load</param>
<param name="minimumVersion">Minimum version to consider</param>
<returns>loaded assembly voption</returns>
val filePath : string
Multiple items
val string : value:'T -> string
--------------------
type string = String
val minimumVersion : Version
Multiple items
type Version =
new : unit -> Version + 4 overloads
member Build : int
member Clone : unit -> obj
member CompareTo : version:obj -> int + 1 overload
member Equals : obj:obj -> bool + 1 overload
member GetHashCode : unit -> int
member Major : int
member MajorRevision : int16
member Minor : int
member MinorRevision : int16
...
--------------------
Version() : Version
Version(version: string) : Version
Version(major: int, minor: int) : Version
Version(major: int, minor: int, build: int) : Version
Version(major: int, minor: int, build: int, revision: int) : Version
type Assembly =
member CodeBase : string
member CreateInstance : typeName:string -> obj + 2 overloads
member CustomAttributes : IEnumerable<CustomAttributeData>
member DefinedTypes : IEnumerable<TypeInfo>
member EntryPoint : MethodInfo
member Equals : o:obj -> bool
member EscapedCodeBase : string
member ExportedTypes : IEnumerable<Type>
member FullName : string
member GetCustomAttributes : inherit:bool -> obj[] + 1 overload
...
[<Struct>]
type 'T voption = ValueOption<'T>
type File =
static member AppendAllLines : path:string * contents:IEnumerable<string> -> unit + 1 overload
static member AppendAllLinesAsync : path:string * contents:IEnumerable<string> * ?cancellationToken:CancellationToken -> Task + 1 overload
static member AppendAllText : path:string * contents:string -> unit + 1 overload
static member AppendAllTextAsync : path:string * contents:string * ?cancellationToken:CancellationToken -> Task + 1 overload
static member AppendText : path:string -> StreamWriter
static member Copy : sourceFileName:string * destFileName:string -> unit + 1 overload
static member Create : path:string -> FileStream + 2 overloads
static member CreateText : path:string -> StreamWriter
static member Decrypt : path:string -> unit
static member Delete : path:string -> unit
...
File.Exists(path: string) : bool
val name : AssemblyName
Multiple items
type AssemblyName =
new : unit -> AssemblyName + 1 overload
member Clone : unit -> obj
member CodeBase : string with get, set
member ContentType : AssemblyContentType with get, set
member CultureInfo : CultureInfo with get, set
member CultureName : string with get, set
member EscapedCodeBase : string
member Flags : AssemblyNameFlags with get, set
member FullName : string
member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
...
--------------------
AssemblyName() : AssemblyName
AssemblyName(assemblyName: string) : AssemblyName
AssemblyName.GetAssemblyName(assemblyFile: string) : AssemblyName
Assembly.Load(rawAssembly: byte []) : Assembly
Assembly.Load(assemblyRef: AssemblyName) : Assembly
Assembly.Load(assemblyString: string) : Assembly
Assembly.Load(rawAssembly: byte [], rawSymbolStore: byte []) : Assembly
val private loadFromCurrentDirectory : fileName:'a -> version:'b -> unit
val fileName : 'a
val version : 'b
type Debug =
static member Assert : condition:bool -> unit + 3 overloads
static member AutoFlush : bool with get, set
static member Close : unit -> unit
static member Fail : message:string -> unit + 1 overload
static member Flush : unit -> unit
static member Indent : unit -> unit
static member IndentLevel : int with get, set
static member IndentSize : int with get, set
static member Print : message:string -> unit + 1 overload
static member SetProvider : provider:DebugProvider -> DebugProvider
...
Debug.WriteLine(value: obj) : unit
Debug.WriteLine(message: string) : unit
Debug.WriteLine(message: string, category: string) : unit
Debug.WriteLine(format: string, [<ParamArray>] args: obj []) : unit
Debug.WriteLine(value: obj, category: string) : unit
More information