Accessing UI thread in Xamarin Android - c#

My application sends and receives TCP strings. One of those strings is to make an object visible depending on the string. My current code gives System.NullReferenceException has been thrown Object reference not set to an instance of an object.
I can't find the right method to access, I guess as RunOnUI doesn't seem to access this right.
My current code:
Listener class: (Snippet of the full class, I can post more if needed).
public void ReadCallback(IAsyncResult ar)
{
MainActivity ma = new MainActivity();
String content = string.Empty;
StateObject so = (StateObject)ar.AsyncState;
Socket handle = so.workSocket;
int bytesRead = handle.EndReceive(ar);
if (bytesRead > 0)
{
so.sb.Append(System.Text.Encoding.ASCII.GetString(so.buffer, 0, bytesRead));
content = so.sb.ToString();
}
if (content.IndexOf("0") > -1)
{
ma.RunOnUiThread(() =>
{
//This is where the received data is passed
ma.SortData(content);
});
Send(handle, content);
}
else
{
handle.BeginReceive(so.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), so);
}
}
And the code for SortData:
public void SortData(string data)
{
if(data == "0")
{
txtmsg.Visibility = ViewStates.Invisible;
}
} //This is the only code that's called, the txtmsg.Visibility part is the error producer once called.

You have to pass the Context to your class in a constructor
so you would add a constructor to your class like :
MainActivity mContext;
public YourClass(MainActivity context) {
this.mContext = context;
}
and then call the method from your class like :
mContext.RunOnUiThread(() =>
{
//This is where the received data is passed
mContext.SortData(content);
});

Related

Propagate data from many UDP sockets to TPL Dataflow using async/await

