Program acting as client and server - c#

I have a few questions regarding WCF:
- Can a program act as both client and server ?
- What's wrong with my code :
The service:
[ServiceContract]
public interface IShout
{
[OperationContract]
String Broadcast(String message);
}
The implementation:
public class eveShout : IShout
{
public String Broadcast(String message)
{
return message + " reply";
}
}
I start the service in the form contructor:
ServiceHost s = new ServiceHost(typeof(IShout));
s.AddServiceEndpoint(typeof(IShout), new BasicHttpBinding(), "http://localhost:9189");
s.Open();
The, When I click a button on another form, I want to send a message and get a reply back.
I use the following code:
ChannelFactory<IShout> channel = new ChannelFactory<IShout>(new BasicHttpBinding(), "http://localhost:9189");
IShout shout = channel.CreateChannel();
String reply = shout.Broadcast("Test");
Note: all the code is in the same namespace.
Note: I first start the "server" (open) then the app continues.
when i run the code, the server is created. I use netstat -a to see if the port is open. when I run the command, i get 9189 is in listening state. but the code stops at the command reply = shout("test"). and I get anexception that says
The request channel timeout while waiting for a reply after 00:00:59...

Yes, you can have an app act as both client and server.
I see a couple of things that may need correcting. First, try adding OperationContract.
[ServiceContract]
public interface IShout
{
[OperationContract]
String Broadcast(String message);
}
Then, take the type of the class, not the interface.
ServiceHost s = new ServiceHost(typeof(eveShout));
s.AddServiceEndpoint(typeof(IShout), new BasicHttpBinding(), "http://localhost:9189");
s.Open();
Make sure you you have permission to access the namespace (s.Open() should throw an exception if it does not).
net http add urlacl url=http://+:9189/ user=...
See if these suggestions help.
(oh yeh, and make Broadcast public in your class)
A quick example WindowsFormsApplication looks like this...
// form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChannelFactory<IShout> channel = new ChannelFactory<IShout>(new BasicHttpBinding(), "http://localhost:9189");
IShout shout = channel.CreateChannel();
String reply = shout.Broadcast("Test");
}
}
}
// and Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.ServiceModel;
namespace WindowsFormsApplication1
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
ServiceHost s = new ServiceHost(typeof(eveShout));
s.AddServiceEndpoint(typeof(IShout), new BasicHttpBinding(), "http://localhost:9189");
s.Open();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
public class eveShout : IShout
{
public String Broadcast(String message)
{
return message + " reply";
}
}
[ServiceContract]
public interface IShout
{
[OperationContract]
String Broadcast(String message);
}
}
See if you can get something as simple as this working. That will at least prove to you that it can be done and that the problem is somewhere else.

Enable WCF debugging.
The easiest way to do this is with WCF Service Configuration Editor. Open the utility and then browse to open your application's configuration file. From the diagnostics section simply click 'enable tracing'. The default tracing will be fine.
Once you run your application, the framework will dump a log file to a location specified in your configuration file. Double click to open it and read through the red events (these are the ones that have exceptions or unexpected outcome). It's very helpful and should help you identify where the problem is occurring.

Related

How to implement WCF ServiceModelEx Subscriber?

I'm using ServiceModelEx WCF library from Juval Lowy's "Programming WCF Services". I'm trying to implement a Publish-Subscribe Service with publisher and subscriber. What I have done so far is the publisher and the discover-publish service.
Service Contract:
[ServiceContract]
interface IMyEvents
{
[OperationContract(IsOneWay=true)]
void OnEvent1(int number);
}
Discover - publish Service:
class MyPublishService : DiscoveryPublishService<IMyEvents>, IMyEvents
{
public void OnEvent1(int number)
{
FireEvent(number);
}
}
Discover - publish service host:
ServiceHost host = DiscoveryPublishService<IMyEvents>.
CreateHost<MyPublishService>();
host.Open();
// later..
host.Close();
Publisher:
IMyEvents proxy = DiscoveryPublishService<IMyEvents>.CreateChannel();
proxy.OnEvent1();
(proxy as ICommunicationObject).Close();
My question is how can I implement the subscriber? The book says to implement the service contract. That's simple.
class EventServiceSubscriber : IMyEvents
{
public void OnEvent1(int number)
{
// do something
}
}
but how can i host the subscriber? How subscriber can connect to the Publish-Subscribe service?
To get this to work I created a SubcriptionService as follows:
using ServiceLibrary.Contracts;
using ServiceModelEx;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
namespace Subscriber
{
[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any, IncludeExceptionDetailInFaults = DebugHelper.IncludeExceptionDetailInFaults, InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false)]
class SubscriptionService : DiscoveryPublishService<IMyEvents>, IMyEvents
{
public void OnEvent1()
{
Debug.WriteLine("SubscriptionService OnEvent1");
}
public void OnEvent2(int number)
{
Debug.WriteLine("SubscriptionService OnEvent2");
}
public void OnEvent3(int number, string text)
{
Debug.WriteLine("SubscriptionService OnEvent3");
}
}
}
Then I set up a host for this service as follows:
ServiceHost<SubscriptionService> _SubscriptionHost = DiscoveryPublishService<IMyEvents>.CreateHost<SubscriptionService>();
_SubscriptionHost.Open();
A basic working sample can be found in my Github account at the following url.
https://github.com/systemsymbiosis/PublishSubscribeWithDiscovery
There are a bunch of articles around that cover this subject. For starters, this one. You can host your subscriber in different ways like a console application or a ASP.NET application. Every application type has some kind of startup method so that'd be a good place to implement your subscription/publishing logic.

