WCF server/client callbacks, reply from client to server - c#

In my client/server application, I want count other value in everyone client.
I made application using callbacks, but something is wrong. I get Exception, when I want call method pipeproxy.polacz(S); Which get value to server and write in server console now.
Exception is:
This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on CallbackBehaviorAttribute.
Other problem is, how sum resault in this funkction from all clients.
example;
client 1: S = 1;
client 2: S = 2;
client 3: S = 3;
And this function take result from all clients and sum it. So server will write 6 in server console.
My application code:
server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Interface;
namespace WCFapp
{
class Program
{
static void Main(string[] args)
{
Klienci cust = new Klienci();
cust.Connect();
}
}
}
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Interface;
namespace WCFapp
{
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
class Klienci : IMessage
{
private static List<ImessageCallback> subscribers =
new List<ImessageCallback>();
public void lista()
{
string nm = Console.ReadLine();
if (nm == "1")
{
Console.WriteLine("Number of conected clients: " + subscribers.Count());
funkcja();
}
}
public void Connect()
{
using (ServiceHost host = new ServiceHost(
typeof(Klienci), new Uri("net.tcp://localhost:8000")))
{
host.AddServiceEndpoint(typeof(IMessage),
new NetTcpBinding(), "ISubscribe");
try
{
host.Open();
lista();
Console.ReadLine();
host.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
}
public bool Subscribe()
{
try
{
ImessageCallback callback = OperationContext.Current.GetCallbackChannel<ImessageCallback>();
if (!subscribers.Contains(callback))
subscribers.Add(callback);
Console.WriteLine("Client is conected ({0}).", callback.GetHashCode());
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
}
public bool Unsubscribe()
{
try
{
ImessageCallback callback = OperationContext.Current.GetCallbackChannel<ImessageCallback>();
if (subscribers.Contains(callback))
subscribers.Remove(callback);
Console.WriteLine("Client is unconected ({0}).", callback.GetHashCode());
return true;
}
catch
{
return false;
}
}
public void funkcja()
{
int a = 1; int b = 3;
subscribers.ForEach(delegate(ImessageCallback callback)
{
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
Console.WriteLine("a= {0} , b= {1}", a, b);
callback.klient_licz(a, b);
a++;
b++;
}
});
}
public void polacz(int S)
{
Console.WriteLine("Sum: {0}", S);
}
}
}
Interface:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
namespace Interface
{
[ServiceContract(CallbackContract = typeof(ImessageCallback), SessionMode = SessionMode.Required)]
public interface IMessage
{
[OperationContract]
void funkcja();
[OperationContract]
void polacz(int S);
[OperationContract]
bool Subscribe();
[OperationContract]
bool Unsubscribe();
}
[ServiceContract]
public interface ImessageCallback
{
[OperationContract]
void klient_licz(int a, int b);
}
}
Client:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Interface;
namespace Client
{
class Program
{
static void Main(string[] args)
{
clients cl = new clients();
if (cl.Conect() == true)
{
string tmp = Console.ReadLine();
while (tmp != "EXIT")
{
cl.SendMessage(tmp);
tmp = Console.ReadLine();
}
}
cl.Close();
Environment.Exit(0);
}
}
}
.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using Interface;
namespace Client
{
class clients : ImessageCallback, IDisposable
{
IMessage pipeProxy = null;
public bool Conect()
{
DuplexChannelFactory<IMessage> pipeFactory =
new DuplexChannelFactory<IMessage>(
new InstanceContext(this),
new NetTcpBinding(),
new EndpointAddress("net.tcp://localhost:8000/ISubscribe"));
try
{
pipeProxy = pipeFactory.CreateChannel();
pipeProxy.Subscribe();
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return false;
}
}
public void Close()
{
pipeProxy.Unsubscribe();
}
public void klient_licz(int a, int b)
{
int S = a + b;
Console.WriteLine("Sum= {0}", S);
pipeProxy.polacz(S); //ERROR
}
}
}

The issue here is that inside your callback method klient_licz (which is called by the server) you are making another server call. This is not allowed the way your contracts are currently setup.
Check you really need this behaviour. Do you really need to make a server call INSIDE a method on the callback interface (klient_licz).
If you do need this behaviour then you might be able to fix things by marking the klient_licz call OneWay on the callback interface. That will mean that server call to the callback will not block until the client returns (which is what is currently causing your issue because the server is waiting for the client call to return but the client call is waiting on a call to the server):
[ServiceContract]
public interface ImessageCallback {
[OperationContract(IsOneWay = true)]
void klient_licz(int a, int b);
}
Alternatively you could mark the callback implimentation with a concurrancy mode other than the default mode Single. Eg Reentrant as follows - but bear in mind that this means that calls to callback will not long be marshalled to the UI thead ie will be on threadpool threads so you would have to dispatch to update the UI from method on the callback interface:
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
class clients : ImessageCallback, IDisposable {
...
}
If you want to understand ConcurrencyMode and how it effects execution then you will really need to do someback ground reading as it does get a little complicated - but if you dont have that background it is difficult to really understand what is happen when you change the ConcurrencyMode. This dasBlonde blog post has a good summary of the different modes and behaviour - but you might want to start with some tutorials that are a bit more beginner orientated.

Related

WCF: How can I reach an instance of a service from inside an instance of a service library?

I have a long-running WCF service hosted in a Windows service. I have a service library whose purpose is to report on the state of the service. How can I get to the instance of the service from inside an instance of the service library?
To illustrate, I created a service that records the time it started, and exposes a method to report how long it's been running. The service library needs to be able to call the service's ElapsedSeconds() method, so the the library needs a reference to the running service.
I thought I could use OperationContext.Current. Here's my service library class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;
namespace TimerService
{
public class TimerServiceLib : ITimerServiceLib
{
TheTimerService m_timerService;
public TimerServiceLib()
{
var currentContext = OperationContext.Current;
var instanceContext = currentContext.InstanceContext;
m_timerService = (TheTimerService)instanceContext.GetServiceInstance();
}
public double SecondsSinceStart()
{
return m_timerService.ElapsedSeconds();
}
}
}
But the call to GetServiceInstance() creates a new instance of TimerServiceLib(), which of course gives me an infinite loop. So, what is the correct way to do this?
Here is my service class, actually being hosted in a console application:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
namespace TimerService
{
public partial class TheTimerService : ServiceBase
{
private DateTime m_startTime;
ServiceHost m_svcHost;
public TheTimerService()
{
InitializeComponent();
Init();
m_startTime = DateTime.Now;
}
public double ElapsedSeconds()
{
return (DateTime.Now - m_startTime).TotalSeconds;
}
protected override void OnStart(string[] args)
{
}
protected override void OnStop()
{
}
public void Init()
{
if (m_svcHost != null)
{
m_svcHost.Close();
}
string httpAddress = "http://localhost:1234/TimerService";
string tcpAddress = "net.tcp://localhost:1235/TimerService";
Uri[] adrbase = { new Uri(httpAddress), new Uri(tcpAddress) };
m_svcHost = new ServiceHost(typeof(TimerServiceLib), adrbase);
ServiceMetadataBehavior mBehave = new ServiceMetadataBehavior();
m_svcHost.Description.Behaviors.Add(mBehave);
var debugBehavior = m_svcHost.Description.Behaviors.Find<ServiceDebugBehavior>();
debugBehavior.IncludeExceptionDetailInFaults = true;
BasicHttpBinding httpBinding = new BasicHttpBinding();
m_svcHost.AddServiceEndpoint(typeof(ITimerServiceLib), httpBinding, httpAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
NetTcpBinding tcpBinding = new NetTcpBinding();
m_svcHost.AddServiceEndpoint(typeof(ITimerServiceLib), tcpBinding, tcpAddress);
m_svcHost.AddServiceEndpoint(typeof(IMetadataExchange),
MetadataExchangeBindings.CreateMexTcpBinding(), "mex");
m_svcHost.Open();
// SimShopServiceLib.m_shop = new CSimShopManager();
}
}
}
You can do it this way:
First, modify your TimerServiceLib and do the constructor injection of TheTimerService:
public class TimerServiceLib : ITimerServiceLib
{
private readonly TheTimerService m_timerService;
public TimerServiceLib(TheTimerService theTimerService)
{
m_timerService = theTimerService;
}
public double SecondsSinceStart()
{
return m_timerService.ElapsedSeconds();
}
}
Then, in your Init() upon creation of ServiceHost, instantiate first your service and pass the TheTimerService. Since your are creating the ServiceHost inside your windows service, wich is TheTimerService you can pass this.
Uri[] adrbase = { new Uri(httpAddress), new Uri(tcpAddress) };
var timerServiceLib = new TimerServiceLib(this)
m_svcHost = new ServiceHost(timerServiceLib , adrbase);
For more details about passing object in you service see this link.
Disclaimer : The above code is not tested.

How to use TCP client/listener in multithreaded c#?

I have written this code for my server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
private static bool terminate;
public static bool Terminate
{
get { return terminate; }
}
private static int clientNumber = 0;
private static TcpListener tcpListener;
static void Main(string[] args)
{
StartServer();
Console.Read();
}
private static void StartServer()
{
try
{
Console.WriteLine("Server starting...");
tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8000);
terminate = false;
tcpListener.Start();
tcpListener.BeginAcceptTcpClient(ConnectionHandler, null);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
Console.WriteLine("Server stopping...");
terminate = true;
if (tcpListener != null)
{
tcpListener.Stop();
}
}
}
private static void ConnectionHandler(IAsyncResult result)
{
TcpClient client = null;
try
{
client = tcpListener.EndAcceptTcpClient(result);
}
catch (Exception)
{
return;
}
tcpListener.BeginAcceptTcpClient(ConnectionHandler, null);
if (client!=null)
{
Interlocked.Increment(ref clientNumber);
string clientName = clientNumber.ToString();
new ClientHandler(client, clientName);
}
}
}
}
class ClientHandler
{
private TcpClient client;
private string ID;
internal ClientHandler(TcpClient client, string ID)
{
this.client = client;
this.ID = ID;
Thread thread = new Thread(ProcessConnection);
thread.IsBackground = true;
thread.Start();
}
private void ProcessConnection()
{
using (client)
{
using (BinaryReader reader=new BinaryReader(client.GetStream()))
{
if (reader.ReadString()==Responses.RequestConnect)
{
using (BinaryWriter writer=new BinaryWriter(client.GetStream()))
{
writer.Write(Responses.AcknowledgeOK);
Console.WriteLine("Client: "+ID);
string message = string.Empty;
while (message!=Responses.Disconnect)
{
try
{
message = reader.ReadString();
}
catch
{
continue;
}
if (message==Responses.RequestData)
{
writer.Write("Data Command Received");
}
else if (message==Responses.Disconnect)
{
Console.WriteLine("Client disconnected: "+ID);
}
else
{
Console.WriteLine("Unknown Command");
}
}
}
}
else
{
Console.WriteLine("Unable to connect client: "+ID);
}
}
}
}
}
class Responses
{
public const string AcknowledgeOK = "OK";
public const string AcknowledgeCancel = "Cancel";
public const string Disconnect = "Bye";
public const string RequestConnect = "Hello";
public const string RequestData = "Data";
}
this code listen for client requests in a multi threaded way. I am unable to understand how can i distinguish between different clients connected to my this server and which client is disconnecting and requesting for different commands.
my client code is:
private static void clietnRequest(string message,ref string response)
{
using (TcpClient client = new TcpClient())
{
if (!client.Connected)
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8000);
using (NetworkStream networkStream = client.GetStream())
{
using (BinaryWriter writer = new BinaryWriter(networkStream))
{
writer.Write(Responses.RequestConnect);
using (BinaryReader reader = new BinaryReader(networkStream))
{
if (reader.ReadString() == Responses.AcknowledgeOK)
{
response = Responses.AcknowledgeOK;
}
}
}
}
}
}
}
this piece of code connects the client to server, but i am unable to send anymore messages. I want in my app if client is connected then he can send commands to server. instead of doing this it every time act as a new client to server. I am missing some thing here, Kindly guide me in right direction. I am totally new to c# networking programming. Kindly help me improve my code. Tcp Listener and Tcp Client is valid for this scenario or do I need to use Sockets?
You are closing the connection every time client side after you send a message, if you want to do that there is nothing wrong with it but you will need to send some form of identification to the server so it can tell that this is not a new connection but a old connection connecting in for a second time. This is EXACTLY what the HTTP protocol is doing and that "identification" are internet cookies.
That first option is fine if you transmit data very infrequently but if you are doing it more often you need to keep the connection open.
Basicly you need to take the act of connecting and disconnecting out of the client request function and pass the open connection in as a argument.
private void MainCode()
{
using (TcpClient client = new TcpClient())
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8000);
while(variableThatRepresentsRunning)
{
//(Snip logic that gererates the message)
clietnRequest(message, ref response, client);
//(Snip more logic)
}
}
}
private static void clietnRequest(string message,ref string response, TcpClient client)
{
if (client.Connected)
{
using (NetworkStream networkStream = client.GetStream())
{
using (BinaryWriter writer = new BinaryWriter(networkStream))
{
writer.Write(Responses.RequestConnect);
using (BinaryReader reader = new BinaryReader(networkStream))
{
if (reader.ReadString() == Responses.AcknowledgeOK)
{
response = Responses.AcknowledgeOK;
}
}
}
}
}
else
{
//Show some error because the client was not connected
}
}
By doing it this way the client object server side represents the client, you will have one instance of it per connected client and will remain associated with that client till he disconnects. If you want to track all of the connected clients you will need to insert them all in to some collection like a List<TcpClient> (either use a Concurrent Collection or use locking because you are multi-threaded) and then you will have a list of all clients (you will need to have the clients clean up after themselves so they remove themselves from the list after a disconnection).