I have to listen to several udp sockets and receive multicast datagrams. After receiving from some socket, data has to be sent to the TransformBlock. I don't want to copy received data for each received packet, so data buffer is sent to the TransformBlock by reference. And that's why each particular socket has to wait for the TransformBlock to finish processing before it can begin reading to it's buffer again.
I used code from this article for async operations with sockets.
Also I need an ability to add or delete sockets which to listen during the program execution.
My multicast listener class:
using ChannelWithDecoder = Tuple<FastChannel, TransformBlock<SocketAsyncEventArgs, List<Message>>>;
class MulticastReceiveManager
{
const int MaxPacketSize = 1400;
readonly ConcurrentDictionary<int, SocketReadData> socketDataByPort = new ConcurrentDictionary<int, SocketReadData>();
public MulticastReceiveManager(IEnumerable<ChannelWithDecoder> channelsWithDecoders)
{
foreach (ChannelWithDecoder tuple in channelsWithDecoders) AddChannel(tuple.Item1, tuple.Item2);
}
static Socket CreateSocket(FastChannel channel)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
var end = new IPEndPoint(IPAddress.Any, channel.Port);
socket.Bind(end);
//подписываемся на source specific multicast
var membershipAddresses = new byte[12]; // 3 IPs * 4 bytes (IPv4)
IPAddress mcastGroup = IPAddress.Parse(channel.IP);
IPAddress mcastSource = IPAddress.Parse(channel.SourceIP);
Buffer.BlockCopy(mcastGroup.GetAddressBytes(), 0, membershipAddresses, 0, 4);
Buffer.BlockCopy(mcastSource.GetAddressBytes(), 0, membershipAddresses, 4, 4);
Buffer.BlockCopy(IPAddress.Any.GetAddressBytes(), 0, membershipAddresses, 8, 4);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddSourceMembership, membershipAddresses);
return socket;
}
public void AddChannel(FastChannel channel, TransformBlock<SocketAsyncEventArgs, List<Message>> decoderTransformBlock)
{
var args = new SocketAsyncEventArgs();
args.SetBuffer(new byte[MaxPacketSize], 0, MaxPacketSize);
var socketAwaitable = new ReceiveSocketAwaitable(args);
Socket socket = CreateSocket(channel);
var socketReadData = new SocketReadData(socket, socketAwaitable, decoderTransformBlock);
if (!socketDataByPort.TryAdd(channel.Port, socketReadData))
throw new ArgumentException("Channel with port number = " + channel.Port + " already exists in dictionary. IP = " + channel.IP);
}
public void DeleteChannel(FastChannel channel)
{
SocketReadData socketReadData;
if (!socketDataByPort.TryRemove(channel.Port, out socketReadData))
throw new ArgumentException("Channel with port number = " + channel.Port + " could not be removed from dictionary. IP = " + channel.IP);
}
public async Task StartListen(CancellationToken token)
{
SocketReadData socketReadData = socketDataByPort.Values.First();
while (!token.IsCancellationRequested)
{
await socketReadData.Socket.ReceiveAsync(socketReadData.Awaitable);
SocketAsyncEventArgs args = socketReadData.Awaitable.EventArgs;
if (args.BytesTransferred > 0) await socketReadData.DecoderTransformBlock.SendAsync(args, token);
}
}
}
Socket data:
class SocketReadData
{
public Socket Socket { get; }
public ReceiveSocketAwaitable Awaitable { get; }
public TransformBlock<SocketAsyncEventArgs, List<Message>> DecoderTransformBlock { get; }
public SocketReadData(Socket socket, ReceiveSocketAwaitable awaitable, TransformBlock<SocketAsyncEventArgs, List<Message>> decoderTransformBlock)
{
Socket = socket;
Awaitable = awaitable;
DecoderTransformBlock = decoderTransformBlock;
}
}
And just in case, the code from the article for socket awaitable:
class ReceiveSocketAwaitable : INotifyCompletion
{
static readonly Action Sentinel = () => { };
Action mContinuation;
public bool WasCompleted { get; set; }
public SocketAsyncEventArgs EventArgs { get; }
public bool IsCompleted => WasCompleted;
public ReceiveSocketAwaitable(SocketAsyncEventArgs eventArgs)
{
Contract.Requires<ArgumentNullException>(eventArgs != null, "eventArgs can't be null");
EventArgs = eventArgs;
eventArgs.Completed += delegate
{
Action prev = mContinuation ?? Interlocked.CompareExchange(ref mContinuation, Sentinel, null);
prev?.Invoke();
};
}
public void OnCompleted(Action continuation)
{
if (mContinuation == Sentinel || Interlocked.CompareExchange(ref mContinuation, continuation, null) == Sentinel)
{
Task.Run(continuation);
}
}
public void Reset()
{
WasCompleted = false;
mContinuation = null;
}
public ReceiveSocketAwaitable GetAwaiter()
{
return this;
}
public void GetResult()
{
if (EventArgs.SocketError != SocketError.Success) throw new SocketException((int)EventArgs.SocketError);
//return EventArgs.BytesTransferred;
}
}
And extensions:
static class SocketExtensions
{
public static ReceiveSocketAwaitable ReceiveAsync(this Socket socket, ReceiveSocketAwaitable awaitable)
{
awaitable.Reset();
if (!socket.ReceiveAsync(awaitable.EventArgs)) awaitable.WasCompleted = true;
return awaitable;
}
public static ReceiveSocketAwaitable SendAsync(this Socket socket, ReceiveSocketAwaitable awaitable)
{
awaitable.Reset();
if (!socket.SendAsync(awaitable.EventArgs)) awaitable.WasCompleted = true;
return awaitable;
}
}
As you can see, this code achieves my goal for a single socket. In a loop it awaits for data and then await for transformblock to accept the packet. And only after that it can read data from a socket to the buffer again.
So the question is: how can i achieve this behavior for many sockets using async/await pattern, without creating threads and copying data for each packet?

How to properly separate packets using Sockets stream? C#

