Using WCF in MonoDevelop / MonoTouch: how to use the app.config file? - mono

I have added a web reference to a WCF service in my MT project (using MonoDevelop 2.4.2 here).
I am trying to recycle the app.config file that is used by Visual Studio. I copied it over into my MT's root directory and specified "copy to output directory" in MonoDevelop. Still it does not work.
What is the correct way to use an app.config in MonoDevelop?
René

You can't use app.config files in Monotouch unfortunately. You have to create all the bindings yourself in code. In one of our projects, this is what we have done:
public static ServiceClient GetClient()
{
BasicHttpBinding binding = new BasicHttpBinding();
binding.OpenTimeout = new TimeSpan(0,0,10);
binding.CloseTimeout = new TimeSpan(0,0,10);
binding.SendTimeout = new TimeSpan(0,0,10);
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
binding.BypassProxyOnLocal = false;
binding.AllowCookies = false;
// snip - we set all the properties found in the serverside config file in code here
EndPointAddress endpointAddress = new EndpointAddress("https://www.domain.com/ServiceClient.svc");
ServiceClient client = new ServiceClient(binding, endpointAddress);
return client;
}
You need to go through and set EVERY property that is found in the server's app.config file, ensuring that the values match exactly, otherwise this won't work.
(If I've misunderstood your question, then I do apologise!).

I think you just need to properly name the .config file and place it in your output directory:
myapp.exe.config
I do not think MD does it automatically for you like VS does.

Related

WCF certificate security with Mono

I'm trying to migrate an existing application to Mono (v2.10.2).
Therefore I created a test WCF service with BasicHttpBinding and message security. The client works perfectly with .NET, but when running with Mono it fails.
The client factory is instantiated as follows:
//var certificate = CertificateUtil.GetCertificate(StoreLocation.LocalMachine,
// StoreName.My, X509FindType.FindBySubjectDistinguishedName, CertName, true);
var certificate = new X509Certificate2("certificate.pfx", "password");
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Message;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
var epa = new EndpointAddress(
new Uri("http://localhost:53076/Service1.svc"),
new X509CertificateEndpointIdentity(certificate));
var factory = new ChannelFactory<IService1>(binding, epa);
factory.Credentials.ServiceCertificate.DefaultCertificate = certificate;
factory.Credentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
factory.Credentials.ServiceCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;
factory.Credentials.ClientCertificate.Certificate = certificate;
var client = factory.CreateChannel();
In Mono the application fails within CreateChannel throwing the exception:
System.InvalidOperationException: The binding does not support any of the channel types that the contract 'IService1' allows.
I debugged into the Mono source code and found out that the problem is that AsymmetricSecurityBindingElement.InitiatorTokenParameter == null.
I'm new to Mono, maybe you could point me to a documentation/tutorial which covers this topic.
UPDATE:
With the aid of konrad.kruczynski the certificate object has a private key now. The exception is still the same. So this is not a certificate store issue.
Yes, certificates created on Windows usually does not contain private key. They can be found in some kind of cache. You should be able to create certificate with private key using this instruction. X509Certificate2 should consume the file without problems. You can also try procedure described here. In case of any problems just write.
It is also worth adding, that certificates created such way on Linux works perfectly on Windows too.
Update:
I'm not sure whether I understood your comment correctly. You can load PFX certificate using code like that:
var myCert = new X509Certificate2("filename.pfx", "password");
Given certficate contained key, it worked for me.

How can I configure a webservice in .NET 4 without using app.config

I have a .NET 4 project made of a EXE project and a class library. The class library contains a reference to a webservice (using WCF).
Everything works ok only if I have deployed the app.config file (that contains the info about the binding) along with my exe. How can I have everything configured by code without the need to deploy an app.config file (I don't want my users to change those settings).
Thank you.
Andrea
You can use the ChannelFactory class to generate proxies to your services.
Everything you configure through the configuration file can also be done using code.
You just need to instantiate an instance of the correct binding and configure its properties according to the service requirements on the other side.
For example:
private IDisposableService GetClient()
{
var netBinding = new BasicHttpBinding();
netBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
netBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Ntlm;
var factory = new ChannelFactory<IDisposableService>(netBinding, new EndpointAddress(new Uri(ServerUrl)));
factory.Credentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
factory.Credentials.Windows.ClientCredential = CredentialCache.DefaultNetworkCredentials;
var channel = factory.CreateChannel();
return channel;
}
interface IDisposableService : IYourService, IDisposable
{
}
Then you can simply use:
using (var proxy = GetClient())
{
// call proxy here
}
This is how I did it:
MyServiceResponseClient embEvalServiceClient = new MyServiceResponseClient (new BasicHttpBinding(),
new EndpointAddress(new Uri(url)));
if (embEvalServiceClient != null)
{
embEvalServiceClient.GetPendingEvalsCompleted += getPendingEvalsCompletedHandler;
embEvalServiceClient.GetPendingEvalsAsync(attemptId);
}

How to programmatically generate WSDL from WCF service (Integration Testing)

I am looking to write some integration tests to compare the WSDL generated by WCF services against previous (and published) versions. This is to ensure the service contracts don't differ from time of release.
I would like my tests to be self contained and not rely on any external resources such as hosting on IIS.
I am thinking that I could recreate my IIS hosting environment within the test with something like...
using (ServiceHost host = new ServiceHost(typeof(NSTest.HelloNS), new Uri("http://localhost:8000/Omega")))
{
host.AddServiceEndpoint(typeof(NSTest.IMy_NS), new BasicHttpBinding(), "Primary");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
host.Description.Behaviors.Add(behavior);
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.Open();
}
Does anyone else have any better ideas?
EDIT:
Obviously this code is simply creating a host for the service, I am still missing the client code to obtain the WSDL definition.
Just use WebClient and ?wsdl sufix in URL
using (ServiceHost host = new ServiceHost(typeof(NSTest.HelloNS),
new Uri("http://localhost:8000/Omega")))
{
host.AddServiceEndpoint(typeof(NSTest.IMy_NS), new BasicHttpBinding(), "Primary");
ServiceMetadataBehavior behavior = new ServiceMetadataBehavior();
behavior.HttpGetEnabled = true;
host.Description.Behaviors.Add(behavior);
host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
host.Open();
string wsdl = null;
using (WebClient wc = new WebClient())
{
using (var stream = wc.OpenRead("localhost:8000/Omega?wsdl"))
{
using (var sr = new StreamReader(stream))
{
wsdl = sr.ReadToEnd();
}
}
}
Console.Write(wsdl);
}
Check out the WsdlExporter on MSDN. Its used to generate wsdl in WCF.
You could also have a look in svcutil with reflector to see how its generating the wsdl information, since the tool can generate wsdl from a dll-file.
Another way to do your comparison would be to use the svcutil tool to generate the wsdl and compare it to a saved/baselined version of the service. Run the svcutil in your test and verify the output against the old files. Not really self-contained test since you'll need the svcutil...
How about something like this?
Creating a WSDL using C#
One thing you need to be careful of is to compare the entire WSDL. WCF breaks up WSDLs, unlike classic web services (asmx) WSDLs. This means that the core of the info is on the ?WSDL page, however, there will also be multiple XSDs (.svc?XSD=XSD0, 1, 2 ...) and possibly multiple WSDL pages (?WSDL and ?WSDL=WSDL0 for example).
One way to accomplish this would be to generate a webrequest to get the data from the root wsdl. Then you can search the WSDL for anything like (yourServicename).svc?WSDL=WSLD0 and (yourServicename)?XSD=XSD0 and so on, spawning additional webrequests for each WSDL and XSD.
You might be better off using SoapUI to test the WSDL rather than relying on NUnit directly.
If you want to call SoapUI from NUnit, it's possible, but a little clunky. See http://enthusiasm.soapui.org/forum/viewtopic.php?f=2&t=15 for more information.
Same answer translated to VB
Using host = New ServiceHost(GetType(MyHelloWorldWcfLib.HelloWorldServer), New Uri("http://localhost:8000/Omega"))
host.AddServiceEndpoint(GetType(MyHelloWorldWcfLib.IHelloWorld), New BasicHttpBinding(), "Primary")
Dim behavior = New ServiceMetadataBehavior()
behavior.HttpGetEnabled = True
host.Description.Behaviors.Add(behavior)
host.AddServiceEndpoint(GetType(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex")
host.Open()
Dim wsdl As String = Nothing
Using wc = New System.Net.WebClient()
Using stream = wc.OpenRead("http://localhost:8000/Omega?wsdl")
Using sr = New IO.StreamReader(stream)
wsdl = sr.ReadToEnd()
End Using
End Using
End Using
Console.Write(wsdl)
End Using

Mono WCF NetTcp service takes only one client at a time

While trying to build a client-server WCF application in Mono we ran into some issues.
Reducing it to just a bare example we found that the service only accepts one client at a time. If another client attempts to connect, it hangs until the first one disconnects.
Simply changing to BasicHttpBinding fixes it but we need NetTcpBinding for duplex communication. Also the problem does not appear if compiled under MS .NET.
EDIT: I doubt (and hope not) that Mono doesn't support what I'm trying to do. Mono code usually throws NotImplementedExceptions in such cases as far as I noticed. I am using Mono v2.6.4
This is how the service is opened in our basic scenario:
public static void Main (string[] args)
{
var binding = new NetTcpBinding ();
binding.Security.Mode = SecurityMode.None;
var address = new Uri ("net.tcp://localhost:8080");
var host = new ServiceHost (typeof(Hello));
host.AddServiceEndpoint (typeof(IHello), binding, address);
ServiceThrottlingBehavior behavior = new ServiceThrottlingBehavior ()
{
MaxConcurrentCalls = 100,
MaxConcurrentSessions = 100,
MaxConcurrentInstances = 100
};
host.Description.Behaviors.Add (behavior);
host.Open ();
Console.ReadLine ();
host.Close ();
}
The client channel is obtained like this:
var binding = new NetTcpBinding ();
binding.Security.Mode = SecurityMode.None;
var address = new EndpointAddress ("net.tcp://localhost:8080/");
var client = new ChannelFactory<IHello> (binding, address).CreateChannel ();
As far as I know this is a Simplex connection, isn't it?
The contract is simply:
[ServiceContract]
public interface IHello
{
[OperationContract]
string Greet (string name);
}
Service implementation has no ServiceModel tags or attributes.
I'll update with details as required.
I've played around with this a bit, and it definitely looks like a Mono bug.
I'm porting a WCF application to run in Mono at the moment. I had played with some NetTcpBinding stuff, but I hadn't tried this scenario (multiple connections to a Mono-hosted service host). However now I try it out, I'm able to reproduce - both in 2.6 and the latest daily package.
It does work in .NET, however. Any difference in behavior between Mono and .NET is classed as a bug. You should log it on Bugzilla with a test case, I would also post in the Mono newslist.
Good luck.
Definately a bug. I'm wondering if there was a version it was working correctly...
I've posted it at Novell Bugzilla, if you are interested in its progress.

Reading from ServiceReferences.ClientConfig in WCF in Silverlight 3 in a dynamically loaded .xap file

I'm using Silverlight 3 Prism (CAB) with WCF
When I call a WCF service in a Prism module, I get the same error:
"Could not find default endpoint element that references contract 'IMyService' in the service model client configuaration section. This might be because no configuaration file was found for your application or because no end point element matching this contract could be found in the client element"
It turns out that its looking in the Shell's .xap file for a ServiceReferences.ClientConfig file, not in the module's ServiceReferences.ClientConfig file. I added my endpoint and binding to the existing ServiceReferences.ClientConfig file in my Silverlight Shell application (it calls it's own WCF services).
Then I had to rebuild the Shell app to generate the new .xap file for my Web project's ClientBin folder.
Next I changed to setting up the service in code:
// create the binding elements
BinaryMessageEncodingBindingElement binaryMessageEncoding = new BinaryMessageEncodingBindingElement();
HttpTransportBindingElement httpTransport = new HttpTransportBindingElement()
{ MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue};
HttpsTransportBindingElement httpsTransport = new HttpsTransportBindingElement()
{ MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
// add the binding elements into a Custom Binding
CustomBinding customBinding;
if (Application.Current.Host.Source.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase))
{
customBinding = new CustomBinding(binaryMessageEncoding, httpsTransport);
}
else
{
customBinding = new CustomBinding(binaryMessageEncoding, httpTransport);
}
// create the Endpoint URL
EndpointAddress endpointAddress = new EndpointAddress(
"http://localhost/Test/TestModule/Test.TestModule.WCF/TestModuleService.svc");
// create an interface for the WCF service
var service = new TestModuleServiceClient(customBinding, endpointAddress);
This post deals with a similar situation:
http://blogs.southworks.net/matiasb/2009/06/20/how-to-consume-wcf-services-from-composite-application-guidance-for-wpf-and-silverlightprism-v2-modules/
Thanks,
Damian Schenkelman
http://blogs.southworks.net/dschenkelman