We're developing a Silverlight Client onto a server-based API exposed via WCF.
I'm trying to move my WCF client code (which works fine) from a configuration-based model to a programmatic model. This will enable me to have a single "root" URL which I can apply at start-up and not require installations to have to maintain humongous configuration files.
I'm stuggling converting my configurations to Silverlight-capable code, though.
Where I have the configuration below for one of my services:
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="CustomBinding_ISilverlightHelper">
<binaryMessageEncoding />
<httpTransport maxReceivedMessageSize="2147483647" maxBufferSize="2147483647">
<extendedProtectionPolicy policyEnforcement="Never" />
</httpTransport>
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc"
binding="customBinding" bindingConfiguration="CustomBinding_ISilverlightHelper"
contract="API.WCF.Silverlight.ISilverlightHelper" name="CustomBinding_ISilverlightHelper" />
</client>
</system.serviceModel>
</configuration>
I can't figure out how to create the equivelant client-config code. At the moment I have:
CustomBinding customBinding = new CustomBinding();
// I see I need to do something with customBinding but the properties don't seem
// logical
// I have used BasicHttpBinding, but it just returns with "Not Found" (the service does resolve to a valid URL)
BasicHttpBinding basicHttpBinding = new BasicHttpBinding() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc");
ISilverlightHelper silverlightHelper= new ChannelFactory<ISilverlightHelper>(basicHttpBinding, endpointAddress).CreateChannel();
AsyncCallback asyncCallback = delegate(IAsyncResult result)
{
ISilverlightHelper asyncSilverlightHelper = (ISilverlightHelper)result.AsyncState;
string[] files=asyncSilverlightHelper.EndGetPlugInXapNames(result).ToArray();
};
silverlightHelper.BeginGetPlugInXapNames(asyncCallback, silverlightHelper);
Any clues would be appreciated. I've spent all morning Googling/Binging/Overflowing but haven't come across this scenario. Or I might be just so far wrong ...
Sorted it.
I created the BinaryMessageEncodingBindingElement and HttpTransportBindingElements, added them to the CustomBinding and it all works.
Here's my annotated code:
// create the binding elements
BinaryMessageEncodingBindingElement binaryMessageEncoding = new BinaryMessageEncodingBindingElement();
HttpTransportBindingElement httpTransport = new HttpTransportBindingElement() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue };
// add the binding elements into a Custom Binding
CustomBinding customBinding = new CustomBinding(binaryMessageEncoding,httpTransport);
// create the Endpoint URL (I'll use a configured URL later - all web services will then move as one)
EndpointAddress endpointAddress = new EndpointAddress("http://localhost:50072/API/WCF/Silverlight/SilverlightHelper.svc");
// create an interface for the WCF service
ISilverlightHelper silverlightHelper= new ChannelFactory<ISilverlightHelper>(customBinding, endpointAddress).CreateChannel();
// set-up the asynchronous callback
AsyncCallback asyncCallback = delegate(IAsyncResult result)
{
ISilverlightHelper asyncSilverlightHelper = (ISilverlightHelper)result.AsyncState;
string[] files=asyncSilverlightHelper.EndGetPlugInXapNames(result).ToArray();
};
// execute the call
silverlightHelper.BeginGetPlugInXapNames(asyncCallback, silverlightHelper);
Related
So, I noticed FaultException is not giving me the proper result when I use the BasicHttpBinding. When I use WSHttpBinding it works file.
The issue is, From WCF Service if I throw the FaultException like below,
var translations = new List<FaultReasonText> { new FaultReasonText("FaultReasonText 1"), new FaultReasonText("FaultReasonText 2") };
throw new FaultException<MessageServiceFault>(MessageServiceFault.Fault1, new FaultReason(translations));
When it reaches to the client the fault.Reason.Translations count is 1. That means the first one (FaultReasonText 1) only is getting back to client.
But when I use WSHttpBinding the count is 2. Where the issue is? Can anyone help me on this.
It gives me different result when I test the below code with BasicHttpBinding & WSHttpBinding bindings.
class Program
{
static void Main(string[] args)
{
try
{
string baseAddress = "http://" + Environment.MachineName + ":8000/Service";
ServiceHost host = new ServiceHost(typeof(MessageService), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IMessageService), new WSHttpBinding(), "");
host.Open();
Console.WriteLine("Host opened");
ChannelFactory<IMessageService> myChannelFactory = new ChannelFactory<IMessageService>(new WSHttpBinding(), new EndpointAddress(baseAddress));
IMessageService channel = myChannelFactory.CreateChannel();
var response = channel.GetMessage();
}
catch (FaultException fault)
{
fault.Reason.Translations.ToList().ForEach(i => Console.WriteLine(i.Text));
Console.WriteLine(false);
}
}
}
[ServiceContract]
public interface IMessageService
{
[OperationContract]
[FaultContract(typeof(MessageServiceFault))]
string GetMessage();
}
public class MessageService : IMessageService
{
public string GetMessage()
{
var translations = new List<FaultReasonText> { new FaultReasonText("FaultReasonText 1"), new FaultReasonText("FaultReasonText 2") };
throw new FaultException<MessageServiceFault>(MessageServiceFault.Fault1, new FaultReason(translations));
}
}
[DataContract]
public enum MessageServiceFault
{
[EnumMember]
Fault1,
[EnumMember]
Fault2
}
EDIT:
But, this article says, You can supply a number of different text strings that get picked from depending on the user's language settings. The Translations bucket holds all of the different text strings and their associated cultural identifiers (tied together by a FaultReasonText). When no culture is specified for a fault reason or a translation search, the assumed culture is the current thread culture. For example, if you want a translation to "en-UK", we'll first look for "en-UK" and then we'll look for "en". If we still can't find a match, then we'll take the first translation in the list, which could be anything.
If so, Why in case of WsHttpBinding it returns me the 2 FaultReasonText ?
To use FaultException, you need to activate SOAP 1.2 on your web service.
BasicHttpBinding uses SOAP 1.1, WSHttpBinding uses SOAP 1.2. That's why it works with WSHttpBinding and not with BasicHttpBinding.
Instead of using BasicHttpBinding, you should better use customBindings, with textMessageEncoding and httpTransport :
<customBinding>
<binding name="simpleBinding">
<textMessageEncoding messageVersion="Soap12" writeEncoding="utf-8" />
<httpTransport />
</binding>
</customBinding>
If you convert a default basicHttpBinding with this tool : you will obtain :
<!-- generated via Yaron Naveh's http://webservices20.blogspot.com/ -->
<customBinding>
<binding name="NewBinding0">
<textMessageEncoding MessageVersion="Soap11" />
<httpTransport />
</binding>
</customBinding>
<!-- generated via Yaron Naveh's http://webservices20.blogspot.com/ -->
Source binding :
<bindings>
<basicHttpBinding>
<binding name="NewBinding0" />
</basicHttpBinding>
</bindings>
Try to activate SOAP 12 to your service, and it will work
I am using custom binding in the sevrice side in C#. I want binary Encoding in HTTP.
<bindings>
<customBinding>
<binding name="myOwnBinding">
<binaryMessageEncoding></binaryMessageEncoding>
<httpTransport/>
</binding>
</customBinding>
</bindings>
<extensions>
<bindingExtensions>
<add name="myOwnBinding" type="CustomBinding.UserBinding,CustomBinding"/>
</bindingExtensions>
</extensions>
<service name="CustomBinding.Service1" behaviorConfiguration="CustomBinding.Service1Behavior">
This service is not going to expose the metadata.So,i will not be able to create a service Reference in client to consume the servvice.
Now,I want to know how to use this binding in the client channel factory to consume this service.Below is my client side code.
EndpointAddress address = new EndpointAddress("http://localhost:2418/Service1.svc");
ChannelFactory<IService1> c = new ChannelFactory<IService1>(Binding, address);
IService1 reqChannel = c.CreateChannel();
String str = reqChannel.GetData(1);
How to manually fill the binding object that the Channel factory is expecting when service is developed with custom binding.?
Thanks
Arun
I have sorted it out when i used the app.config to load the custom binding object.
System.ServiceModel.Channels.CustomBinding cus = new System.ServiceModel.Channels.CustomBinding("CustomBinding_IService1");
EndpointAddress address = new EndpointAddress("http://localhost:2418/Service1.svc");
ChannelFactory<IService1> c = new ChannelFactory<IService1>(cus);
IService1 serviceInstance = c.CreateChannel(address);
String str = serviceInstance.GetData(1);
Thanks
I have a WCF Service that is hosted in a ServiceHost object. The ServiceHost is created on the OnStart method of an Azure Worker Role. Here is the code:
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
Uri baseAddress = ServiceBusEnvironment.CreateServiceUri("http", "my_sb", "SimpleService");
host = new ServiceHost(typeof(SimpleService1.Service1), baseAddress);
BasicHttpRelayBinding binding = new BasicHttpRelayBinding(EndToEndBasicHttpSecurityMode.None, RelayClientAuthenticationType.None);
binding.OpenTimeout = new TimeSpan(1, 1, 0);
binding.ReceiveTimeout = new TimeSpan(1, 10, 0);
binding.SendTimeout = new TimeSpan(1, 10, 0);
binding.MaxReceivedMessageSize = 73400320;
XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
readerQuotas.MaxArrayLength = 73400320;
binding.ReaderQuotas = readerQuotas;
TransportClientEndpointBehavior sharedSecretServiceBusCredential = new TransportClientEndpointBehavior();
sharedSecretServiceBusCredential.CredentialType = TransportClientCredentialType.SharedSecret;
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerName = "owner";
sharedSecretServiceBusCredential.Credentials.SharedSecret.IssuerSecret = "blablablabla==";
ContractDescription contractDescription = ContractDescription.GetContract(typeof(SimpleService1.IService1), typeof(SimpleService1.Service1));
ServiceEndpoint serviceEndPoint = new ServiceEndpoint(contractDescription);
serviceEndPoint.Address = new EndpointAddress(baseAddress);
serviceEndPoint.Binding = binding;
IEndpointBehavior serviceRegistrySettings = new ServiceRegistrySettings(DiscoveryType.Public);
serviceEndPoint.Behaviors.Add(serviceRegistrySettings);
serviceEndPoint.Behaviors.Add(sharedSecretServiceBusCredential);
host.Description.Endpoints.Add(serviceEndPoint);
try
{
host.Open();
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message, "Error");
throw;
}
Trace.WriteLine("SimpleService1 running...");
and the binding configuration on the client side is:
<basicHttpBinding>
<binding name="FileTransferBinding" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" maxReceivedMessageSize="73400320">
<readerQuotas maxArrayLength="73400320"/>
<security mode="None"/>
</binding>
</basicHttpBinding>
and
<endpoint address="http://my_sb.servicebus.windows.net/simpleservice" binding="basicHttpBinding" bindingConfiguration="FileTransferBinding" contract="Service1reference.IService1" name="FileTransferBinding" behaviorConfiguration="sbBehavior"/>
The problem is that if one call to the service takes longer than 1 minute, the client receives this exception:
The content type application/xml; charset=utf-8 of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly
If I change the binding to a netTcpRelayBinding everything works fine.
This is because the Windows Azure load-balancer disconnects you if the connection is idle for more than a minute.
Your best bet is to use a WCF callback. This will execute a call from the server to the client to let it know that the long-running operation has completed. For more on how to do this have a look at this blog [WCF Callbacks
Is there an easy way to tie custom X509 cert validation to BasicHttpBinding (or CustomHttpBinding for the same matter, which will implement transport-only security)?
EDIT1: I added a ServerCertificateValidationCallback to the code for the sake of showing that it doesn't fire up either
Here's what I'm trying to do:
1) wrote custom X509CertificateValidator:
public class MyX509Validator : X509CertificateValidator
{
public override void Validate(X509Certificate2 certificate)
{
Console.WriteLine("Incoming validation: subj={0}, thumb={1}",
certificate.Subject, certificate.Thumbprint);
}
}
2) created host:
var soapBinding = new BasicHttpBinding() { Namespace = "http://test.com" };
soapBinding.Security.Mode = BasicHttpSecurityMode.Transport;
soapBinding.Security.Transport.ClientCredentialType =
HttpClientCredentialType.Certificate;
var sh = new ServiceHost(typeof(Service1), uri);
sh.AddServiceEndpoint(typeof(IService1), soapBinding, "");
sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.My, X509FindType.FindBySubjectName, "localhost");
sh.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
System.ServiceModel.Security.X509CertificateValidationMode.Custom;
sh.Credentials.ClientCertificate.Authentication.CustomCertificateValidator =
new MyX509Validator();
System.Net.ServicePointManager.ServerCertificateValidationCallback +=
delegate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors)
{
Console.WriteLine("Incoming validation: subj={0}, thumb={1}",
certificate.Subject, certificate.GetIssuerName());
return true;
};
sh.Open();
3) Created WCF Client:
var binding = new BasicHttpBinding();
binding.Security.Mode = BasicHttpSecurityMode.Transport;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
var cli = new ServiceReference2.Service1Client(binding,
new EndpointAddress("https://localhost:801/Service1"));
cli.ClientCredentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine,
StoreName.My, X509FindType.FindBySubjectName, "localhost");
cli.HelloWorld();
Authentication works fine, but MyX509Validator.Validate() never gets called. I have suspicion that X509CertificateValidator only works on message security, not on transport. Is that right? Is there something I could do to override transport-level cert validation?
I'm assuming that you are talking about the certificate that is tied to HTTPS...
If so, here is the answer: The X509CertificateValidationMode is used within the header of the document that you are exchanging to provide authentication. It does nothing for the underlying transport itself, which in this case is HTTPS with its' associated x.509 cert. So, you are spot on with your assumption.
If you want to provide custom certificate validation of the transport, use System.Net.ServicePointManager.ServerCertificateValidationCallback instead. Be careful though, this is an app wide setting. If you are cycling through multiple endpoints and don't set this to null, it will remain active.
I am doing this using the following settings and my custom validator definitely gets hit:
serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator =
new CertificateValidator(ConfigurationManager.AppSettings["Cerficate"]);
My behaviour is:
<behavior name="CustomCertificateBehavior">
<serviceCredentials>
<clientCertificate>
<authentication certificateValidationMode="Custom" />
</clientCertificate>
</serviceCredentials>
</behavior>
</serviceBehaviors>
And my binding:
<basicHttpBinding>
<binding name="SecureBinding" maxReceivedMessageSize="5242880">
<security mode="Transport">
<transport clientCredentialType="Certificate"></transport>
</security>
</binding>
</basicHttpBinding>
How do I increase the default timeout to larger than 1 minute on a WCF service?
Are you referring to the server side or the client side?
For a client, you would want to adjust the sendTimeout attribute of a binding element. For a service, you would want to adjust the receiveTimeout attribute of a binding elemnent.
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="longTimeoutBinding"
receiveTimeout="00:10:00" sendTimeout="00:10:00">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="longTimeoutService"
behaviorConfiguration="longTimeoutBehavior">
<endpoint address="net.tcp://localhost/longtimeout/"
binding="netTcpBinding" bindingConfiguration="longTimeoutBinding" />
</service>
....
Of course, you have to map your desired endpoint to that particular binding.
Under the Tools menu in Visual Studio 2008 (or 2005 if you have the right WCF stuff installed) there is an options called 'WCF Service Configuration Editor'.
From there you can change the binding options for both the client and the services, one of these options will be for time-outs.
You can choose two ways:
1) By code in the client
public static void Main()
{
Uri baseAddress = new Uri("http://localhost/MyServer/MyService");
try
{
ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService));
WSHttpBinding binding = new WSHttpBinding();
binding.OpenTimeout = new TimeSpan(0, 10, 0);
binding.CloseTimeout = new TimeSpan(0, 10, 0);
binding.SendTimeout = new TimeSpan(0, 10, 0);
binding.ReceiveTimeout = new TimeSpan(0, 10, 0);
serviceHost.AddServiceEndpoint("ICalculator", binding, baseAddress);
serviceHost.Open();
// The service can now be accessed.
Console.WriteLine("The service is ready.");
Console.WriteLine("Press <ENTER> to terminate service.");
Console.WriteLine();
Console.ReadLine();
}
catch (CommunicationException ex)
{
// Handle exception ...
}
}
2)By WebConfig in a web server
<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding openTimeout="00:10:00"
closeTimeout="00:10:00"
sendTimeout="00:10:00"
receiveTimeout="00:10:00">
</binding>
</wsHttpBinding>
</bindings>
</system.serviceModel>
For more detail view the official documentations
Configuring Timeout Values on a Binding
Class WSHttpBinding
Different timeouts mean different things. When you're working on the client.. you're probably looking mostly at the SendTimeout - check this reference - wonderful and relevant explanation:
http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/84551e45-19a2-4d0d-bcc0-516a4041943d/
It says:
Brief summary of binding timeout knobs...
Client side:
SendTimeout is used to initialize the OperationTimeout, which governs the whole interaction for sending a message (including receiving a reply message in a request-reply case). This timeout also applies when sending reply messages from a CallbackContract method.
OpenTimeout and CloseTimeout are used when opening and closing channels (when no explicit timeout value is passed).
ReceiveTimeout is not used.
Server side:
Send, Open, and Close Timeout same as on client (for Callbacks).
ReceiveTimeout is used by ServiceFramework layer to initialize the session-idle timeout.
In addition to the binding timeouts (which are in Timespans), You may also need this as well. This is in seconds.
<system.web>
<httpRuntime executionTimeout="600"/><!-- = 10 minutes -->