I'm building a server / client application and I'm looking through options for separating packets. I've read that the most proper one would be creating a header that contains information on how big the payload is and then read until it ends.
How does that programmatically works?
Also separating those by using "\n" newline. A proper example would be nice.
I'm async receiving data this way:
private void AsyncReceive(IAsyncResult result)
{
int bytesTransfered;
try
{
bytesTransfered = _handle.EndReceive(result);
if(bytesTransfered <= 0)
{
throw new Exception("No bytes transfered");
}
}
catch(NullReferenceException)
{
return;
}
catch(ObjectDisposedException)
{
return;
}
catch(Exception)
{
return;
}
byte[] received = new byte[bytesTransfered];
try
{
Array.Copy(_readBuffer, received, received.Length);
}
catch(Exception)
{
Disconnect();
return;
}
// How should I process the received data now?
try
{
_handle.BeginReceive(_readBuffer, 0, _readBuffer.Length, SocketFlags.None, AsyncReceive, null);
}
catch(ObjectDisposedException)
{
return;
}
catch(Exception)
{
}
}
First you need to distinguish between different types of messages. You can use single byte for that, which will allow for up to 255 different message types. Make an enum for that, and an attribute to mark your messages (see below):
enum MessageType : byte {
FirstMessage,
SecondMessage
}
class MessageAttribute : Attribute {
public MessageAttribute(MessageType type) {
Type = type;
}
public MessageType Type { get; private set; }
}
Second, you need compact serializer for your messages. One good option is protobuf - it it's very compact (does not serialize property names, only values and so on) while still easy to use.
[Message(MessageType.FirstMessage)]
[ProtoContract]
class MyFirstMessage {
[ProtoMember(1)]
public string Value { get; set; }
[ProtoMember(2)]
public int AnotherValue { get; set; }
}
[Message(MessageType.SecondMessage)]
[ProtoContract]
class MySecondMessage {
[ProtoMember(1)]
public decimal Stuff { get; set; }
}
Third you need to know the length of a message, as caller says you. Use 2 or 4 bytes for that (size of Int16 and Int32 types respectively).
So our format would be: 1 byte - message type. 2-5 bytes - message size, 5-5+size bytes - protobuf serialized message. Then read your stream in three steps, as defined below:
class MessageReader {
static readonly Dictionary<byte, Type> _typesMap = new Dictionary<byte, Type>();
static MessageReader() {
// initialize your map
// this is executed only once per lifetime of your app
foreach (var type in Assembly.GetExecutingAssembly().GetTypes().Where(c => c.GetCustomAttribute<MessageAttribute>() != null)) {
var message = type.GetCustomAttribute<MessageAttribute>();
_typesMap.Add((byte)message.Type, type);
}
}
public async Task<object> Read(Stream stream) {
// this is your network or any other stream you have
// read first byte - that is message type
var firstBuf = new byte[1];
if (await stream.ReadAsync(firstBuf, 0, 1) != 1) {
// failed to read - end of stream
return null;
}
var type = firstBuf[0];
if (!_typesMap.ContainsKey(type)) {
// unknown message, handle somehow
return null;
}
// read next 4 bytes - length of a message
var lengthBuf = new byte[4];
if (await stream.ReadAsync(lengthBuf, 0, 4) != 4) {
// read less than expected - EOF
return null;
}
var length = BitConverter.ToInt32(lengthBuf, 0);
// check if length is not too big here! or use 2 bytes for length if your messages allow that
if (length > 1*1024*1024) {
// for example - adjust to your needs
return null;
}
var messageBuf = new byte[length];
if (await stream.ReadAsync(messageBuf, 0, length) != length) {
// didn't read full message - EOF
return null;
}
try {
return ProtoBuf.Serializer.NonGeneric.Deserialize(_typesMap[type], new MemoryStream(messageBuf));
}
catch {
// handle invalid message somehow
return null;
}
}
}
After you read one message from stream - continue in the same way to read next message. Read calls will block until new data arrives. If there is any violation of protocol - drop connection.
Have you not considered using a TCPClient and TCPListener, and then a NetworkStream? Sockets are pretty low level and probably not needed in the majority of cases.
See this post:
How reading messages from server?(TCP)
Also, do not catch exceptions that you cannot recover from, unless you log and rethrow them. This will cause very hard to debug behaviors when exceptions get silently swallowed up.

how to serialize a custom object including Tcpclient (for chatroom userlist)

