Consume WCF service in Xamarin Forms - wcf

I can integrate the WCF service in xamarin with .net framework class library file.
WCF - Developed in .net Framework 4.5
Xamarin - Developing in .net Core 2.2
Here I am unable to consume the WCF service created with .net framework. But I can consume the service where I as created the Asp.Net project with same .net framework version.
What need to do to consume it in xamarin

Hi Colin / Jason / Hakim.....
there is no issue while consuming the WCF with ASP.net which was created both in the same framework. But unable to consume in Xamarin... Below is the code...
public class Class1
{
public UserInfo GetUser(string username, string password)
{
WSHttpBinding binding = new WSHttpBinding();
TimeSpan span = new TimeSpan(0, 3, 0);
binding.Name = "WSHttpBinding_IService";
binding.CloseTimeout = span;
binding.OpenTimeout = span;
binding.ReceiveTimeout = span;
binding.SendTimeout = span;
binding.AllowCookies = false;
binding.BypassProxyOnLocal = false;
binding.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard;
// binding.MaxBufferSize = 65536;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 65536;
binding.MessageEncoding = WSMessageEncoding.Text;
binding.TextEncoding = Encoding.UTF8;
//binding.TransferMode = TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.ReaderQuotas = new XmlDictionaryReaderQuotas();
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxStringContentLength = 8192;
binding.ReaderQuotas.MaxArrayLength = 16384;
binding.ReaderQuotas.MaxBytesPerRead = 4096;
binding.ReaderQuotas.MaxNameTableCharCount = 16384;
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
binding.Security.Transport.Realm = string.Empty;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
binding.Security.Message.AlgorithmSuite = SecurityAlgorithmSuite.Default;
ICFService.ServiceClient client = new ServiceClient(binding, new EndpointAddress("..../Service.svc"));
client.ClientCredentials.UserName.UserName = username;
client.ClientCredentials.UserName.Password = password;
return client.CheckUser(new UserRQ() { UserName = username, Password = password });
}
}
Xamarin Button click
try
{
APIServiceLibrary.Class1 api = new APIServiceLibrary.Class1();
var user = api.GetUser(Entry_Username.Text, Entry_Password.Text);
if (user != null)
{
}
}
catch (Exception ex)
{
throw ex;
}

Related

Unable to modify a:To element of WCF addressing header. a:To header is not available in ClientMessageInspector.BeforeSendRequest

I'm trying to modify the value of a:To addressing header element. a:To element is not available in BeforeSendRequest of ClientMessageInspector.
If I add it in BeforeSendRequest, then it is overridden with the endpoint.
var toHeader = MessageHeader.CreateHeader("To", "http://www.w3.org/2005/08/addressing", "https://toHeaderValue", true);
request.Headers.Add(toHeader);
I'm here using the CustomBinding with Soap version 1.1 and Addressing version 10
{
HttpTransportBindingElement bindingElement;
var binding = new CustomBinding
{
Name = "*******",
OpenTimeout = TimeSpan.FromMinutes(10),
CloseTimeout = TimeSpan.FromMinutes(10),
SendTimeout = TimeSpan.FromMinutes(10),
ReceiveTimeout = TimeSpan.FromMinutes(10)
};
binding.Elements.Add(new TextMessageEncodingBindingElement
{
MessageVersion =
MessageVersion.CreateVersion(EnvelopeVersion.Soap11,
AddressingVersion.WSAddressing10),
WriteEncoding = Encoding.UTF8
});
bindingElement = GetBindingElement(url);
bindingElement.ManualAddressing = false;
bindingElement.MaxReceivedMessageSize = 20000000;
bindingElement.AllowCookies = false;
bindingElement.BypassProxyOnLocal = false;
bindingElement.MaxBufferSize = 20000000;
bindingElement.TransferMode = TransferMode.Buffered;
bindingElement.AuthenticationScheme = AuthenticationSchemes.Anonymous;
bindingElement.ProxyAuthenticationScheme = AuthenticationSchemes.Anonymous;
bindingElement.UseDefaultWebProxy = true;
binding.Elements.Add(bindingElement);
return binding;
}
private HttpTransportBindingElement GetBindingElement(string url)
{
if (Uri.TryCreate(url, UriKind.Absolute, out var uriResult) && uriResult.Scheme == Uri.UriSchemeHttp)
return new HttpTransportBindingElement();
else
return new HttpsTransportBindingElement();
}
Maybe the solution is set this:
var endpoint = new EndpointAddress
(
new Uri("a to address"),
new DnsEndpointIdentity("endpoint identity"),
new AddressHeaderCollection()
);
And set the value to header:
client.Endpoint.Behaviors.Add(new ClientViaBehavior(new Uri("address")));
Hope it helps.