Asp.Net 4.5 Consume Service Reference with windows authentication and default credentials

I have a web application on my intranet configured to use windows authentication on IIS. We have a windows network and an active dircory server, so when some user try to access the application the browser doesn't ask for login and password because it uses the windows credentials of the current logged user.
I added a webservice in this application and tried to consume it in an windows application. I got an error 401 when I tried. The users are already logged on windows with their own credentials, so I'd like to have my windows application logging into the webservice using current user's credentials.
My Service:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace MyWebServices
{
/// <summary>
/// Summary description for TestWS
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class TestWS : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
My console Application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MyWebServiceClient
{
class Program
{
static void Main(string[] args)
{
TWS.TestWSSoapClient svc = new TWS.TestWSSoapClient();
try
{
Console.WriteLine(svc.HelloWorld());
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
finally
{
Console.ReadLine();
}
}
}
}
both are .net framework 4.5
Sorry about my poor English :)
I found it.
I needed to create a basic http binding and set it's client credential type to Windows. It works with ntlm too.
I had to create an endpont address to and pass both http binding and endpoint address to my SoapClient constructor.
static void Main(string[] args)
{
try
{
System.ServiceModel.BasicHttpBinding MyHttpBinding = new System.ServiceModel.BasicHttpBinding(System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly);
MyHttpBinding.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
//MyHttpBinding.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Ntlm; //works too
System.ServiceModel.EndpointAddress MyAuthASMXWebServiceAddress = new System.ServiceModel.EndpointAddress(new Uri("http://localhost/TestWS.asmx"));
TWS.TestWSSoapClient svc = new TWS.TestWSSoapClient(MyHttpBinding, MyAuthASMXWebServiceAddress);
Console.WriteLine(svc.HelloWorld());
}
catch (Exception err)
{
Console.WriteLine(err.ToString());
}
finally
{
Console.ReadLine();
}
}
I still doesn't know what means BasicHttpSecurityMode.TransportCredentialOnly and what are the another options, how they work. But, for now, it worked.

Make Windows Service run a specific file

I've been watching some tuts on how to create a C# Windows Service; all good but no one says how to make te service run, at the end of installation, a specific file from installation folder(in my case hidden.vbs)(my app has 2 project: the service itself and the setup).
After the install of the setup, the service starts PROJECT_NAME.exe and PROJECT_NAME.svhost.exe
Tell me please if you need any other code in order to help me...
Here is my Program.cs
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.ServiceProcess;
namespace PROJECT_NAME
{
[RunInstaller(true)]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
public ProjectInstaller()
{
InitializeComponent();
}
private void serviceInstaller1_AfterInstall(object sender, InstallEventArgs e)
{
new ServiceController(serviceInstaller1.ServiceName).Start();
}
}
}
Service1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
namespace PROJECT_NAME
{
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
}
public void OnDebug()
{
OnStart(null);
}
protected override void OnStart(string[] args)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "OnStart.txt");
}
protected override void OnStop()
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "OnStart.txt");
}
}
}
Also, here is a pic of my Solution Explorer http://i.imgur.com/wbqUGOc.png ; please tell me how or where should I import the files I need the service to run.
It's my first time in C#, I'm not willing to understand it now, but to make this service because I will need it in my work..
Your script can do one of several things to start a service:
Issue the net start console command to launch a service (e.g. net start "My Service Name")
OR
Programmaticaly, call the StartService API.

Web service and form translator