I've created a simple chatroom program .
Basic message sending and receiving works well on the client, and server,too.
But I want to broadcast the connection list to all users when any user leave.
I use a thread to handle this task.
private void monitorProc()
{
while(true)
{
try
{
int bytereads = 0;
byte[] buffer = new byte[4096];
bytereads = clientStream.Read(buffer, 0, buffer.Length);
updateMonitor(encoder.GetString(buffer), monitor);
}
catch
{
}
}
}
And I use this thread like this ...
monitorThread = new Thread(new ThreadStart(monitorProc));
monitorThread.Start();
And server is ...
private void broadcast(string message)
{
foreach (User user in userlist)
{
NetworkStream clientStream;
clientStream = user.Userclient.GetStream();
clientStream.Write(encoder.GetBytes(message), 0, 4096);
clientStream.Flush();
}
}
When server received message from client , it call this function , and then all user will
In that way , client will put the message when receive message from server.
I define a User class . It contain the following info...
[Serializable]
public class User
{
public enum stat
{
ALIVE,
DEAD
}
private string username;
private IPEndPoint userEP;
private TcpClient userclient;
private stat userstat;
public string Username { get; set; }
public IPEndPoint UserEP { get { return userEP; } }
public TcpClient Userclient { get { return userclient; } }
public stat Userstat { get; set; }
public User(TcpClient _userclient)
{
userclient = _userclient;
userstat = stat.ALIVE;
}
}
I use a list to store every user in server .
Question1: how to send the list to every client ?
(I know that serialization can help . But an error occurred when I use the following code to serialize the list...
foreach (User user in userlist) {
Stream statBroadcast = user.Userclient.GetStream();
var bin = new BinaryFormatter();
bin.Serialize(statBroadcast , userlist);
connlist.Items.Add(user.Username);
}
It said that I didn't mark TcpClient as serializable.
Question 2: If I can send custom object to client . How to send connection list and message at the same time ?
(If I define a function in client called "updateList" and it receive the data through stream . How to distinct from the data (whether message of connectionlist))

How to send multiple images from android to a WCF Rest Service as a stream to write to a network drive?

After much googling and searching, I managed to send an image using multiparsers from android to my WCF service, but ideally, I'd like to send several images at once, instead of calling the method over and over again, since it'd take a lot longer, and add a bunch more overhead.
This is my current code
Android (Taken from code found on here somewhere):
public static String postFile(Bitmap bitmap, String urlString) throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(urlString);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
ByteArrayOutputStream bao = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 30, bao);
byte[] data = bao.toByteArray();
//filename
String fileName = String.format("File_%d.png",new Date().getTime());
ByteArrayBody bab = new ByteArrayBody(data, fileName);
builder.addPart("image", bab);
final HttpEntity yourEntity = builder.build();
class ProgressiveEntity implements HttpEntity {
#Override
public void consumeContent() throws IOException {
yourEntity.consumeContent();
}
#Override
public InputStream getContent() throws IOException,
IllegalStateException {
return yourEntity.getContent();
}
#Override
public Header getContentEncoding() {
return yourEntity.getContentEncoding();
}
#Override
public long getContentLength() {
return yourEntity.getContentLength();
}
#Override
public Header getContentType() {
return yourEntity.getContentType();
}
#Override
public boolean isChunked() {
return yourEntity.isChunked();
}
#Override
public boolean isRepeatable() {
return yourEntity.isRepeatable();
}
#Override
public boolean isStreaming() {
return yourEntity.isStreaming();
} // CONSIDER put a _real_ delegator into here!
#Override
public void writeTo(OutputStream outstream) throws IOException {
class ProxyOutputStream extends FilterOutputStream {
/**
* #author Stephen Colebourne
*/
public ProxyOutputStream(OutputStream proxy) {
super(proxy);
}
public void write(int idx) throws IOException {
out.write(idx);
}
public void write(byte[] bts) throws IOException {
out.write(bts);
}
public void write(byte[] bts, int st, int end) throws IOException {
out.write(bts, st, end);
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
} // CONSIDER import this class (and risk more Jar File Hell)
class ProgressiveOutputStream extends ProxyOutputStream {
public ProgressiveOutputStream(OutputStream proxy) {
super(proxy);
}
public void write(byte[] bts, int st, int end) throws IOException {
// FIXME Put your progress bar stuff here!
out.write(bts, st, end);
}
}
yourEntity.writeTo(new ProgressiveOutputStream(outstream));
}
};
ProgressiveEntity myEntity = new ProgressiveEntity();
post.setEntity(myEntity);
HttpResponse response = client.execute(post);
return getContent(response);
}
public static String getContent(HttpResponse response) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String body = "";
String content = "";
while ((body = rd.readLine()) != null)
{
content += body + "\n";
}
return content.trim();
}
C# WCF Service method to take it
[WebInvoke(UriTemplate = "UploadPicture/{filename}", Method = "POST", BodyStyle = WebMessageBodyStyle.Bare, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
public String UploadPicture(string filename, Stream fileStream)
{
WriteLog("Uploading picture...");
try
{
MultipartParser parser = new MultipartParser(fileStream);
if (parser.Success)
{
string fileName = parser.Filename;
string contentType = parser.ContentType;
byte[] fileContent = parser.FileContents;
FileStream fileToupload = new FileStream("\\\\OHS-SUN\\Tracker\\robbie\\" + filename, FileMode.Create);
fileToupload.Write(fileContent, 0, fileContent.Length);
fileToupload.Close();
fileToupload.Dispose();
fileStream.Close();
return "Success !!!";
}
else
{
return "Exception!!!";
}
}
catch (Exception ex)
{
WriteLog("Uploading picture exception: " + ex.Message);
}
return "Picture uploaded!";
}
I'd like to go from sending one image, to sending several, each with 2 text attributes; the filename, and the project number they're associated with. Essentially, both is what I need it for. At the moment, I'm just trying to do put another addPart on to the android bit, but then I don't know how to add metadata to that and I wouldn't know how to parse it based on the name. I'm fine with using any third party libraries, the one I'm using on C# at the moment is already one.
Thanks a lot!
Instead of sending multiple images in one thing, I just stuck it in an asynchronous class and sent them concurrently with a max of 10 at a time until all the images are sent in that particular session. Seems to work fine, the implementation's the same, so I've not had to change any of that, which is good. If anyone would like me to post the code I did to do that, I'd be happy to. It's just small snippets here and there added to the above code, though.
Well, the main bit I added was:
public static class FileUploader extends AsyncTask<UploadFile , Void , String> implements Future<String>
{
#Override
protected void onPreExecute() {
filesUploading ++;
}
#Override
protected String doInBackground(UploadFile... uploadFile)
{
try
{
return postFile(uploadFile[0].file, uploadFile[0].projectNo, uploadFile[0].filename);
} catch (Exception e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
filesUploading --;
}
#Override
public boolean isDone() {
return AsyncTask.Status.FINISHED == getStatus();
}
}
This allows me to send each image separately, and handle them separately.

C# TCP Sending Generic Objects

Ok so I'm working on a simple data entry software for work, using a 3-tier architecture. What I'm doing is basically using a common dll file to store classes with fields that are filled out when a request to the server is initialized. I have various user controls set up to take care of different ui forms, this works just fine if I open a connection and send the object directly from the form itself, but that creates a lot of redundant code. So I thought, lets make a MasterControl and create a public Connect_To_Server method to send objects over and then process the information sent back. Only problem is it keeps freezing my server.
Here is the code for my MasterControl:
public void Connect_To_Server(object obj)
{
using (TcpClient tcpClient = new TcpClient())
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("10.20.51.251"), 57657);
try
{
tcpClient.Connect(endPoint);
NetworkStream clientStream = tcpClient.GetStream();
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(clientStream, obj);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + " - " + ex.StackTrace);
}
}
}
Of course it's going to be a bit more complex later on but just for testing I've made it simple. Then from one of my ControlForms I create an object from one of the classes listed in the Common.dll, assign it it's values and then pass it to the Connect_To_Server method.
For instance a couple classes from my Common.dll
[Serializable]
public class Switch_Request // Switch class contains an integer describing a boolean request
{
public int switchID { get; set; }
}
[Serializable]
public class Send_String_List // Returns a list of strings
{
public int switchID { get; set; }
public List<string> stringsList { get; set; }
}
On my Server's side:
private void bt_StartServer_Click(object sender, EventArgs e) // Starts the server listening for clients
{
Set_String("System: Starting Services.");
tm_ActiveTime.Start();
serverListener = new TcpListener(IPAddress.Any, port);
serverThread = new Thread(new ThreadStart(Listen_For_Clients));
serverThread.Start();
}
private void Listen_For_Clients() // Listens for incoming client connections then redirects
{
serverListener.Start();
Set_String("System: Listening for connections...");
while (true)
{
tcpClient = serverListener.AcceptTcpClient();
clientThread = new Thread(new ParameterizedThreadStart(Handle_Client_Communication));
clientThread.Start(tcpClient);
}
}
private void Handle_Client_Communication(object client) // Handles incoming client communications
{
TcpClient tempClient = (TcpClient)client;
clientStream = tempClient.GetStream();
object sentObjet = formatter.Deserialize(clientStream);
Type objectType = sentObjet.GetType();
else if(objectType == typeof(Switch_Request)) // Handle - Switch Request
{
Switch_Request switchRequest = (Switch_Request)sentObjet;
object obj = new object();
if (switchRequest.switchID == 1)
{
}
else if (switchRequest.switchID == 2)
{
}
else if (switchRequest.switchID == 3)
{
}
else if (switchRequest.switchID == 4)
{
}
else if (switchRequest.switchID == 5)
{
}
else if (switchRequest.switchID == 6)
{
Send_String_List sendStringList = new Send_String_List();
sendStringList.switchID = 6;
sendStringList.stringsList = Get_Users();
obj = sendStringList;
}
else if (switchRequest.switchID == 7)
{
}
else if (switchRequest.switchID == 8)
{
}
else if (switchRequest.switchID == 9)
{
}
else if (switchRequest.switchID == 10)
{
}
formatter.Serialize(clientStream, obj);
Now I know that the object is being sent and received on the other end, as I set a little text display to popup when the object arrives on the other end, and it displays the correct object and it's type just before the server freezes. I'm just not sure why it keeps seizing up....

Categories

Resources