Consuming Task based async WCF web service from Android [duplicate] - c#

I am creating a server in .NET and a client application for Android. I would like to implement an authentication method which sends username and password to server and a server sends back a session string.
I'm not familiar with WCF so I would really appreciate your help.
In java I've written the following method:
private void Login()
{
HttpClient httpClient = new DefaultHttpClient();
try
{
String url = "http://192.168.1.5:8000/Login?username=test&password=test";
HttpGet method = new HttpGet( new URI(url) );
HttpResponse response = httpClient.execute(method);
if ( response != null )
{
Log.i( "login", "received " + getResponse(response.getEntity()) );
}
else
{
Log.i( "login", "got a null response" );
}
} catch (IOException e) {
Log.e( "error", e.getMessage() );
} catch (URISyntaxException e) {
Log.e( "error", e.getMessage() );
}
}
private String getResponse( HttpEntity entity )
{
String response = "";
try
{
int length = ( int ) entity.getContentLength();
StringBuffer sb = new StringBuffer( length );
InputStreamReader isr = new InputStreamReader( entity.getContent(), "UTF-8" );
char buff[] = new char[length];
int cnt;
while ( ( cnt = isr.read( buff, 0, length - 1 ) ) > 0 )
{
sb.append( buff, 0, cnt );
}
response = sb.toString();
isr.close();
} catch ( IOException ioe ) {
ioe.printStackTrace();
}
return response;
}
But on the server side so far I haven't figured out anything.
I would be really thankful if anyone could explain how to create an appropriate method string Login(string username, string password) with appropriate App.config settings and Interface with appropriate [OperationContract] signature in order to read these two parameters from client and reply with session string.
Thanks!

To get started with WCF, it might be easiest to just use the default SOAP format and HTTP POST (rather than GET) for the web-service bindings. The easiest HTTP binding to get working is "basicHttpBinding". Here is an example of what the ServiceContract/OperationContract might look like for your login service:
[ServiceContract(Namespace="http://mycompany.com/LoginService")]
public interface ILoginService
{
[OperationContract]
string Login(string username, string password);
}
The implementation of the service could look like this:
public class LoginService : ILoginService
{
public string Login(string username, string password)
{
// Do something with username, password to get/create sessionId
// string sessionId = "12345678";
string sessionId = OperationContext.Current.SessionId;
return sessionId;
}
}
You can host this as a windows service using a ServiceHost, or you can host it in IIS like a normal ASP.NET web (service) application. There are a lot of tutorials out there for both of these.
The WCF service config might look like this:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="LoginServiceBehavior">
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service name="WcfTest.LoginService"
behaviorConfiguration="LoginServiceBehavior" >
<host>
<baseAddresses>
<add baseAddress="http://somesite.com:55555/LoginService/" />
</baseAddresses>
</host>
<endpoint name="LoginService"
address=""
binding="basicHttpBinding"
contract="WcfTest.ILoginService" />
<endpoint name="LoginServiceMex"
address="mex"
binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
</system.serviceModel>
</configuration>
(The MEX stuff is optional for production, but is needed for testing with WcfTestClient.exe, and for exposing the service meta-data).
You'll have to modify your Java code to POST a SOAP message to the service. WCF can be a little picky when inter-operating with non-WCF clients, so you'll have to mess with the POST headers a little to get it to work. Once you get this running, you can then start to investigate security for the login (might need to use a different binding to get better security), or possibly using WCF REST to allow for logins with a GET rather than SOAP/POST.
Here is an example of what the HTTP POST should look like from the Java code. There is a tool called "Fiddler" that can be really useful for debugging web-services.
POST /LoginService HTTP/1.1
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://mycompany.com/LoginService/ILoginService/Login"
Host: somesite.com:55555
Content-Length: 216
Expect: 100-continue
Connection: Keep-Alive
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<Login xmlns="http://mycompany.com/LoginService">
<username>Blah</username>
<password>Blah2</password>
</Login>
</s:Body>
</s:Envelope>

