I'm working on a SOAP project which contains:
C# client
C# server (WCF)
J2EE server (with webservice)
On my C# Server, I have my service and I'm adding the J2EE WSDL to this project to calling a J2EE method.
But I'm still having an issue. Which does not append when I'm calling the WSDL from an console app wjich contains a MAIN.
Any clue if there is a restriction or anything else?
the service:
public class ClientRequest : IClientRequest
{
public STG m_service(STG msg)
{
var remoteJavaServer = new ServerServicesClient();
remoteJavaServer.Open();
Console.WriteLine("Result value for 2 square -> {0}", remoteJavaServer.test(2));
return msg;
}
public int m_square(int i)
{
Console.WriteLine("value input = "+i);
return i*i;
}
}
the console app :
class Program
{
static void Main(string[] args)
{
var client = new ServerServicesClient();
client.Open();
Console.WriteLine("2 -> {0}", client.test(2));
}
}
Turns out, only my 'service' library project was configure with the endpoint to target the WSDL. So, I've add the endpoint to the host console app and now it is working.
Thanks anyway.
Closed.
Related
This is my first project using Azure. So if I am asking very basic question, please be patient with me.
I have a web application which runs on Azure server. I also have a windows form app which is hosted on Azure VM. According to the requirement, a web app will establish a connection with the windows form app whenever it is required, will send a notification to the form app, receive a response from it and will cut off the connection. So here Web app is like a client and a Windows form app is like a server.
I tried using SignalR. Activated the end point and a port for the Windows form app on Azure portal. I was able to establish the connection but never getting the confirmation of that connection back from the Windows Form app.
Am I using the proper technique or there is a better way to do this? I hope someone will suggest a proper solution.
Here is what I tried
Server side code in Windows form app
Installed the Microsoft.AspNet.SignalR package by Nuget
Activated the VM end point and port #12345 from Azure portal
DNS name of VM - abc.xyz.net
Endpoint port number - 12345
public partial class FormsServer : Form
{
private IDisposable SignalR { get; set; }
const string ServerURI = "http://abc.xyz.net:12345";
private void btnStart_Click(object sender, EventArgs e)
{
btnStart.Enabled = false;
Task.Run(() => StartServer());
}
private void StartServer()
{
try
{
SignalR = WebApp.Start<Startup>(ServerURI);
}
catch (TargetInvocationException)
{ }
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR("/CalcHub", new HubConfiguration());
}
}
public class CalcHub : Hub
{
public async Task<int> AddNumbers(int no1, int no2)
{
MessageBox.Show("Add Numbers");
return no1 + no2;
}
}
Client side code in web application
Installed the Microsoft.AspNet.SignalR.Client by Nuget
public class NotificationAppClient
{
Microsoft.AspNet.SignalR.Client.HubConnection connectionFr;
IHubProxy userHubProxy;
public void InitiateServerConnection()
{
connectionFr = new Microsoft.AspNet.SignalR.Client.HubConnection("http:// abc.xyz.net:12345/CalcHub", useDefaultUrl: false);
connectionFr.TransportConnectTimeout = new TimeSpan(0, 0, 60);
connectionFr.DeadlockErrorTimeout = new TimeSpan(0, 0, 60);
userHubProxy = connectionFr.CreateHubProxy("CalcHub");
userHubProxy.On<string>("addMessage", param => {
Console.WriteLine(param);
});
connectionFr.Error += async (error) =>
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await connectionFr.Start();
};
}
public async Task<int> AddNumbers()
{
try
{
int result = -1;
connectionFr.Start().Wait(30000);
if (connectionFr.State == ConnectionState.Connecting)
{
connectionFr.Stop();
}
else
{
int num1 = 2;
int num2 = 3;
result = await userHubProxy.Invoke<int>("AddNumbers", num1, num2);
}
connectionFr.Stop();
return result;
}
catch (Exception ex)
{ }
return 0;
}
}
There is actually no need to connect and disconnect constantly. The persistent connection will work as well.
Thanks for the reply
So the code works even if it is messy. Usually this is a firewall issue so I would make absolutely sure the port is open all the way between the two services. Check both the Windows firewall and the one in the Azure Network Security Group to make sure that the port is open. I recommend double checking the "Effective Security Rules". If there are multiple security groups in play it is easy to open the port in one group but forget the other.
In order to rule out a DNS issue, you can change const string ServerURI = "http://abc.xyz.net:12345"; to `"http://*:12345" and try connecting over the public IP.
Finally if the catch blocks are actually empty as opposed to just shortening the code either remove them or add something in them that allows you to see errors. As is any errors are just being swallowed with no idea if they are happening. I didn't get any running your code, but it would be good to be sure.
As far as the method of communication goes, if you are going to stick with SignalR I would move opening the connection on the client into the InitiateServerConnection() and leave it open as long as the client is active. This is hoq SignalR is designed to work as opposed to opening and closing the connection each time. If your end goal is to push information in real time from your forms app to the web app as opposed to the web app pulling the data this is fine. For what you are currently doing this is not ideal.
For this sort of use case, I would strongly suggest looking at WebAPI instead of SignalR. If you are going to add more endpoints SignalR is going to get increasingly difficult to work with in comparison to WebApi. You can absolutely use both in parallel if you need to push data to the web client but also want to be able to request information on demand.
The Startup method on the server changes just a bit as Microsoft.AspNet.WebApi is what is being setup instead of SignalR:
class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
}
}
Instead of a Hub you create a controller.
public class AddController : ApiController
{
// GET api/add?num1=1&num2=2
public HttpResponseMessage Get(int num1, int num2)
{
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
response.Content = new StringContent((num1 + num2).ToString());
return response;
}
}
The client side is where things get a lot simpler as you no longer need to manage what is usually a persistent connection. InitiateServerConnection() can go away completely. AddNumbers() becomes a simple http call:
public static async Task<int> AddNumbers(int num1, int num2)
{
try
{
using(var client = new HttpClient())
{
return Int32.Parse(await client.GetStringAsync($"http://<sitename>:12345/api/add?num1={num1}&num2={num2}"));
}
}
catch (Exception e)
{
//Do something with the exception
}
return 0;
}
If that doesn't end up resolving the issue let me know and we can continue to troubleshoot.
I've been trying to create an application that can receive information from other running applications through WCF.
I've setup a void method in a separate class, created the interface, and hosted the service.
In my Host application I have the following method.
public Class ReceivingMethods : IReceivingMethods
{
Public void HelloWorld(string text)
{
MessageBox.Show(text);
}
}
and
[ServiceContract]
interface iReceivingMethods
{
[OperationContract]
void HelloWorld(string text);
}
In the client, I would like to do this:
HostService client = new HostService();
client.HelloWorld("Hello World");
client.close();
But it doesn't work and instead I have to do this.
HostService client = new HostService();
HelloWorld hi = new HelloWorld();
hi.text = "Hello World";
client.HelloWorld(hi);
client.close();
I've gotten it to work as the former previously in an Application/ASP combination, but not on this application and I cannot find any difference in the setup between the two applications.
Can anybody tell me what is required from the WCF setup to get it to work as the former?
HostService client = new HostService();
You haven't mention what endpoint or which class object to use.Typically the servicehost class must create the object of particular end point,something like below one.
using(System.ServiceModel.ServiceHost host =
new System.ServiceModel.ServiceHost(typeof(ReceivingMethodsnamespace.ReceivingMethods )))
{
host.Open();
Console.WriteLine("Host started # " + DateTime.Now.ToString());
Console.ReadLine();
}
Generally the hostservice must create an object of the class which is implementing servicecontract interface(servicename of AddressBindingContract file)
Turns out I found the issue somewhere else.
I configured the client service reference to "always generate message contracts"
Unchecking this and updating the service reference solved the issue.
I found the solution here.
https://social.msdn.microsoft.com/Forums/en-US/b9655eeb-cdbb-4703-87d8-00deac340173/add-service-reference-creates-message-contracts-requestresponse-objects-with-always-generate?forum=wcf
I've been following tutorial here and trying to host a simple REST Server using WCF. Basically, I created the WCF interface and class file as described in the tutorial:
[ServiceContract]
public interface IService
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/GET/{msg}/{msg2}")]
string GetRequest(string msg, string msg2);
[OperationContract]
[WebInvoke(Method = "PUT", UriTemplate = "/PUT/{msg}")]
void PutRequest(string msg, Stream contents);
}
and the concrete class:
class Service : IService
{
static string Message = "Hello";
public string GetRequest(string msg, string msg2)
{
return Message + msg + msg2;
}
public void PutRequest(string msg, Stream contents)
{
Service.Message = msg + msg + msg;
string input = new StreamReader(contents).ReadToEnd();
Console.WriteLine("In service, input = {0}", input);
}
}
These 2 WCF service classes work perfecting in a Console Application I created. Here is how "Main" looks like. When I submit a GET request to the Console Application, I get a 200 OK:
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
using (var host = new ServiceHost(typeof(Service)))
{
var ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), new Uri("http://1.10.100.126:8899/MyService"));
ep.EndpointBehaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Service is running");
Console.ReadLine();
host.Close();
}
}
}
}
However, when I want to use those 2 classes in a WPF Application, they don't work anymore. Here is the MainWindow class for the WPF Application. When I submit a GET Request to the WPF Application, I get error 502 BAD GATEWAY:
namespace WpfApplication1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
using (var host = new ServiceHost(typeof(Service)))
{
var ep = host.AddServiceEndpoint(typeof(IService), new WebHttpBinding(), new Uri("http://1.10.100.126:8899/MyService"));
ep.EndpointBehaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Service is running");
Console.ReadLine();
host.Close();
}
}
}
}
How do you make those 2 WCF classes work with a simple empty WPF Application project? Why does those 2 WCF classes work with an empty Console Application project, but not an empty WPF Application Project?
Giving you a complete, thorough answer on how to properly host a WCF service properly in a WPF application is really a bit too broad, but here are some pointers.
You have a few major problems with your WPF attempt:
You're attempting to host the service on the UI thread, a big no-no in GUI design and programming. If you got it working the way you have it, you'd lock your UI and the user wouldn't be able to do anything but force-close your application.
You're handling it all in a code behind for a Window - WPF encourages the MVVM pattern, which guides you to separate concerns of how your view (window, controls, etc.) is rendered vs. what services are used/hosted/consumed.
You're attempting to block the thread by using Console.ReadLine() in a GUI application, where there is no Console listening - so Console.ReadLine() is just returning immediately (but if you did manage to block the thread, you'd be back to problem #1).
For a full tutorial on how to do what you're attempting with better design principles, see the following blog
Some highlights from that:
Create some controls (e.g. buttons that say 'Start' and 'Stop') to start and stop your service.
Wire up those buttons to the logic to start your service and stop your service respectively.
There's definitely improvements that could be made there - starting and managing the lifetime of the service, using the Commanding model in WPF, using the TPL or a BackgroundWorker to run the service in a different thread, making fuller usage of the MVVM pattern - but it's a start.
class myremoteobject:MarshalByRefObject
{
public myremoteobject()
{
Console.WriteLine("hi there");
}
}
class Program
{
static void Main(string[] args)
{
HttpChannel chn = new HttpChannel(1234);
ChannelServices.RegisterChannel(chn, false);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(myremoteobject), "abc", WellKnownObjectMode.Singleton);
Console.WriteLine("server started.... press any key to stop");
Console.ReadLine();
}
}
I have these simple classes but while I am trying to generate metadata from it using soapsuds tool
like this:- soapsuds -ia:server -nowp -oa:metadata.dll
I am getting error
Error: Invalid schema data., No Bindings with SOAP, RPC and Encoded elements
I have received this error in the past because soapsuds.exe expects a different encoding than that provided by ASP.NET. In such a case, wsdl.exe worked for me. It is a difference between remoting (soapsuds.exe) and web services (wsdl.exe).
Continuing to learn WCF, I'm trying to write a small program that would with a click of a button take the work from texbox1 , pass it to ServiceContract and get back its length.
Here's how far I got.
Form1.cs:
...
wcfLib.Service myService = new wcfLib.Service();
private void button1_Click(object sender, EventArgs e)
{
textBox2.Text = Convert.ToString( myService.go(textBox1.Text) );
}
...
and the wcf file:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace wcfLib
{
[ServiceContract]
public interface IfaceService
{
[OperationContract]
int wordLen(string word);
}
public class StockService : IfaceService
{
public int wordLen(string word)
{
return word.Length;
}
}
public class Service
{
public int go( string wordin )
{
ServiceHost serviceHost = new ServiceHost(typeof(StockService), new Uri("http://localhost:8000/wcfLib"));
serviceHost.AddServiceEndpoint(typeof(IfaceService), new BasicHttpBinding(), "");
serviceHost.Open();
int ret = **///// HOW SHOULD I PASS wordin TO StockService to get word.Length in return?**
serviceHost.Close();
return ret;
}
}
}
what I can't figure out right now, is how do I pass the wordin variable above into the ServiceContract?
You need to create the client in your form and call wordLen() directly... only a class that inherits from IfaceService can be called as a WCF service. So:
// You'll have to create references to your WCF service in the project itself...
// Right-click your form project and pick 'Add Service Reference', picking
// 'Discover', which should pick up the service from the service project... else
// enter http://localhost:8000/wcfLib and hit 'Go'.
// You'll have to enter a namespace, e.g. 'MyWcfService'... that namespace is
// used to refer to the generated client, as follows:
MyWcfService.wcfLibClient client = new MyWcfService.wcfLibClient();
private void button1_Click(object sender, EventArgs e) {
// You really shouldn't have the client as a member-level variable...
textBox2.Text = Convert.ToString(client.wordLen(textBox1.Text));
}
If your Service class is meant to host the WCF Service, it needs to be its own executable and running... put the code you have in go() in Main()
Or host your WCF Service in IIS... much easier!
Edit
IIS = Internet Information Services... basically hosting the WCF Service over the web.
To host in IIS, create a new project, "WCF Service Application". You'll get a web.config and a default interface and .svc file. Rename these, or add new items, WCF Service, to the project. You'll have to read up a bit on deploying to IIS if you go that route, but for debugging in Visual Studio, this works well.
To split into two applications, just make the form its own project... the service reference is set through the application's config file; you just point it to the address of the machine or website, e.g. http://myintranet.mycompany.com:8000/wcflib or http://myserver:8000/wcflib.
Thanks for the vote!
You've definitely got things back-to-front. You don't want to create the ServiceHost in your Go method, or at least, you'd never create it in any method invoked by the client, because how could the client call it if the service hasn't been created yet?
A service in WCF is started, and THEN you can invoke its methods from a remote client. EG, this is your Main() for the service:
ServiceHost serviceHost = new ServiceHost(typeof(StockService), new Uri("http://localhost:8000/wcfLib"));
serviceHost.AddServiceEndpoint(typeof(IfaceService), new BasicHttpBinding(), "");
serviceHost.Open();
Console.WriteLine("Press return to terminate the service");
Console.ReadLine();
serviceHost.Close();
Then for your client you'd use "Add Service Reference" in Visual Studio (right-click on the Project in Solution Explorer to find this menu option) and enter the address for the service. Visual Studio will create a proxy for your service, and this is what you'd instantiate and use on the client. EG:
MyServiceClient client = new MyServiceClient();
textBox2.Text = Convert.ToString( client.wordLen(textBox1.Text) );