My project is to write a web service and a web form that consumes it. It should have two text boxes and a button. The user enters an text speak acronym in the first text box and presses the button. The web service compares the textbox1 entry against a dictionary file, and displays the resulting full word in the second text box. This is the code I have so far and I am really struggling to get it to work, any help would be appreciated. At this point I have 'Type or namespace definition, or end of file expected' error. Here are the two files i have.
Default.aspx.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.IO;
public partial class _Default : System.Web.UI.Page
{
private Dictionary<string, string> _dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
protected void Page_Load(object sender, EventArgs e)
{
using (var reader = new StreamReader(File.OpenRead(#"C:/dictionary.csv")))
{
while (!reader.EndOfStream)
{
string[] tokens = reader.ReadLine().Split(';');
_dictionary[tokens[0]] = tokens[1];
}
}
}
protected void Button1_Click(object sender, EventArgs e)
{
localhost.Service obj = new localhost.Service();
TextBox1.Text = (obj.Translate());
}
}
Service.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.IO;
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
// [System.Web.Script.Services.ScriptService]
public class Service : System.Web.Services.WebService
{
public Service () {
//Uncomment the following line if using designed components
//InitializeComponent();
}
[WebMethod]
public string Translate(string input)
{
string output;
if(_dictionary.TryGetValue(input, out output))
return output;
// Obviously you might not want to throw an exception in this basis example,
// you might just go return "ERROR". Up to you, but those requirements are
// beyond the scope of the question! :)
throw new Exception("Sinatra doesn't know this ditty");
}
}
}
Not sure if the question is still unanswered. But here are my suggestions.
In the web service file i.e. say Service1.cs you are not declaring the _dictionary object. So you will be moving the dictionary object declaration and initialization in the constructor of the service.
Some thing like this below.
public WebService1()
{
using (var reader = new StreamReader(File.OpenRead(#"C:/dictionary.csv")))
{
while (!reader.EndOfStream)
{
string[] tokens = reader.ReadLine().Split(',');
_dictionary[tokens[0]] = tokens[1];
}
}
}
Also in the split method I would assume you wanted to use the comma instead of the semicolon(that was used in your sample).
And then in the consumption of the service, you would do some thing like this below. I was not sure what you were trying to do using the localhost object in your sample.
ServiceReference1.WebService1SoapClient obj = new WebService1SoapClient();
TextBox2.Text = obj.Translate(TextBox1.Text);
Hope this helps.
-Davood.

Wpf Server/client logon. Problems with events

I’m pretty new to programming, so bear with me if my question isn’t specific enough. Right now I’m trying to make a simple Client Logon to my server. So the server App knows which users are connected. When a client connects I want an event to fire on the server that update the userlist. But it doesn’t and I can’t figure out why. Hope you can help.
In the codes I have removed how the users should be displayed in the serverApp. Right now I just need the event to work.
In my Service Library:
INetworkService contract:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace NetworkLib
{
[ServiceContract]
public interface INetworkService
{
[OperationContract]
void Logon(UserInfo userInfo);
[OperationContract]
void Logout();
}
}
NetworkService Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace NetworkLib
{
public class NetworkService : INetworkService
{
public event EventHandler UserListChanged;
public void Logon(UserInfo userInfo)
{
OnUserListChanged();
}
public void Logout()
{
OnUserListChanged();
}
private void OnUserListChanged()
{
var handler = UserListChanged;
if (handler != null)
{
handler(this, EventArgs.Empty);
}
}
}
}
UserInfo Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace NetworkLib
{
[DataContract]
public class UserInfo
{
[DataMember]
public string Name;
}
}
In my ServerApp (WPF):
using System.ServiceModel;
using NetworkLib;
namespace ServerApp
{
public partial class MainWindow : Window
{
NetworkService networkService;
public MainWindow()
{
InitializeComponent();
ServiceHost host = new ServiceHost(typeof(NetworkService));
host.Open();
networkService = new NetworkService();
networkService.UserListChanged += networkService_UserListChanged;
}
private void networkService_UserListChanged(object sender, EventArgs e)
{
MessageBox.Show("It Works!");
}
}
}
In my ClientApp (WPF): (Have made a Service Reference to the Server)
namespace ClientApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
ServiceReference.NetworkServiceClient proxy = new ServiceReference.NetworkServiceClient();
ServiceReference.UserInfo userInfo = new ServiceReference.UserInfo();
userInfo.Name = "Test";
proxy.Logon(userInfo);
}
}
}
You subscribe to event of other NetworkService instance than ServiceHost instantiates. In your case every time you make request to server, new NetworkService instance is created. Place the following attribute above NetworkService class:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
Then subscribe to event:
var serviceInstance = (NetworkService)host.SingletonInstance;
serviceInstance.UserListChanged += networkService_UserListChanged;
When creating your ServiceHost, you should provide NetworkService instance instead of typeof(NetworkService)
ServiceHost host = new ServiceHost(networkService);
You need to initialize it first, of course.
I didnt look in great detail but overall your code looks ok. It is sometimes useful in this situation to run 2 instances of VisualStudio - one for server in debug and one for client in debug. If you put a break point in client button1_Click code in VS thats debugging client, and a break point in NetworkServices.Logout in VS thats debugging server you will be able to step from client to server code and see easily whats going wrong where.
Why do you need an event model here? Why not just handle your "event" directly in NetworkService.Logout(). Does pushing this off to an event and then having to wire that event (which as ilya.dofofeev correctly points out is not on the same object) provide any real benefit?

Categories

Resources