.NET Remoting: Exception "Value NULL" at RegisterWellKnownServiceType

I'm new at .NET remoting and C#. I need a client/server application and want to handle this with .NET Remoting. I've wrote a class library for the remoting object, the EchoServer class, with some test methods.
The class library I've added to my server project in Visual Studio. The assembly "System.Runtime.Remoting" I've added, too.
The following is the code of my server:
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.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using Remoting; //Namespace Lib
namespace Server
{
public partial class Server : Form
{
public Server()
{
InitializeComponent();
TcpChannel serverChannel = null;
try
{
serverChannel = new TcpChannel(9998);
lvStatus.Items.Add("Server is listening on port 8089...");
string strIn = "";
ChannelServices.RegisterChannel(serverChannel, true);
RemotingConfiguration.RegisterWellKnownServiceType(Type.GetType("Remoting.EchoServer, remoting_dll"), "Echo", WellKnownObjectMode.SingleCall);
}
catch (Exception ex)
{
ChannelServices.UnregisterChannel(serverChannel);
MessageBox.Show(ex.Message.ToString());
}
}
}
}
If I start the server, I will get an exception:
The value cannot be NULL
Parametername: type
I've tried some other code of a tutorial, but I will get the same excetion, equal if the class for the remoting object is implented as a class library or it is as a class directly in my project.
Can you post implementation of Remoting?
I thing that your mistake is next:
"Remoting.EchoServer, remoting_dll"
So, you should use Type.GetType correctly.
Example of working code:
static void Main(string[] args)
{
Server();
}
static void Server()
{
Console.WriteLine("Server started...");
var httpChannel = new HttpChannel(9998);
ChannelServices.RegisterChannel(httpChannel);
RemotingConfiguration.RegisterWellKnownServiceType(Type.GetType("Server.Program+SomeClass"), "SomeClass", WellKnownObjectMode.SingleCall);
Console.WriteLine("Press ENTER to quit");
Console.ReadLine();
}
public interface ISomeInterface
{
string GetString();
}
public class SomeClass : MarshalByRefObject, ISomeInterface
{
public string GetString()
{
const string tempString = "ServerString";
Console.WriteLine("Server string is sended: {0}", tempString);
return tempString;
}
}

