F# Type Provider compiled as *.exe file - f#

Why I cannot create Type Provider as *.exe file with [<TypeProviderAssembly()>] and [<EntryPoint>] inside?
When I try to reference such TP using #r #"d:\TP\bin\Debug\MyTypeProvider.exe", I see the following:
test.fsx(3,1): error FS3031: The type provider 'd:\TP\bin\Debug\MyTypeProvider.exe' reported an error: Assembly attribute 'TypeProviderAssemblyAttribute' refers to a designer assembly 'MyTypeProvider' which cannot be loaded or doesn't exist. Could not load file or assembly 'file:///d:\TP\bin\Debug\MyTypeProvider.dll' or one of its dependencies. The system cannot find the file specified.
I need to have a type inference runtime in separate process, because it should be 64bit (unlike 32bit VS process). But I want to pack all things into one file, reference it from VS and start as external process.

Perhaps there's some good underlying reason for always looking for DLLs instead of EXEs, but I suspect this may be an arbitrary limitation.
I can get things to work in FSI if I supply the assembly's full name to the TypeProviderAssemblyAttribute constructor (e.g. [<TypeProviderAssembly("MyExe, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null")>]), but IntelliSense doesn't work and I can't use the TP from other projects. Consider filing a bug with the team - but it would probably help if you could justify why you need an EXE instead of a DLL for your scenario.

Related

F# IDE scripting support for accessing internal types in referenced assemblies

Usually for non-scripting C#/F# project, one can specify a InternalsVisibleTo attribute in the dependency assembly and be able to get intellisense for its internal types in the IDE. But in F# scripting, how would I configure the dependency assembly with respect to the IDE I'm using in order to get intellisense for internal types? Of course in order for the script to run by fsi I assume I'd need something like
[assembly:InternalsVisibleTo("fsi")]
But in order to get the IDE support should I also specify every known IDE in the dependency assembly? That doesn't seem to scale very well.
I did a code search and found this where fsc, fsi, compiler service assembly, and their strong name versions, etc. are all specified, seemingly to accommodate IDEs. This is exactly what concerns me and I don't want to litter my assemblies with these. Is there a better way?

Referencing an executable from F#

I've used F# to do some quick data-analysis using datastructures from another project. To do so, it needs access to this project; i.e. it needs an assembly reference - but the project is an executable.
I've tried this in F# interactive, and it almost works*; I can #I the appropriate path and #r the executable and a few support dll's - but I can't actually use em. And whatever I do, I can't get the reference into a compiled F# program: VS lets me add a reference just fine, and the appropriate compiler option -r:X:full\path\here.exe is correctly generated by the project, but none of the datastructures are present and the compiler complains of non-existent namespaces; it's as if the reference didn't exist. The application is 64-bit, which may be relevant. 64-bit dll's work fine.
(*) after setting fsi.exe to run in 64-bit mode it thinks it can load it, but actually using it returns FS0193: internal error.
How can I reference a managed 64-bit executable from an F# project?
To others with this same issue: as a workaround, I'm now compiling the executable as Any CPU (which will be executed in 64-bit mode, so behaves the same). This allows FSI and the compiler to reference it. Based on the questions referenced in the comments, this seems to be a known bug that will hopefully be fixed some day.

Using COM DLLs with FSI

Is there a way within FSI that I can reference and use registered COM components?
In a normal .fs compiled program I can simply reference the component in question and then open the relevant generated namespace(s). In a .fsx file, however, I can't seem to replicate this behaviour. I have tried using #r to reference the .dll directly, and I have tried using #I to point to the directory followed #r both with the library's "friendly" name and the file name, but nothing seems to work.
Are you only able to reference .NET assemblies from a .fsx? I don't really want to have to write/gen a wrapper assembly. I am hoping there might be a way to force FSI to take whatever steps the normal executable takes in order to provide the interop layer.
When you add a reference to a COM component in Visual Studio, it invokes a tool to generate a wrapper (standard .NET assembly) and then references the wrapper.
If you want to reference COM from fsx, you'll need to generate the wrapper yourself (or find the one generated by Visual Studio?) The tool that generates the wrapper that is called TlbImp.exe (see Type Library Importer on MSDN).

F# powerpack and distribution

