Although I love the idea of F# type providers my first serious attempt to use them crashed hard.
I was going to connect to a service (WCF) with WsdlService<"http://someurl/some.svc?wsdl">
It fails epicly with:
The type provider
'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders'
reported an error: tmp6E6C.cs(9409,26): error CS0644:
'System.ComponentModel.PropertyChangedEventHandler' cannot derive from
special class 'System.MulticastDelegate'
c:\Windows\Microsoft.NET\Framework\v4.0.30319\mscorlib.dll: (Location
of symbol related to previous error)
and a lot of other warnings which probably are not relevant:
tmp6E6C.cs(290,28): warning CS0436: The type
'System.Data.DataRowState' in
'c:\Users\someuser\AppData\Local\Temp\tmp6E6C.cs' conflicts with the
imported type 'System.Data.DataRowState' in
'c:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Data.dll'. Using
the type defined in 'c:\Users\someuser\AppData\Local\Temp\tmp6E6C.cs'.
tmp6E6C.cs(9427,17): (Location of symbol related to previous warning)
Is this a known feature ;-) or am I using it wrong?
I unfortunately cannot post the WSDL, and its rather large with a lot of types in it so I must admit I am somewhat lazy and have not trimmed it down either. OTOH if I did know what part of the WSDL was offending or creating this error I would of course have put it here.
To change the WSDL is not an option either, so I am mainly interested in knowing why F# WSDL type providers can not handle this (WCF) WSDL, or what I am doing wrong.
It works excellent when consumed by C# and svcutil.exe from VS2010.
I have tried all the params to the WsdlTypeProvider and they do give the same result (except ForceUpdate of course). Should I be consuming these services in another way with F#?
===============================================================================
Added info (since I am new and didnt want to answer. dont ask why :):
Thank you all answering/commenting.
I did go partly this way may self (manually using svcutil). As I tried to say above, I tried to use svcutil by hand, and it fails when compiling the generated C# code (in a library besides the F#).
That is, I did the following:
1) Create the contract by setting up a reference in VS 2010 GUI. This works as expected
2) Try to create it by using svcutil from cmd-line. Then the compile of that file fails with same error.
As it seems from my point of view what happens in svcutil from cmd-line and what happens when using svcutil (or what is used) from the GUI adding the same service does not generate the code with the same parameters. I guess this is partly controlled by the fact that what I try to consume is a WCF service and not a "clean" WSDL/webservice, and the type provider assumes that I try to use a "clean" webservice.
I did not manage to find any params for svcutil takeing care of this, or any possible combinations of params, not saying that I did try all permutations of combinations, but trying the ones probable based upon (trying to) deep reading the documentation of svcutil (and I am not entirley new at using it from cmd-line).
So far I have concluded that it is some "missing" params to svcutil which causes this, and that the F# type provider is not at fault. I would still very much like to solve it somehow, still using F# type providers, but a fallback is to generate the code by GUI in C# and then reference that part of code in F# again. That is not the elegant solution I was trying to achieve, since I do have a lot of services and I would very much like to create such a nice way of prototyping and testing those services.
Another fallback would of course also give up the whole F# part and just go with some unit-testing etc., but that again is defating the purpose of sneaking in F# and learning at same time ;-)
The WSDL type provider (and a few others) are using SvcUtil in the background to do the heavy lifting. If you open ProcExp of taskmgr or some similar tool, you can see the SvcUtil process getting spawned after pasting the TP code into Visual Studio. With ProcExp at least, you can see the full command line with arguments which was used.
So find out exactly what SvcUtil command line was invoked by the TP for your service, and check if it works outside of the F# environment.
The fact that SvcUtil works from C#/VS 2010 is interesting. I assume if you are using F# TPs you are on VS 2012 right now. If so, the version of SvcUtil itself might be different, which could be related.
The specific error would appear to be the same as explained here, so you might have some incomplete annotations in your service code.
I am not able to leave this issue ...
I have now done the following:
Run svcutil with plain vanilla setting: svcutil http://some.address/some/path.svc
Run with some more setting: svcutil /r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\System.dll" /r:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework.NETFramework\v4.5\System.Data.dll" http://some.address/some/path.svc
This does generate the follwowing differences in the C# file (it is present in 1) and not present in 2) obviously):
namespace System.ComponentModel
{
using System;
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.SerializableAttribute()]
public partial class PropertyChangedEventHandler : System.MulticastDelegate
{
public PropertyChangedEventHandler(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) :
base(info, context)
{
}
}
}
namespace System.Data
{
using System;
using System.Runtime.Serialization;
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.FlagsAttribute()]
[System.Runtime.Serialization.DataContractAttribute(Name="DataRowState", Namespace="http://schemas.datacontract.org/2004/07/System.Data")]
public enum DataRowState : int
{
[System.Runtime.Serialization.EnumMemberAttribute()]
Detached = 1,
[System.Runtime.Serialization.EnumMemberAttribute()]
Unchanged = 2,
[System.Runtime.Serialization.EnumMemberAttribute()]
Added = 4,
[System.Runtime.Serialization.EnumMemberAttribute()]
Deleted = 8,
[System.Runtime.Serialization.EnumMemberAttribute()]
Modified = 16,
}
}
Which again makes the file compile in 2) and is as expected otherwise.
The somewhat strange part then is: Why isnt System.dll used in F# wsdl providers when running svcutil? System.Data.dll I kind of understand, since that isnt default used when running svcutil (at least according to the documentation).
OTOH I think also that the documentations says that IF the assemblies are in the GAC it should use them. So how do I verify they are there, and/or load them to the assembly if not?
Running gacutil -i System.dll (on version 4.5 of the System.dll) gives:
Failure adding assembly to the cache: An attempt was made to load a
program with an incorrect format.
Is it some 64/32 bit issue? (Im on a 64 bit windows if that does have any relevance)
Or to rephrase the problem: How do I get System.dll and System.Data.dll to part of the references when running svcutil when I cannot add the references directly through the WsdlProvider-part?
Im pretty sure it does not use System.dll since if I add the collectiontype param to wsdlprovider:
WsdlService<"http://some.url/some/path.svc", "c:\\temp\\wsdl\\some.wsdlschema", true, ".", true, true, false, false, "System.Collections.Generic.List'1">
it also complains with the following:
The type provider
'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders'
reported an error: Error: No type could be loaded for the value
System.Collections.Generic.List'1 passed to the /collectionType
option. Ensure that the assembly this type belongs to is specified via
the /reference option.
which should have been available directly if System.dll was referenced (I think).
Any ideas to further investigate or solve this issue?
Related
I'm trying to use a 3rd party DLL (WinSCP .NET assembly) in Dolphin 6.1b2. I've registered the DLL and generated a TypeLib in Windows 7.
In Dolphin I successfully used the component wizard to generate the interfaces but when I try to register the control and TypeLib I get errors. On the registering the control I get
WinSCPnet.dll was loaded but DllRegisterServer entry point could not be found.
Does anyone have any idea why it's failing? I have also asked the author of the DLL and he's leaning toward a Dolphin problem since the registration worked in Windows.
The DLL is a .NET assembly, import the generated TLB.
Downloaded ".NET assembly/automation package" from: https://winscp.net/eng/download.php
Unpacked, registered as per included readme_automation.txt.
See also Downloading and Installing WinSCP .NET Assembly
Started fresh Dolphin, imported the .tlb, generated with WinSCP prefix (so the classes wouldn't start with _).
Opened workspace, imported the WinSCP_Constants Pool, converted start of the C# example (https://winscp.net/eng/docs/library#example):
opts := WinSCP_SessionOptions new
protocol: Protocol_Sftp;
hostName = 'example.com';
userName: 'user';
password: 'mypassword';
sshHostKeyFingerprint: 'ssh-rsa 2048 ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff:ff';
yourself.
Got working object back ...
EDIT: Your WinSCP forums notion "in order to use it within dolphin you need to have its tools register the dll and tlib" is wrong. The COM "source" needs to be registered only once (In case of "old-school" COM server, you can either use regsvr32 or dolphin - both does the same; in case of .NET assembly you have to use the .NET incantation). Only thing really needed on dolphin side is to import previously registered library.
If there is .TLB, I'd go for .TLB, otherwise try my luck with .DLL. Sadly, for some standard COM interfaces Microsoft never made typelibs available, so it's even worse there (use C/C++, or create struct/interface tables by hand).
Edit 2 - further questions:
1) can you explain the relationship between the typelib and the library class which "i create" ( i.e. dolphin tutorial in help)
Dolphin creates smalltalk classes to mirror the COM types / structures. You use these to instantiate COM types from Smalltalk, call their methods, pass them (and also primitive types such as strings, integers, ...) as arguments and get Smalltalk types for returned values (Dolphin does all the conversions for you, so you can +- forget you are calling foreign code).
2) an example of the method you implemented mapping the library class to the winscp interface.
I implemented nothing, I just used the generated wrapper (in background, WinSCP COM object - SessionOptions - got created, and had some properties set).
basically, i just said:
var opts = new WinSCP.SessionOptions().
opts.Protocol = Protocol.Sftp;
opts.HostName = .........
Just look at WinSCP Automation documentation / examples, and then convert it to smalltalk-speak (and hopefully, it should auto-magically work ;-).
3) where are the smalltalk methods protocol:, hostName:, etc defined? i searched the image and they are not there. how did you know to use those method names?
Since SessionOptions (represented by [PREFIX]_SessionOptions class in Dolphin) is an IDispatch interface (subclass of IDispatch in Dolphin), all the method calls are dynamic in nature. You just do the right things (& catch possible failures at necessary granularity), and it will "just work (tm)".
Smalltalk sibbling is the #doesNotUnderstand: aMessage method.
I created a new Metro Split App in C++ using VS2012 on Win8 (both RC). Everything compiled and worked out of the box. I then changed went through and changed the generated namespaces to my own. After some trials and tribulations, I got everything to compile with no warnings, errors, nor messages. The app (as it comes in the project template) runs fine.
However, if I try to edit either of the generated xaml files (ItemsPage.xaml or SplitPage.xaml) I get a "Markup error" on the first line:
The name "LayoutAwarePage" does not exist in the namespace "using:A.B.Product.Client.Common".
The definition of the class is:
namespace A{ namespace B { namespace Product { namespace Client { namespace Common
The code compiles fine, and runs fine. This only happens in design mode.
UPDATE: I added a new xaml file and (after fixing up the namespaces again) everything worked.
Please let me know if any additional information is needed.
The name of the WinMD file produced by your project must be some prefix of the namespaces in which the public WinRT types are defined. Given that your type is in the A.B.Product.Client.Common namespace , the WinMD file must have one of the following names:
A.winmd
A.B.winmd
A.B.Product.winmd
A.B.Product.Client.winmd
A.B.Product.Client.Common.winmd
The public types must also be defined in the WinMD file with the longest prefix that matches the namespace. So, if you have both A.winmd and A.B.winmd, the type A.B.MyClass must be defined in A.B.winmd.
So, why does your code work at runtime but not in the designer? The naming rules for public types only apply to types defined in Windows Runtime components (for C++, DLL files), not for applications (EXEs).
However, to be able to instantiate your user-defined types (including LayoutAwarePage), the designer will load your project's EXE as a DLL, so the naming rules must be followed.
I had a similar bug, but then I closed VS, deleted the .suo, and reloaded the project and everything worked just fine.
I try to mock an internal interface in Silverlight 4, using moq-silverlight 4.0.10827.0.
I get an error "Can not create proxy for types that are not accessible." in a Castle.DynamicProxy.Generators.GeneratorException.
I have [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] in the assemblyInfo of the tested assembly. I do not have any signed assemblies.
Try including the public key as well:
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
And make sure you also make the internals visible to the unit test assembly (assuming they're in a different assembly).
The InternalsVisibleTo switch works only in this scenario: You have to apply it in the assembly containing the internals you want to be visible to another assembly. If it would work when you specify it in an assembly who wants to consume those internals, then it would be a great security leak!
I have been trying to use protobuf-net with MonoTouch but I have no idea how, and despite having heard that it is possible, I haven't been able to find any tutorial or any example that actually work.
It was confirmed by Marc Gravell on his blog that it does work on MonoTouch. I have also looked through the blogs of the two people he states in this article, but I haven't found anything related to protobuf.
Having no lead on the subject, i decided to download protobuf-net and try it out anyway. So I created the following object for testing purposes :
[ProtoContract]
public class ProtoObject
{
public ProtoObject()
{
}
[ProtoMember(1)]
public byte[] Bytes { get; set; }
}
and I tried to send it through WCF from a service running on windows using a [ServiceContract] interface with
[OperationContract]
ProtoObject GetObject();
but the instance of ProtoObject recieved on the device is always null. This is not really unexpected since i have read that to make protobuf-net work with WCF you need to modify the app.config/web.config.
It's a little hard to accomplish since a MonoTouch project has no app.config, but I did not yet give up. To replace the app.config, I tried to add the ProtoEndpointBehavior to the client's endpoint's behaviors programmatically, and there I hit a wall. ProtoBuf.ServiceModel.ProtoEndpointBehavior, available on .NET 3.0 implementation of protobuf-net is not available on the iOS release.
How would I go about using protobuf-net to deserialize objects received from a windows-based WCF endpoint using protobuf-net serialization.
It is actually pretty much the same as described in this blog entry by Friction Point Studios. Since meta-programming on the device is not really an option, the trick is to pre-generate a serialization dll. This can be done by creating a small console exe (this is just a tool - it isn't designed to be pretty) that configures a RuntimeTypeModel (by adding the types you are interested in), and then call .Compile(...):
var model = TypeModel.Create();
model.Add(typeof (ProtoObject), true);
model.Compile("MySerializer", "MySerializer.dll");
This generates a serializer dll; simply reference this dll (along with the iOS version protobuf-net), and use the serializer type in the dll to interact with your model:
var ser = new MySerializer();
ser.Serialize(dest, obj); // etc
Just to bring this up to date there are a few issues with using WCF + Protobuf on MonoTouch. As you have observed the current releases of System.ServiceModel and protobuf light for ios don't include all the necessary bits.
However if you go and get the full System.ServiceModel from the Mono repository on GitHub and build it against the full Protobuf source then you can get it to work; I have done so.
You need to generate a serialisation assembly using the precompile tool then edit the ProtoOperationBehavior attribute to give it some way to reference your serialisation assembly. All the changes are too extensive to document here but it can be done and it is a lot faster than DatacontractSerializer which is pretty awful on iOS.
I am trying to create an instance of a COM object. I have the class name that implements the interface and I get a CLSID by using CLSIDFromProgID(). So since I am getting a CLSID I thought everything should be fine from now on. However when I do a call to CreateInstance and pass in the CLSID, I get an error saying "Class not registered". Also I get this error only in some computers. It runs error free on several computers. I don't understand where the problem could be. Is my registry dirty? Does anyone know what is going on here? Thanks for your help!
I just want to add that this is a .NET COM class. The appropriate entries are in the registry and the DLL is in the GAC.
CLSIDFromProgId is simply looking up the ProgId's name in the registry and translating it to a CLSID, it doesn't have to look at anything beyond the registry or even check that something is actually implementing that CLSID.
When you call CreateInstance on the CLSID, Windows will look up in the registry to find out how the object should be instantiated (usually a exe or dll). It will then try to load the dll (or start up the exe) and create the object from it.
There is a lot of documentation in MSDN on the processes involved, for example see "COM Class Objects and CLSIDs", and if you do a lot of COM work it is worthwhile learning the process from first principals since it can save a lot of time and hassle when debugging this type of issue.
It's a two step process in the registry. You used the ProgID to get the CLSID. Then, when you call CreateInstance, COM then uses the CLSID to find the path to the dll. You can used regedit yourself to lookup the CLSID and see what that entry looks like.
Thanks for your answers. The .Net assemblies were registered properly and were present in the GAC. One application that absolutely confirmed this was Process Explorer. You can view the dlls that are loaded by each application. So from here I was able to see if the application that was instantiating the COM objects was actually able to load the DLLs or not. I found out that this was indeed happening. The problem was due to different Regional settings. We found that the application threw an exception when the region was not set to US. This issue was fixed. The error message "Class not registered" was not very helpful. Thankfully it was a quick fix.
Using shell32 as an example, you can create a new instance like so;
var shl = (Shell) Activator.CreateInstance(Type.GetTypeFromProgID("Shell.Application"));
This will aquire a refernce to an existing component;
var shl2 = (Shell) Marshal.GetActiveObject("Shell.Application");
Here's a reference to how to do the same in IronPython.
** Note, this used the progid, clsid would be nearly identical, just use Type.GetTypeFromCLSID({GUID}).