How to make a WCF REST method entirely asynchronous with the Task Parallel Library?

I am trying to make a WCF REST method entirely asynchronous (I don't want to block anywhere). Essentially I have a simple service with 3 layers: Service, Business Logic and Data Access Layer. The Data Access Layer is accessing a database and it can take several second to get a response back from that method.
I don't understand very well how to chaining of all those method work. Can someone please help me to complete the sample I am trying to write below? I don't understand well the pattern used by WCF and I didn't find much documentation on the subject.
Can someone help me to complete the following example? In addition, how can I measure that the service will be able to handle more load than a typical synchronous implementation?
using System;
using System.Collections.Generic;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.ServiceModel.Activation;
using System.ServiceModel.Web;
using System.Threading.Tasks;
namespace WcfRestService1
{
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1
{
private BusinessLogic bll = new BusinessLogic();
// Synchronous version
[WebGet(UriTemplate = "/sync")]
public string GetSamples()
{
return bll.ComputeData();
}
// Asynchronous version - Begin
[WebGet(UriTemplate = "/async")]
[OperationContract(AsyncPattern = true)]
public IAsyncResult BeginGetSampleAsync(AsyncCallback callback,
object state)
{
Task<string> t = bll.ComputeDataAsync();
// What am I suppose to return here
// return t.AsyncState; ???
}
// Asynchronous version - End
public List<SampleItem> EndGetSampleAsync(IAsyncResult result)
{
// How do I handle the callback here?
}
}
public class BusinessLogic
{
public Task<string> ComputeDataAsync()
{
DataAccessLayer dal = new DataAccessLayer();
return dal.GetData();
}
public string ComputeData()
{
Task<string> t = this.ComputeDataAsync();
// I am blocking... Waiting for the data
t.Wait();
return t.Result;
}
}
public class DataAccessLayer
{
public Task<string> GetData()
{
// Read data from disk or network or db
}
}
}
Here's an example. I got it working with help from the following posts:
Edit: Added an example of an async client
Implement Classic Async Pattern using TPL
http://pfelix.wordpress.com/2008/06/27/wcf-and-the-asyncpattern-property-part-1/
http://pfelix.wordpress.com/2008/06/28/wcf-and-the-asyncpattern-part-2/
Here's a little do-nothing service:
namespace WcfAsyncTest
{
[ServiceContract]
public interface IAsyncTest
{
[OperationContract(AsyncPattern=true)]
IAsyncResult BeginOperation(AsyncCallback callback, object state);
string EndOperation(IAsyncResult ar);
}
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service1" in code, svc and config file together.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Service1 : IAsyncTest
{
public IAsyncResult BeginOperation(AsyncCallback callback, object state)
{
Task result = Task.Factory.StartNew((x) =>
{
// spin to simulate some work
var stop = DateTime.Now.AddSeconds(10);
while (DateTime.Now < stop)
Thread.Sleep(100);
}, state);
if (callback != null)
result.ContinueWith(t => callback(t));
return result;
}
public string EndOperation(IAsyncResult ar)
{
ar.AsyncWaitHandle.WaitOne();
return "Hello!!";
}
}
}
And here's the client (command line):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestClient
{
class Program
{
static void Main(string[] args)
{
var client = new ServiceReference1.AsyncTestClient();
var result = client.Operation();
Console.WriteLine(result);
Console.ReadLine();
}
}
}
if you put trace points on the service, you can see that WCF really is calling EndOperation for you.
Async Client Example
First, you will need to generate an async proxy. You can do that by right-clicking on the Service Reference (in the References Folder of your project), and choosing "Configure Service Reference". Check the "Generate Asynchronous Operations" checkbox.
Now your client proxy will have some new members that weren't there before. Here's how to use them:
// this is in the command-line test client
// no changes to your service required.
static void AsyncTest()
{
var client = new ServiceReference1.AsyncTestClient();
client.OperationCompleted += new EventHandler(client_OperationCompleted);
client.OperationAsync();
Console.WriteLine("Operation Running");
}
static void client_OperationCompleted(object sender, ServiceReference1.OperationCompletedEventArgs e)
{
if (e.Error == null)
Console.WriteLine("Operation Complete. Result: " + e.Result);
else
Console.WriteLine(e.Error.ToString());
}
here is an implementation of a service that implements Async. In this the callback of wcf is passed all the way to the ado.net's sql command. When the command returns, it would invoke the service's EndXXX method, which would invoke Business layer, which would finally invoke EndXXX of SqlCommand. Let me know if you face any issues
public class Service
{
private BusinessLogic businessLayer = new BusinessLogic();
public IAsyncResult BeginAnyOperation(AsyncCallback callback, object userState)
{
return businessLayer.BeginComputeData(callback, userState);
}
public string EndAnyOperation(IAsyncResult result)
{
return businessLayer.EndComputeDate(result);
}
}
public class MyState<T> : IAsyncResult
{
public MyState() { }
public object AsyncState { get; set; }
public WaitHandle AsyncWaitHandle { get; set; }
public bool CompletedSynchronously
{
get { return true; }
}
public bool IsCompleted { get; set; }
public AsyncCallback AsyncCallback { get; set; }
public T Result { get; set; }
public IAsyncResult InnerResult { get; set; }
}
public class BusinessLogic
{
private DataAccessLayer dal = new DataAccessLayer();
public IAsyncResult BeginComputeData(AsyncCallback callback, object state)
{
return dal.BeginGetData(callback, state);
}
public string EndComputeDate(IAsyncResult asyncResult)
{
return dal.EndGetData(asyncResult);
}
}
public class DataAccessLayer
{
public IAsyncResult BeginGetData(AsyncCallback callback, object state)
{
var conn = new SqlConnection("");
conn.Open();
SqlCommand cmd = new SqlCommand("myProc", conn);
var commandResult = cmd.BeginExecuteReader(callback, state, System.Data.CommandBehavior.CloseConnection);
return new MyState<string> { AsyncState = cmd, InnerResult = commandResult };
}
public string EndGetData(IAsyncResult result)
{
var state = (MyState<string>)result;
var command = (SqlCommand)state.AsyncState;
var reader = command.EndExecuteReader(state.InnerResult);
if (reader.Read())
return reader.GetString(0);
return string.Empty;
}
}

Getting callers IP

I have application based on this tutorial
Method I use to test connection to server (in client app):
public class PBMBService : IService
{
private void btnPing_Click(object sender, EventArgs e)
{
ServiceClient service = new ServiceClient();
tbInfo.Text = service.Ping().Replace("\n", "\r\n");
service.Close();
}
//other methods
}
Service main function:
class Program
{
static void Main(string[] args)
{
Uri baseAddress = new Uri("http://localhost:8000/PBMB");
ServiceHost selfHost = new ServiceHost(typeof(PBMBService), baseAddress);
try
{
selfHost.AddServiceEndpoint(
typeof(IService),
new WSHttpBinding(),
"PBMBService");
ServiceMetadataBehavior smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
selfHost.Description.Behaviors.Add(smb);
selfHost.Open();
Console.WriteLine("Serwis gotowy.");
Console.WriteLine("Naciśnij <ENTER> aby zamknąć serwis.");
Console.WriteLine();
Console.ReadLine();
selfHost.Close();
}
catch (CommunicationException ce)
{
Console.WriteLine("Nastąpił wyjątek: {0}", ce.Message);
selfHost.Abort();
}
}
}
Ping() function decaration
[ServiceContract(Namespace = "http://PBMB")]
public interface IService
{
[OperationContract]
string Ping();
}
Ping() function implementation
public class PBMBService : IService
{
SqlConnection sql = new SqlConnection(#"Data Source=.\SqlExpress;Initial Catalog=PBMB;Integrated Security=True");
SqlCommand cmd;
private void Message(string message)
{
Console.WriteLine(DateTime.Now + " -> " + message);
}
public string Ping()
{
Message("Ping()");
return "Metoda Ping() działa.";
}
}
How can I put caller's IP in Message method?
The original blog is available through the Wayback Machine. Note that you'll need to be using WCF 3.5 or later per the author's post.
The code from the article is below;
Service Contract
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace ClientInfoSample
{
[ServiceContract]
public interface IService
{
[OperationContract]
string GetData(string value);
}
}
Implementation with retrieving IP:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Channels;
namespace ClientInfoSample
{
public class MyService : IService
{
public string GetData(string value)
{
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
return string.Format("Hello {0}! Your IP address is {1} and your port is {2}", value, endpointProperty.Address, endpointProperty.Port);
}
}
}
Are you looking for something like
HttpContext.Current.Request.UserHostAddress

Categories