I need arbitrary precision rational numbers, which I'm given to understand are available in the F# powerpack. My question is about the mechanics of distribution; my program needs to be able to compile and run both on Windows/.Net and Linux/Mono at least, since I have potential users on both platforms. As I understand it, the best procedure is:
Download the powerpack .zip, not the installer.
Copy the DLL into my program directory.
Copy the accompanying license file into my program directory, to make sure everything is above board.
Declare references and go ahead and use the functions I need.
Ship the above files along with my source and binary, and since the DLL uses byte code, it will work fine on any platform.
Is this the correct procedure? Am I missing anything?
You're essentially correct, arbitrary precision rational numbers are available only in PowerPack (BigInteger is part of .NET 4.0, but rationals are still F# specific).
However, you'll also need to distribute your program with F# runtime redistributable (that is the FSharp.Core.dll assembly). It contains some basic F# types (such as types used to represent functions) that are not a part of standard .NET runtime.
More information about F# Redistributable Package is available at MSDN
You can download the FSharp.Core.dll redist from Microsoft Downloads.
When you add a reference to your project, the compiler includes the name and version of the referenced library in your application. When the application starts, the runtime tries to locate the library in various places. So, to deploy your application on both .NET and Mono, you'll need to (somehow) distribute your application together with FSharp.Core.dll and FSharp.PowerPack.dll.
The F# Redistributable and F# PowerPack installers place the library to GAC (Global Assembly Cache) which is shared by all .NET apps on the computer. On Mono, you can get the same result by using the gacutil tool (from command line). In that case, you need to copy them somewhere (anywhere) and run this tool. Your application will find them in the GAC.
Alternatively, if you place the assemblies to the same folder as your application (exe file) then both .NET and Mono should locate them correctly as well and it should work. I believe that this is discouraged for versioning reasons (e.g. the globally installed file can be easily updated), but I don't think the license prohibits this form of deployment.
It seems that for creating .NET/Mono redistributable, using the second technique would be easier (as it allows simple xcopy depoloyment).

What happens when I load an assembly?

In my ASP.NET MVC application, I have the following setup:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<probing privatePath="bin;extras"/>
I have referenced assemblies located in the extras folder in the views and they have worked perfectly (using <%# Import Namespace="myNameSpace" %>).
My questions
What happens when that line is called?
Where is the assembly loaded?
Why is it that I can't overwrite the assembly located in the extras folder that contains myNameSpace with a newer version? (I get an error saying that the assembly is "open" in another program)
Is there a way to overwrite the assembly with a newer version without having the application restart?
1) Import doesn't actually do anything at runtime. It's a compile-time convenience that just lets you refer to types using their unqualified names such as Environment instead of System.Environment.
2) The assembly is loaded using normal assembly probing rules. The CLR checks various locations before these private probing paths so it's important to keep that in mind. If you reference a strong-named assembly and expect to find that assembly in a private probing path, an assembly with the same strong name (name, version, public key, etc) in the GAC would be preferred. This can sometimes lead to unexpected behavior and is usually caused by hard coding an assembly version in your AssemblyInfo.cs and forgetting to update it.
3) Once loaded, an assembly cannot be unloaded without unloading the AppDomain. But ASP.NET uses "shadow copying" which means assemblies are copied to a temporary path before being loaded. This should leave the original assembly unlocked and able to be overwritten. Off the top of my head, I am not sure why you'd be getting the error about locked assemblies. In a normal Windows application, this would be totally normal and expected. But ASP.NET is designed so that you can overwrite content, code, assemblies, etc while the application is running, which leads to #4.
4) In practice, no. Because an assembly cannot be unloaded, there is no way to upgrade an assembly without the web application being restarted. Technically speaking, you can load multiple versions of an assembly but this would not give you the desired results. Any compile-time references would still reference the old assembly and you'd get all kinds of invalid cast exceptions if you tried to use the new assembly. But as I said in #3, with ASP.NET upgrading assemblies is supposed to be as simple as replacing the files and should happen automatically. You shouldn't have to restart IIS or worker processes manually.
The following links may be of interest.
How the Runtime Locates Assemblies
Best Practices for Loading Assemblies
Shadow Copying Assemblies
Unloading Assemblies - Suzanne Cook
UPDATE
After reading a bit more on shadow copying, I think the reason you might be seeing the issue of locked assemblies in the extras folder is that ASP.NET probably only specifies the "bin" folder for shadow copying.
I think this is the same as a using statement in C#, it basically means that the namespace's classes are now available to be used in yoru page.
The assembly will be loaded into memory probably by the aspnetwp.exe process
If the assembly is currently being used you will get this error message
A restart is the safest way I know of doing this, you could use dependency injection or late binding to achieve the same result. I would jsut wonder why you would want to switch an assembly while the application is running?

Resources