Get claims for service using Windows validation/authentication

I have the following code which was validation using username & password.
How can I use Windows credentials instead?
private static SecurityToken GetClaims(string serviceurl, string username, string password)
{
bool isincurrentusercontext = String.IsNullOrEmpty(username);
WS2007HttpBinding binding = new WS2007HttpBinding();
binding.Security.Mode = SecurityMode.TransportWithMessageCredential;
binding.Security.Message.EstablishSecurityContext = false;
EndpointAddress endpoint = new EndpointAddress(new Uri(GetStsUrl(isincurrentusercontext)));
WSTrustChannelFactory trustChannelFactory;
if (!isincurrentusercontext)
{
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
trustChannelFactory = new WSTrustChannelFactory(binding, endpoint);
trustChannelFactory.Credentials.UserName.UserName = username;
trustChannelFactory.Credentials.UserName.Password = password;
}
else
trustChannelFactory = new WSTrustChannelFactory(new KerberosWSTrustBinding(SecurityMode.TransportWithMessageCredential), endpoint);
trustChannelFactory.TrustVersion = TrustVersion.WSTrust13;
trustChannelFactory.Credentials.UseIdentityConfiguration = true;
WSTrustChannel channel = null;
RequestSecurityToken rst = new RequestSecurityToken(RequestTypes.Issue);
rst.AppliesTo = new EndpointReference(serviceurl);
rst.KeyType = KeyTypes.Bearer;
channel = (WSTrustChannel)trustChannelFactory.CreateChannel();
SecurityToken token = channel.Issue(rst);
((IChannel)channel).Close();
channel = null;
trustChannelFactory.Close();
trustChannelFactory = null;
return token;
}
If I change,
binding.Security.Message.ClientCredentialType = MessageCredentialType.UserName;
to
binding.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
and remove these two statements,
trustChannelFactory.Credentials.UserName.UserName = username;
trustChannelFactory.Credentials.UserName.Password = password;
and when i run this statement,
SecurityToken token = channel.Issue(rst);
I get the following error,
Secure channel cannot be opened because security negotiation with the
remote endpoint has failed. This may be due to absent or incorrectly
specified EndpointIdentity in the EndpointAddress used to create the
channel. Please verify the EndpointIdentity specified or implied by
the EndpointAddress correctly identifies the remote endpoint

Web service security using X509 certificate in Classic ASP

I'm trying to call a C# dll from classic ASP - this dll calls a webservice. I've been asked by someone that runs that ASP site to create this dll for him and had tons of problems doing that. He told me he has a *.crt file, and that the dll should use that to call his SSL-based webservice.
So since this is classic ASP, had to make it a COM object and also configure the service and endpoint through code, like so:
BasicHttpBinding binding = new BasicHttpBinding();
binding.Name = "Service1Binding";
binding.CloseTimeout = System.TimeSpan.Parse("00:01:00");
binding.OpenTimeout = System.TimeSpan.Parse("00:01:00");
binding.ReceiveTimeout = System.TimeSpan.Parse("00:10:00");
binding.SendTimeout = System.TimeSpan.Parse("00:01:00");
binding.AllowCookies = false;
binding.BypassProxyOnLocal = false;
binding.HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.StrongWildcard;
binding.MaxBufferSize = 65536;
binding.MaxBufferPoolSize = 524288;
binding.MaxReceivedMessageSize = 65536;
binding.MessageEncoding = System.ServiceModel.WSMessageEncoding.Text;
binding.TextEncoding = System.Text.Encoding.UTF8;
binding.TransferMode = System.ServiceModel.TransferMode.Buffered;
binding.UseDefaultWebProxy = true;
binding.ReaderQuotas.MaxDepth = 32;
binding.ReaderQuotas.MaxStringContentLength = 8192;
binding.ReaderQuotas.MaxArrayLength = 16384;
binding.ReaderQuotas.MaxBytesPerRead = 4096;
binding.ReaderQuotas.MaxNameTableCharCount = 16384;
binding.Security.Mode = System.ServiceModel.BasicHttpSecurityMode.None;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.None;
binding.Security.Transport.ProxyCredentialType = HttpProxyCredentialType.None;
binding.Security.Transport.Realm = "";
binding.Security.Mode = BasicHttpSecurityMode.TransportWithMessageCredential;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Certificate;
binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
binding.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
EndpointAddress endpoint =
new EndpointAddress("https://webservice.XXXX.com/Service1.svc");
var cert = new X509Certificate2(certPath); //local path to *.crt file
Service1.ServiceClient client = new Service1.ServiceClient(binding, endpoint);
client.ClientCredentials.ClientCertificate.Certificate = cert;
var result = client.HelloWorld();
At first i got a Forbidden exception, so I changed the Security.Mode to be BasicHttpSecurityMode.TransportWithMessageCredential. Now, I'm getting this error:
The private key is not present in the X.509 certificate
Is it looking for the cert in the store, or using the path I gave it? How can i make this work?