Another option might be to avoid WCF all-together and just use a .NET HttpHandler. The HttpHandler can grab the query-string variables from your GET and just write back a response to the Java code.

You will need something more that a http request to interact with a WCF service UNLESS your WCF service has a REST interface. Either look for a SOAP web service API that runs on android or make your service RESTful. You will need .NET 3.5 SP1 to do WCF REST services:
http://msdn.microsoft.com/en-us/netframework/dd547388.aspx

From my recent experience i would recommend ksoap library to consume a Soap WCF Service, its actually really easy, this anddev thread migh help you out too.

If I were doing this I would probably use WCF REST on the server and a REST library on the Java/Android client.

Related

Consume WCF service from .NET Framework in .NET Core

WCF services are hosted on a local VM, written in .NET Framework. I need to consume it in a .NET Core application. When I try to connected it via Microsoft WCF Web Service Reference Provider
option, I get warning message like this
Moving forward ignoring this messages, I can see only endpoints implementing async.
Now if I try to invoke anyone of the async method, I get this error.
This is how I am instantiating it.
public class MotionSimulatorManager
{
public MotionSimulatorManager()
{
try
{
var uri = "net.tcp://192.168.184.33:8458/MotionSimulator";
var endpoint = new EndpointAddress(uri);
var binding = new NetTcpBinding
{
SendTimeout = new TimeSpan(1, 59, 59),
ReceiveTimeout = new TimeSpan(1, 59, 59),
MaxBufferPoolSize = int.MaxValue,
MaxBufferSize = int.MaxValue,
MaxReceivedMessageSize = int.MaxValue,
Security = { Mode = SecurityMode.None }
};
_motionSimulatorClient = new MotionSimulatorClient(binding, endpoint);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public async Task<object> NameSake()
{
try
{
var res = _motionSimulatorClient.EstopAsync(); //error comes at this point.
return res;
}
catch (Exception e)
{
File.WriteAllText("D://CollimatorType.txt", e.StackTrace);
throw;
}
}
}
How do I solve this ? Let me know if any other details is required.
Thanks in advance..
EDIT:
I introduced a proxy by adding .NET Framework project which consumes the WCF services and create a dll of that which I'm using in other .NET Core project but upon doing I'm getting this error while connecting to it.
Can someone help me here ?
Please check that the service configuration has the correct binding configuration,like this:
<service behaviorConfiguration="somebehavior"
name="somename">
<endpoint address="" binding="wsHttpBinding"
bindingConfiguration="SomeBinding"
name="http"
contract="somecontract" />
<endpoint address="mex"
binding="mexHttpBinding"
bindingConfiguration=""
name="mex"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:8700/service/"/>
</baseAddresses>
</host>
</service>
This bindingConfiguration was empty. It then takes the default wsHttpBinding which is something different then the one specified.

Sending message to msmq queue via msmqIntegrationBinding

So I'm trying to configure my client code to send messages to MSMQ queue. I followed the steps described in here: https://msdn.microsoft.com/en-us/library/ms789008(v=vs.100).aspx?cs-save-lang=1&cs-lang=csharp and my client code looks as below:
class Program
{
static void Main(string[] args)
{
var binding = new MsmqIntegrationBinding("MyMessagesBinding");
var address = new EndpointAddress(#"msmq.formatname:DIRECT = OS:.\private$\MyMessages");
var channelFactory = new ChannelFactory<IDataRelayService>(binding, address);
var channel = channelFactory.CreateChannel();
while (true)
{
var message = new MyMessage
{
Content = "this is content!!!",
Id = "random uuid"
};
var msmqWrapper = new MsmqMessage<MyMessage>(message)
{
Priority = MessagePriority.Highest
};
channel.PassMessage(msmqWrapper);
Console.WriteLine("message sent");
Console.ReadLine();
}
}
}
App.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
</startup>
<system.serviceModel>
<client>
<endpoint name="MyResponseEndpoint"
address="msmq.formatname:DIRECT=OS:.\private$\MyMessages"
binding="msmqIntegrationBinding"
bindingConfiguration="MyMessagesBinding"
contract="Client.IDataRelayService">
</endpoint>
</client>
<bindings>
<msmqIntegrationBinding>
<binding name="MyMessagesBinding">
<security mode="None" />
</binding>
</msmqIntegrationBinding>
</bindings>
</system.serviceModel>
</configuration>
IDataRelayService.cs:
[ServiceContract]
public interface IDataRelayService
{
[OperationContract(IsOneWay = true, Action = "*")]
void PassMessage(MsmqMessage<MyMessage> message);
}
IDataRelayServiceChannel.cs:
public interface IDataRelayServiceChannel : IDataRelayService, System.ServiceModel.IClientChannel
{
}
It compiles and runs with no problem, but when I open up evet viewer there are no events logged for MSMQ. If I open computer management tool to view queues it shows 0 messages in my queue. What am I doing wrong here?
EDIT:
I enabled event tracing for MSMQ and here's what event viewer is showing me:
Your problem is almost certainly permissions related.
The service account the message sender is running under must have the following MSMQ permissions on the queue it is trying to send to:
Send Message
Get Properties
Get Permissions
If your sender is on a different domain to your receiver, you will need to grant these permissions to a local user called ANONYMOUS_LOGON.
Also, enable MSMQ E2E event logging: https://technet.microsoft.com/en-us/library/cc730882(v=ws.11).aspx. This should tell you what is going on.
If you have WCF on both ends of the queue you should be using netMsmqBinding rather than msmqIntegrationBinding.

Changing ServiceHost EndPoint Address at Runtime C#

I'm busy writing a file server/client tool that basically uses a hosted Service to send and receive data to and from the server. Since this solution will be used by many different people, its not really advisable to have them go and edit the App.Config file for their setup. What I would like to do is change this at runtime so that the user(s) have full control over the settings to use. So, this is my App.Config file:
<system.serviceModel>
<services>
<service name="FI.ProBooks.FileSystem.FileRepositoryService">
<endpoint name="" binding="netTcpBinding"
address="net.tcp://localhost:5000"
contract="FI.ProBooks.FileSystem.IFileRepositoryService"
bindingConfiguration="customTcpBinding" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="customTcpBinding" transferMode="Streamed" maxReceivedMessageSize="20480000" />
</netTcpBinding>
</bindings>
</system.serviceModel>
What I would like to do is to change only the address (in this example, net.tcp://localhost:5000) when the application is executed. So I must be able to read the current value and display that to the user, and then take their input and save it back into that field.
The test below may help you. Essentially the steps are
Instantiate an instance of the host that reads the configuration from the .config file;
Create a new instance of EndpointAddress using the same configuration as the old one, but changing the uri and assign it to the Address property of your ServiceEndpoint.
[TestMethod]
public void ChangeEndpointAddressAtRuntime()
{
var host = new ServiceHost(typeof(FileRepositoryService));
var serviceEndpoint = host.Description.Endpoints.First(e => e.Contract.ContractType == typeof (IFileRepositoryService));
var oldAddress = serviceEndpoint.Address;
Console.WriteLine("Curent Address: {0}", oldAddress.Uri);
var newAddress = "net.tcp://localhost:5001";
Console.WriteLine("New Address: {0}", newAddress);
serviceEndpoint.Address = new EndpointAddress(new Uri(newAddress), oldAddress.Identity, oldAddress.Headers);
Task.Factory.StartNew(() => host.Open());
var channelFactory = new ChannelFactory<IFileRepositoryService>(new NetTcpBinding("customTcpBinding"), new EndpointAddress(newAddress));
var channel = channelFactory.CreateChannel();
channel.Method();
(channel as ICommunicationObject).Close();
channelFactory = new ChannelFactory<IFileRepositoryService>(new NetTcpBinding("customTcpBinding"), oldAddress);
channel = channelFactory.CreateChannel();
bool failedWithOldAddress = false;
try
{
channel.Method();
}
catch (Exception e)
{
failedWithOldAddress = true;
}
(channel as ICommunicationObject).Close();
Assert.IsTrue(failedWithOldAddress);
}
you can create the service instance providing a configuration name and endpoint. So you can use;
EndpointAddress endpoint = new EndpointAddress(serviceUri);
var client= new MyServiceClient(endpointConfigurationName,endpoint )
look at msdn article.

Read WCF service endpoint address by name from web.config

Here I am trying to read my service endpoint address by name from web.config
ClientSection clientSection = (ClientSection)ConfigurationManager.GetSection("system.serviceModel/client");
var el = clientSection.Endpoints("SecService"); // I don't want to use index here as more endpoints may get added and its order may change
string addr = el.Address.ToString();
Is there a way I can read end point address based on name?
Here is my web.config file
<system.serviceModel>
<client>
<endpoint address="https://....................../FirstService.svc" binding="wsHttpBinding" bindingConfiguration="1ServiceBinding" contract="abc.firstContractName" behaviorConfiguration="FirstServiceBehavior" name="FirstService" />
<endpoint address="https://....................../SecService.svc" binding="wsHttpBinding" bindingConfiguration="2ServiceBinding" contract="abc.secContractName" behaviorConfiguration="SecServiceBehavior" name="SecService" />
<endpoint address="https://....................../ThirdService.svc" binding="wsHttpBinding" bindingConfiguration="3ServiceBinding" contract="abc.3rdContractName" behaviorConfiguration="ThirdServiceBehavior" name="ThirdService" />
</client>
</system.serviceModel>
This will work clientSection.Endpoints[0];, but I am looking for a way to retrieve by name.
I.e. something like clientSection.Endpoints["SecService"], but it's not working.
This is how I did it using Linq and C# 6.
First get the client section:
var client = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
Then get the endpoint that's equal to endpointName:
var qasEndpoint = client.Endpoints.Cast<ChannelEndpointElement>()
.SingleOrDefault(endpoint => endpoint.Name == endpointName);
Then get the url from the endpoint:
var endpointUrl = qasEndpoint?.Address.AbsoluteUri;
You can also get the endpoint name from the endpoint interface by using:
var endpointName = typeof (EndpointInterface).ToString();
I guess you have to actually iterate through the endpoints:
string address;
for (int i = 0; i < clientSection.Endpoints.Count; i++)
{
if (clientSection.Endpoints[i].Name == "SecService")
address = clientSection.Endpoints[i].Address.ToString();
}
Well, each client-side endpoint has a name - just instantiate your client proxy using that name:
ThirdServiceClient client = new ThirdServiceClient("ThirdService");
Doing this will read the right information from the config file automatically.

WCF Discovery simply doesn't work

I'm trying to add ad-hoc discovery to a simple WCF service-client setup (currently implemented by self hosting in a console app). Debugging using VS2010 on windows 7, and doing whatever I can find in online tutorial, but still - the discovery client simply finds nothing. Needless to say if I open a client to the correct service endpoint I can access the service from the client.
service code:
using (var selfHost = new ServiceHost(typeof(Renderer)))
{
try
{
selfHost.Open();
...
selfHost.Close();
service app.config:
<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service name="TestApp.Renderer">
<host>
<baseAddresses>
<add baseAddress="http://localhost:9000" />
</baseAddresses>
</host>
<endpoint address="ws" binding="wsHttpBinding" contract="TestApp.IRenderer"/>
<endpoint kind="udpDiscoveryEndpoint"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceDiscovery/>
<serviceMetadata httpGetEnabled="True"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
client discovery code:
DiscoveryClient discoveryClient = new DiscoveryClient(new UdpDiscoveryEndpoint());
var criteria = new FindCriteria(typeof(IRenderer)) { Duration = TimeSpan.FromSeconds(5) };
var endpoints = discoveryClient.Find(criteria).Endpoints;
The 'endpoints' collection always comes out empty. I've tried running the service and client from the debugger, from a command line, from an admin command line - everything, but to no avail (all on the local machine, of course, not to mantion I'll need it running on my entire subnet eventually)
Any help would be appreciated :-)
Here is a super simple discovery example. It does not use a config file, it is all c# code, but you can probably port the concepts to a config file.
share this interface between host and client program (copy to each program for now)
[ServiceContract]
public interface IWcfPingTest
{
[OperationContract]
string Ping();
}
put this code in the host program
public class WcfPingTest : IWcfPingTest
{
public const string magicString = "djeut73bch58sb4"; // this is random, just to see if you get the right result
public string Ping() {return magicString;}
}
public void WcfTestHost_Open()
{
string hostname = System.Environment.MachineName;
var baseAddress = new UriBuilder("http", hostname, 7400, "WcfPing");
var h = new ServiceHost(typeof(WcfPingTest), baseAddress.Uri);
// enable processing of discovery messages. use UdpDiscoveryEndpoint to enable listening. use EndpointDiscoveryBehavior for fine control.
h.Description.Behaviors.Add(new ServiceDiscoveryBehavior());
h.AddServiceEndpoint(new UdpDiscoveryEndpoint());
// enable wsdl, so you can use the service from WcfStorm, or other tools.
var smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
h.Description.Behaviors.Add(smb);
// create endpoint
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
h.AddServiceEndpoint(typeof(IWcfPingTest) , binding, "");
h.Open();
Console.WriteLine("host open");
}
put this code in the client program
private IWcfPingTest channel;
public Uri WcfTestClient_DiscoverChannel()
{
var dc = new DiscoveryClient(new UdpDiscoveryEndpoint());
FindCriteria fc = new FindCriteria(typeof(IWcfPingTest));
fc.Duration = TimeSpan.FromSeconds(5);
FindResponse fr = dc.Find(fc);
foreach(EndpointDiscoveryMetadata edm in fr.Endpoints)
{
Console.WriteLine("uri found = " + edm.Address.Uri.ToString());
}
// here is the really nasty part
// i am just returning the first channel, but it may not work.
// you have to do some logic to decide which uri to use from the discovered uris
// for example, you may discover "127.0.0.1", but that one is obviously useless.
// also, catch exceptions when no endpoints are found and try again.
return fr.Endpoints[0].Address.Uri;
}
public void WcfTestClient_SetupChannel()
{
var binding = new BasicHttpBinding(BasicHttpSecurityMode.None);
var factory = new ChannelFactory<IWcfPingTest>(binding);
var uri = WcfTestClient_DiscoverChannel();
Console.WriteLine("creating channel to " + uri.ToString());
EndpointAddress ea = new EndpointAddress(uri);
channel = factory.CreateChannel(ea);
Console.WriteLine("channel created");
//Console.WriteLine("pinging host");
//string result = channel.Ping();
//Console.WriteLine("ping result = " + result);
}
public void WcfTestClient_Ping()
{
Console.WriteLine("pinging host");
string result = channel.Ping();
Console.WriteLine("ping result = " + result);
}
on the host, simply call the WcfTestHost_Open() function, then sleep forever or something.
on the client, run these functions. It takes a little while for a host to open, so there are several delays here.
System.Threading.Thread.Sleep(8000);
this.server.WcfTestClient_SetupChannel();
System.Threading.Thread.Sleep(2000);
this.server.WcfTestClient_Ping();
host output should look like
host open
client output should look like
uri found = http://wilkesvmdev:7400/WcfPing
creating channel to http://wilkesvmdev:7400/WcfPing
channel created
pinging host
ping result = djeut73bch58sb4
this is seriously the minimum I could come up with for a discovery example. This stuff gets pretty complex fast.
Damn! it was the firewall... for some reason all UDP communication was blocked - disabling the firewall solved the problem. Now I only need to figure out the correct firewall configuration...

Categories