David Wallis
David Wallis

Reputation: 315

c# async socket via interface

Bear with me here and try and go easy on bad practice :)

I am beginning to understand the concept of interfaces and I have implemented one in my program.. So I'll try and explain.. I am creating a class library dll that will interface with my alarm panel. The alarm panel can have two types of connection, IP and Serial.. So I have implemented an interface for this called IConnection.

and create a connection as follows:

//IConnection connection = new SerialConnection("com1", 9600);
IConnection conn = new TcpConnection(System.Net.IPAddress.Parse("192.168.0.14"), 1234);

AlarmPanel alarm = new AlarmPanel(conn, Pass);
alarm.SetLogger(logger);
alarm.Connect();

in the concrete class (correct terminology?) I implement a method called SendMessage which I use to be transport agnostic which is working well.

However I now want to add a async handler to process adhoc messages sent back that aren't command/response style messages.

I have an eventhandler working in my main TCPConnection Class:

   private static void tcpReceive(Socket client)
    {
        try
        {
            // Create the state object.
            StateObject state = new StateObject {workSocket = client};

            // Begin receiving the data from the remote device.
            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                new AsyncCallback(receiveCallback), state);
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void receiveCallback(IAsyncResult ar)
    {
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket client = state.workSocket;

            // Read data from the remote device.
            int bytesRead = client.EndReceive(ar);

            if (bytesRead <= 0) return; // No data...

            // Console.WriteLine("Ascii {0}", Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
            Console.WriteLine("Raw: {0}", BitConverter.ToString(state.buffer, 0, bytesRead));

            processMessage(new Response {Data = state.buffer,BytesLength = bytesRead} );

            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(receiveCallback), state);

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void processMessage(Response resp)
    {
       // Do something with the message here.. 
    }

However I want to abstract the IP stuff from the processing code and move the processMessage back up into my Class which uses the interface.. (I know I not explaining this well.. so let me re-try)

Set up event handler in my "class TcpConnection : IConnection"

Turn on event handling from AlarmPanel Class which the constructor looks like:

public AlarmPanel(IConnection connection, int Password)
    {
        _connection = connection;
        _Password = Password;
    }

which uses that interface (IConnection), and be able to say use the ProcessMessage method from the alarmPanel Class, so that I can then call the same method for when I get the serial event handling working..

Upvotes: 0

Views: 496

Answers (1)

smoksnes
smoksnes

Reputation: 10851

It sounds like you want to register an event on your interface IConnection, which AlarmPanel can subscribe to. This way you can let the IConnection implementation handle the logic for retrieving the message, but let AlarmPanel do what it wants with the recieved message.

public class AlarmPanel
{
    public AlarmPanel(IConnection connection, int Password)
    {
        _connection = connection;
        _Password = Password;
        // Bind event.
        _connection.MessageReceived += ProcessMessage;
    }

    private void ProcessMessage(object sender, MessageEventArgs e)
    {
        // Do your central processing here with e.Message.
    }
}

public interface IConnection
{
    event Action<object, MessageEventArgs> MessageRecieved;
}

public class TcpConnection : IConnection
{
    // Other code.

    private static void processMessage(Response resp)
    {
       // Do something with the message here..
       var eventArgs = new MessageEventArgs
       {
           Message = response
       };
       OnMessageReceived(eventArgs);
    }

    protected virtual void OnMessageReceived(MessageEventArgs e)
    {
        // Call subscribers.
        var handler = MessageRecieved;
        if (handler != null) handler(this, e);
    }
    public event Action<object, MessageEventArgs> MessageRecieved;
}

// Class for passing Response back to AlarmPanel.
public class MessageEventArgs : System.EventArgs
{
    Response Message { get; set; } // Consider using an interface for Response.
}

Upvotes: 1

Related Questions