My test indicates .NET Remoting is faster than WCF 4 by a factor of 1.5

In order to tell whether my project should migrate from .net remoting to WCF, I extracted its network communication part and implemented it by WCF. I run the remoting version and wcf version and eventually find remoting is faster than wcf by a factor of 1.5, which greatly differs from the msdn article.
Test configuration
WCF and .NET Remoting both use tcp channel without encryption, no app.config file. Compiled in release mode, no optimization.
Operations
What my program does is this.
You can download the two solutions here.
WCF test
Service Host
ServiceHost host = new ServiceHost(typeof(Server), new Uri(string.Format("net.tcp://{0}:{1}/{2}", args[0], args[1], args[2])));
var binding = new NetTcpBinding();
binding.MaxReceivedMessageSize = 614400;
binding.ReaderQuotas.MaxArrayLength = 512000;//a max picture of 500KB
binding.Security.Mode = SecurityMode.None;
host.AddServiceEndpoint(typeof(IServer), binding, string.Empty);
host.Open();
Server
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single
//, IncludeExceptionDetailInFaults = true
, ConcurrencyMode = ConcurrencyMode.Reentrant
)]
public class Server : IServer
{
public EntryRequirement GetEntryRequirement()
{
return new EntryRequirement(new[] { "fuck", "sex" }, false);
}
public void AddClient()
{
var client = OperationContext.Current.GetCallbackChannel<IServerCallback>();
var p = client.Profile;
var x = client.Password;
System.Diagnostics.Debug.WriteLine(p);
System.Diagnostics.Debug.WriteLine(x);
}
}
Client side
Player player = new Player();
player.Password = "12423";
player.Profile = new Contracts.PlayerProfile
{
Description = "I'm a man.",
HeadImage = imageData,
Name = "Loveright"
};
var binding = new NetTcpBinding();
binding.Security.Mode = SecurityMode.None;
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 20; i++)
{
ServerProxy server = new ServerProxy(player, binding,
new EndpointAddress(string.Format("net.tcp://{0}:{1}/{2}", args[0], args[1], args[2])));
server.GetEntryRequirement();
server.AddClient();
}
watch.Stop();
HeadImage is a picture of size 139KB.
Player class
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
class Player : IServerCallback
{
public PlayerProfile Profile { get; set; }
public string Password { get; set; }
public void ClientCollectionChangedEventHandler(object sender, ControllersChangedEventArgs e)
{
}
public void ClientUpdatedEventHandler(object sender, ClientUpdatedEventArgs e)
{
}
}
.NET Remoting test
Host
var serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
var clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["port"] = args[1];
props["name"] = "tcp server";
var channel = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(channel, false);
System.Runtime.Remoting.RemotingConfiguration.RegisterWellKnownServiceType(typeof(Server),
args[2], System.Runtime.Remoting.WellKnownObjectMode.Singleton);
Client
var serverProv = new BinaryServerFormatterSinkProvider();
serverProv.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
var clientProv = new BinaryClientFormatterSinkProvider();
IDictionary props = new Hashtable();
props["name"] = "tcp client " + Guid.NewGuid();
props["port"] = 0;
var channel = new TcpChannel(props, clientProv, serverProv);
ChannelServices.RegisterChannel(channel, false);
FileStream stream = new FileStream(#"logotz6.png", FileMode.Open);
byte[] imageData = new byte[stream.Length];
stream.Read(imageData, 0, imageData.Length);
stream.Close();
Player player = new Player();
player.Password = "12423";
player.Profile = new PlayerProfile
{
Description = "I'm a man.",
HeadImage = imageData,
Name = "Loveright"
};
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 20; i++)
{
var serverProxy = (IServer)Activator.GetObject(typeof(IServer), string.Format("tcp://{0}:{1}/{2}", args[0], args[1], args[2]));
serverProxy.GetEntryRequirement();
serverProxy.AddClient(player);
}
watch.Stop();
You can download the two solutions here.
Result
So do I make the test somewhere unfair to WCF?
Should it be the message encoding king ?
Have you used binaryMessageEncoding instead of textMessageEncoding or soapMessageEncoding ?
You can create a custom binding to do this :
internal sealed class MyBinding : CustomBinding
{
private static readonly BindingElementCollection elementCollection;
static MyBinding()
{
MessageEncodingBindingElement encoding = new BinaryMessageEncodingBindingElement();
TcpTransportBindingElement transport = new TcpTransportBindingElement();
elementCollection = new BindingElementCollection();
elementCollection.Add(encoding);
elementCollection.Add(transport);
}
internal MyBinding(string bindingName, string bindingNamespace)
: base()
{
base.Namespace = bindingNamespace;
base.Name = bindingName;
}
public override BindingElementCollection CreateBindingElements()
{
return elementCollection;
}
}

