I am following the MSDN tutorial for the WsdlService type provider found here. When I run it at home, it works as expected. When I write the same code at work, I am getting a design time exception:
The type provider
'Microsoft.FSharp.Data.TypeProviders.DesignTime.DataProviders'
reported an error: Error: Cannot obtain Metadata from
http://msrmaps.com/TerraService2.asmx?WSDL
Work does use a proxy and I have to alter the web.config to use a default proxy when consuming WSDL from a C# project in VS2012. When I looked at the parameters for the type provider, I don't see a mention about a proxy. Does anyone have any suggestions?
Thanks in advance.
Expanding on Tomas's answer...
This is a common pattern in the built-in type providers today:
At design time, if you need any kind of non-default configuration (e.g. credentials, proxy config, ...), the type provider will not work. You need to download some schema file locally (e.g. DB schema file, ODATA $metadata file, WSDL schema file...), and point the type provider at that, usually by passing LocalSchemaFile="...", ForceUpdate=false in the static constructor. This feeds the TP all the info it needs to generate the types.
Then, you set all of your non-default config programmatically on the objects that are created for you, so that everything works at runtime.
Here's another example of essentially the same issue, where this pattern is used to set credentials.
In the case of WSDL, below is the programmatic approach to set the proxy after-the-fact (i.e. step #2). Cribbed entirely from this answer, which is exactly what you want, in C#. You'll probably need to play with this a bit to make it work for you.
#r "System.ServiceModel.dll"
#r "FSharp.Data.TypeProviders.dll"
open Microsoft.FSharp.Data.TypeProviders
type Terra = WsdlService< ServiceUri="N/A", ForceUpdate = false,
LocalSchemaFile = #"C:\temp\terra.wsdlschema">
let terra = Terra.GetTerraServiceSoap()
let binding = terra.DataContext.Endpoint.Binding :?> System.ServiceModel.BasicHttpBinding
binding.ProxyAddress <- System.Uri("http://127.0.0.1:8888")
binding.BypassProxyOnLocal <- false
binding.UseDefaultWebProxy <- false
terra.GetPlaceList("New York", 1, false)
I'm not connecting through a proxy, so I have no way of actually testing this, but I think you should be able to use local WSDL file to load the type provider in the designer.
Try downloading the WSDL schema (from http://msrmaps.com/TerraService2.asmx?WSDL) and saving that to a local file (such as C:\temp\terra.wsdlschema). Then you should be able to write:
#r "System.ServiceModel.dll"
#r "FSharp.Data.TypeProviders.dll"
open Microsoft.FSharp.Data.TypeProviders
type Terra = WsdlService< ServiceUri="N/A", ForceUpdate = false,
LocalSchemaFile = #"C:\temp\terra.wsdlschema">
let terra = Terra.GetTerraServiceSoap()
terra.GetPlaceList("New York", 1, false)
The ServiceUri parameter seems to be required, but it should be ignored if you add ForceUpdate=false. It should only require the cached WSDL file. I'm not entirely sure how to configure the runtime to use your config file setting, but I'm sure this can be done in some way (either it just works or you can pass something to the GetTerraServiceSoap method).
Sadly, the type provider does not statically know (at design time) where to look for the config file, so it ignores it.
Related
I am using SQLProvider from NuGet (https://www.nuget.org/packages/SQLProvider/ v1.1.42) in an F# project to access our MSSQL database.
I am referring to the sample code from here, https://fsprojects.github.io/SQLProvider/core/programmability.html and also the source code tests on GitHub, https://github.com/fsprojects/SQLProvider/blob/master/tests/SqlProvider.Tests/scripts/MySqlTests.fsx.
#r #"....\packages\SQLProvider.1.1.42\lib\net451\FSharp.Data.SqlProvider.dll"
#r #"....\System.Data.Linq.dll"
open System
open FSharp.Data.Sql
open FSharp.Data.Sql.Common
open System.Data.Linq
type SeriesResult = { .. fields .. }
[<Literal>]
let ConnectionString = #"connStr"
type Sql = SqlDataProvider<
ConnectionString = ConnectionString,
DatabaseVendor = Common.DatabaseProviderTypes.MSSQLSERVER>
let db = Sql.GetDataContext()
let test =
[
for f in db.Procedures.MyStoredProcedure.Invoke("param").ResultSet do
yield f.MapTo<SeriesResult>()
]
I need to access results from the call to MyStoredProcedure, but ResultSet errors with error FS0039: The field, constructor or member 'ResultSet' is not defined". I also get this for ColumnValues, and on MapTo (presumably because the type is unknown).
Is there an additional library I should be referencing?
I have: FSharp.Core, FSharp.Data, FSharp.Data.SqlProvider, mscorelib, System, System.Core, System.Data, System.Data.Linq, System.Xml.Linq
Thanks!
(wanted to tag with SQLProvider - but can't!)
One possible reason for this is that the intelli-sense thread probably timed out waiting for a response from the SQL provider.
The stored procs and the set of types to carry the result ResultSet are computed lazily (when you type the .). This is good in one way as it means the provider doesn't introspect the entire database on instantiation, pulling in lots of stuff you're probably not going to use. However it does have the side effect, of needing to do a non-trivial amount of work in the . completion on the first request, we cache the result after that. I believe Microsoft have a metric that says any intelli-sense work should complete in 250ms, but what the actual thread timeout is I'm not sure. With a language like C# and F# hitting a response target of 250ms can be a big ask on large solutions, but throw a database in the mix (even a small local database) this becomes a very hard target to hit.
Quite why it didn't recover and try again until you added the references, will only be known to Visual Studio; Usually however just closing and re-opening the file is enough. In rare cases unload the project from the solution and reload.
I'm having some problems with the freebase api. I have managed to put a key to the freebase provider so I don't see any 403 errors, relating quota restrictions. But since I used a google api key, commons is not being recognized when I hit "alt + enter". But while I'm writing, the provider manages to show me data.
[<Literal>]
let FreebaseApiKey = "AIzaSyCOn15-T31Ls"
type FreebaseDataWithKey = FreebaseDataProvider<Key=FreebaseApiKey>
let dataWithKey = FreebaseDataWithKey.GetDataContext()
let travelDestinations = dataWithKey.Commons.Travel.``Travel destinations``
let all = travelDestinations |> Seq.toList
let first = all.Head.Name
As you can see, I have access to Travel Destinations, so the provider shows me data correctly but when I execute it:
Script.fsx(17,38): error FS0039: The field, constructor or member 'Commons' is not defined
The weird thing is that if I delete the google key, and use the provider, this error does not happen. Any clues?
In a provider like freebase, we need to do things asynchronously, and that unfortunately causes the error reporting not to be very good (see https://github.com/fsharp/fsharp/issues/280)
What's probably happening is that freebase is returning errors due to the api key not being right or something similar, and does errors are not surfacing, as the toplevel objects are already cached. You can either look under Fiddler to see the json being returned, use data.DataContext.SendingQuery or data.DataContext.SendingRequest, or clean the cache by deleting the FreebaseSchema and FreebaseRuntime folders under your temporary internet files system folder.
We recently tried to change this to cause errors to surface by generating the toplevel types synchronously, but that caused other problems (https://github.com/fsharp/FSharp.Data/issues/522)
How can I start a process in mono using the Process.Start API? My best guess would be the following (in F#):
let start (path : string) =
System.Diagnostics.Process.Start("/usr/bin/env", sprintf "mono \"%s\"" path)
This seems to work in linux, but it is obviously not correct in Mono/Windows. Is there any way I could obtain the location of the mono executable programmatically?
It turns out that you can basically just Process.Start with just the target executable path, no need to specify the mono executable.
You can find the location of Mono on windows using the following registry keys
$version = HKLM_LOCAL_MACHINE\Software\Novell\Mono\DefaultCLR
$monoprefix = HKLM_LOCAL_MACHINE\Software\Novell\Mono\$version\SdkInstallRoot
where you use the version you found to find the mono prefix.
Taken from this page
Rather than starting a new instance of the CLR, you can start assemblies from within your existing instance. Microsoft documents the relevant functionality here: http://msdn.microsoft.com/en-us/library/yk22e11a%28v=vs.110%29.aspx. Mono implements this as well.
What you have to do is create a new AppDomain to provide you with an execution environment isolated from your current one, load an assembly in there, and execute it.
Example:
var domain = AppDomain.CreateDomain("Foo");
domain.ExecuteAssembly("Bar.exe");
I'm trying to develop a stand-alone client app that uses web services in a Glassfish container (Metro). About all I have to work from is a wsdl for the wervices I'm trying to use. The wsdl is rife with all kinds of 'wsp:Policy' tags. Looks like IssuedToken, Trust13, ecryption are all utilized.
So I generated some code from netbeans and JAX-WS. Everything went well, but when trying to run the client I get:
'WST0029:STS location could not be obtained from either IssuedToken or from client configuration for accessing the service http://localhost:8080/ ....'
That's when it occured to me that I know nothing about WSS. It doesn't look like any code was generated to deal with security. So, I'll have to go from scratch.
So where to start? Books? Tutorials?
TIA
Metro applies the policy in runtime from either the WSDL or the wsit-client.xml config file. That's why no code is generated related to policies. According to this post it is not possible at the moment to do programatically.
This tutorial explains pretty well some of the things you can do with WSS, and though everything do probably not apply in this case it's still a good read.
The simplest way I've found of generating a client with WSS support is by using the wsimport script from Metro:
cd metro/bin/
mkdir src target
./wsimport.sh -s src -d target -extension -Xendorsed -verbose YourService.wsdl
Then install Metro into your application server (copy the libs to the correct places or run the ant script):
ant -f metro-on-glassfish.xml
Then put your local WSDL file in your classpath (e.g. your resource folder), so Metro can get it at runtime to apply the policies from your generated YourService class:
private final static URL YOURSERVICE_WSDL_LOCATION;
// This is enough, you don't need the wsdlLocation attribute
// on the #WebServiceClient annotation if you have this.
static {
YOURSERVICE_WSDL_LOCATION =
CustomerService.class.getClassLoader().getResource("YourService.wsdl");
}
public YourService() {
super(YOURSERVICE_WSDL_LOCATION,
new QName("http://tempuri.org/", "YourService"));
}
And if you want WS-Addressing you might need to add the feature manually to your binding method (Metro has never generated it for me, so I always have to add it myself).
#WebEndpoint(name = "WSHttpBinding_IYourService")
public IYourService getWSHttpBindingIYourService() {
WebServiceFeature wsAddressing = new AddressingFeature(true);
IYourService service =
super.getPort(new QName("http://xmlns.example.com/services/Your",
"WSHttpBinding_IYourService"), IYourService.class,
wsAddressing);
return service;
}
I'm using CreateService to install a windows service on Windows XPE. I'd like to set things up so that only the Administrator can start/stop/pause/resume the service.
Right now I'm using the following to install the service:
schService = CreateService(schSCManager,
ServiceName,
ServiceDisplayName, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
binaryPathName, // service's binary (this program)
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
And the service ends up with security such that members of the PowerUsers group can start and stop the service. I've figured out that I can use sc sdshow to examine the security descriptor, and I've worked out an SDDL line that would do the right thing for us.
I've also learned that our Win XPE install doesn't have the sc.exe binary on it, so we can't really use that to setup this particular system.
So, what I need to know is: What are the APIs I need to use, to set the security descriptor on this service around the time I do the CreateService call. I'm completely unfamiliar with the Windows security APIs, so I just don't know where to start.
UPDATE: The answer is SetServiceObjectSecurity (below). Next question: What's the best way to setup the SecurityDescriptor? Is it best to get the default descriptor, then modify it? Or should I just create a completely new descriptor?
I'm not really familiar with Windows XP Embedded, but normally you would achieve what you are after using the SetServiceObjectSecurity function. Use the handle you get from CreateService and build a security descriptor that matches what you want.