WCF client binding configuration in program code

I have the following class that configures security, encoding, and token parameters but I am having trouble adding a BasicHttpBinding to specify a MaxReceivedMessageSize. Any insight would be appreciated.
public class MultiAuthenticationFactorBinding
{
public static Binding CreateMultiFactorAuthenticationBinding()
{
HttpsTransportBindingElement httpTransport = new HttpsTransportBindingElement();
CustomBinding binding = new CustomBinding();
binding.Name = "myCustomBinding";
TransportSecurityBindingElement messageSecurity = TransportSecurityBindingElement.CreateUserNameOverTransportBindingElement();
messageSecurity.AllowInsecureTransport = true;
messageSecurity.EnableUnsecuredResponse = true;
messageSecurity.MessageSecurityVersion = MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12;
messageSecurity.SecurityHeaderLayout = SecurityHeaderLayout.Strict;
messageSecurity.IncludeTimestamp = true;
messageSecurity.SetKeyDerivation(false);
TextMessageEncodingBindingElement Quota = new TextMessageEncodingBindingElement(MessageVersion.Soap11, System.Text.Encoding.UTF8);
Quota.ReaderQuotas.MaxDepth = 32;
Quota.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
Quota.ReaderQuotas.MaxArrayLength = 16384;
Quota.ReaderQuotas.MaxBytesPerRead = 4096;
Quota.ReaderQuotas.MaxNameTableCharCount = 16384;
X509SecurityTokenParameters clientX509SupportingTokenParameters = new X509SecurityTokenParameters();
clientX509SupportingTokenParameters.InclusionMode = SecurityTokenInclusionMode.AlwaysToRecipient;
clientX509SupportingTokenParameters.RequireDerivedKeys = false;
messageSecurity.EndpointSupportingTokenParameters.Endorsing.Add(clientX509SupportingTokenParameters);
//binding.ReceiveTimeout = new TimeSpan(0,0,300);
binding.Elements.Add(Quota);
binding.Elements.Add(messageSecurity);
binding.Elements.Add(httpTransport);
return binding;
}
}
If you need to specify MaxReceivedMessageSize you can do it on your transport binding element - HttpsTransportBindingElement. You can't add binding to binding.
Just Found this to create a BasicHttpBinding
BasicHttpBinding Basicbinding = new BasicHttpBinding(BasicHttpSecurityMode.None);
Basicbinding.MaxReceivedMessageSize = 10000000;