I've been searching for a way to send a local message within my app and found a tutorial from the Xamarin website on Broadcast Receivers here, more specifically at the bottom of the web page concerning LocalBroadcastManager. I followed the tutorial and read the page a few times but my BroadcastReceiver class still isn't receiving anything when I send a message. I've hit a lot of the questions concerning LocalBroadcastManager for java, but can't seem to figure out what's missing for C#.
This is the code that's triggering a sent message:
Intent intent = new Intent("dirty");
intent.PutExtra("dirtyAppCount", dirtyAppCount);
LocalBroadcastManager.GetInstance(Context).SendBroadcast(intent);
Here's where I'm registering my receiver in OnResume():
_dirtyMessageReceiver = new DirtyBroadcastReceiver();
RegisterReceiver(_dirtyMessageReceiver, new IntentFilter("dirty"));
Unregistering receiver in OnPause():
UnregisterReceiver(_dirtyMessageReceiver);
And here's my receiver class:
[BroadcastReceiver(Enabled = true, Exported = false)]
public class DirtyBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
int dirtyAppCount = intent.GetIntExtra("dirtyAppCount", 0);
OnMessageReceived?.Invoke(this, new MessageArgs(dirtyAppCount));
}
}
There are two issues with this code. First, you should use be registering the Receiver with the LocalBroadcastManager:
_dirtyMessageReceiver = new DirtyBroadcastReceiver();
RegisterReceiver(_dirtyMessageReceiver, new IntentFilter("dirty"));
Should be
_dirtyMessageReceiver = new DirtyBroadcastReceiver();
LocalBroadcastManager.GetInstance(this).RegisterReceiver(_dirtyMessageReceiver, new IntentFilter("dirty"));
Secondly, the Unregistering of the Receiver should be one against the LocalBroadcastManager as well:
UnregisterReceiver(_dirtyMessageReceiver);
becomes
LocalBroadcastManager.GetInstance(this).UnregisterReceiver(_dirtyMessageReceiver);
You need to add a broadcast receiver for these.For example, Set Android.Content.Intent to ActionTimeTick so that android os will broadcast message(an android intent) whenever time is changed.
[BroadcastReceiver(Enabled = true)]
[IntentFilter(new[] { Android.Content.Intent.ActionTimeTick })]
public class GridStartBroadcastReceiver : BroadcastReceiver
{
public static readonly string GRID_STARTED = "GRID_STARTED";
public override void OnReceive(Context context, Intent intent)
{
if (intent.Action == GRID_STARTED)
{
//your logic
}
}
}
you need to register the broadcast receiver first. Add these code to oncreate method to register broadcast receiver.
IntentFilter filter = new IntentFilter(GridStartBroadcastReceiver.GRID_STARTED);
filter.AddCategory(Intent.CategoryDefault);
_receiver = new GridStartBroadcastReceiver();
RegisterReceiver(_receiver, filter);
Next send the broadcast to the broadcast receiver.
//calling
Intent BroadcastIntent = new Intent(this, typeof(MainActivity.GridStartBroadcastReceiver));
BroadcastIntent.SetAction(MainActivity.GridStartBroadcastReceiver.GRID_STARTED);
BroadcastIntent.AddCategory(Intent.CategoryDefault);
SendBroadcast(BroadcastIntent);
Related
I'm writing an app which reads messages from rabbitmq. A message contains a user's name and a correlation ID. There is a message handler which performs some calculations based on the message's payload and writes logs as well. A log entry must contain a user's name and a correlation ID from the message.
So, for each message, a new instance of MessageProcessor is created and a new instance of ExecutionContext should be created as well.
I'm using Microsoft.DependencyInjection which comes with .net core and I can't achieve the desired behaviour.
I tried to use Replace method but it did not work.
MessageProcessor.cs
internal sealed class MessageProcessor
{
public MessageProcessor(ILogger logger)
{
}
public async Task Process(Message message)
{
// do something useful
this.logger.WriteInfo("Message has been processed");
}
}
Logger.cs
internal sealed class Logger
{
public Logger(ExecutionContext context)
{
//context contains UserName and CorrelationID
}
}
Is it a good idea to rebind ExecutionContext for each message? Are there better solutions?
I wouldn't recommend creating a new instance of MessageProcessor with every arrived message. It is better to use the one instance of the processor and just delegate messages:
//register your processor in DI container
services.AddSingleton<MessageProcessor>();
var consumer = new EventingBasicConsumer(Model);
consumer.Received += OnMessageReceived;
Model.BasicConsume(
queue: queueName,
autoAck: true,
consumer: consumer);
//...
private void OnMessageReceived(object sender, BasicDeliverEventArgs e)
{
var message = e.Body; //here's your message in bytes
//deserialize into your model
IFormatter formatter = new BinaryFormatter();
using (MemoryStream stream = new MemoryStream(obj.Body))
{
myMessage = (Message) formatter.Deserialize(stream);
}
//...
}
RabbitMQ operates with bytes, not with JSON/XML/...
Can you post your code of Model class and how the connection to Rabbit looks like?
I have problem with broadcast receiver in xamarin.android. Can't get it to work.
I have notification in my app working and I want to change some things in my app after I get notification (e.g. Toast message or change icon of a button) But it doesn't work. I don't know what am I doing wrong and I can't find solution because all the topics are Java related. I need something, event or broadcastreceiver to fire when user gets notification and then I want to do some stuff in my MainActivity.
So, this is the code.
BroadcastReceiver class:
[BroadcastReceiver(Enabled = true, Exported = false)]
public class MyMessageReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
bool messageReceived = intent.GetBooleanExtra("messageReceived", false);
}
}
OnMessageReceived method:
{
base.OnMessageReceived(message);
SendNotification(message.GetNotification().Body);
LocalBroadcastManager broadcaster = LocalBroadcastManager.GetInstance(this);
Intent intent = new Intent("message");
intent.PutExtra("messageReceived", true);
broadcaster.SendBroadcast(intent);
}
And OnResume and OnPause methods:
protected override void OnResume()
{
base.OnResume();
LocalBroadcastManager.GetInstance(this).RegisterReceiver(myReceiver, new IntentFilter("message"));
RegisterReceiver(myReceiver, new IntentFilter("message"));
}
protected override void OnPause()
{
base.OnPause();
LocalBroadcastManager.GetInstance(this).UnregisterReceiver(myReceiver);
}
I don't know how to receive that info for example in my OnCreate method in MainActivity? I tried with
messageReceived = Intent.GetBooleanExtra("messageReceived", false);
if (messageReceived)
{
Toast.MakeText(this, "new notification", ToastLength.Long).Show();
}
But that doesn't work, messageReceived is null.
I know it is a bit too late but better late than never :
After analysing the firebase messaging I have done a suitable workaround for this purpose :
When your application is in the background the handle intent method is called by default on receiving push notification :
public override void HandleIntent(Intent p0)
{
base.HandleIntent(intent);
//Your code to know that you received a notification (backgrounnd)
// Use shared preference for this
}
Don't know how to use shared preferences check this.
For more information on how handle intent works check my answer out here.
When the application is in the foreground you can simply use on message received method as such :
public override void OnMessageReceived(Context context, Intent intent)
{
//Your code to know that you received a notification (backgrounnd)
// Use shared preference for this
}
Then, wherever you need to use this you can get a flag or count or whatever using shared preferences.
In case of any queries revert!
Considering I have an AdView in a Xamarin.Android project:
private AdView _bannerAd;
I usually initialize it like this:
_bannerAd = new AdView(this)
{
AdSize = AdSize.SmartBanner,
AdUnitId = adUnitId,
Visibility = ViewStates.Visible
};
Then, when I load the banner, I have to build the request. In this case I'd like to add an extra bundle, but when I have to call requestbuilder.AddCustomEventExtrasBundle, I don't know what to put as the first parameter.
var requestbuilder = new AdRequest.Builder();
var extras = new Bundle();
extras.PutString("npa", "1");
requestbuilder.AddCustomEventExtrasBundle(***, extras);
_bannerAd.LoadAd(requestbuilder.Build())
By reading the method definition, I really don't understand what could be an "adapter class".
[Register("addCustomEventExtrasBundle", "(Ljava/lang/Class;Landroid/os/Bundle;)Lcom/google/android/gms/ads/AdRequest$Builder;", "")]
public Builder AddCustomEventExtrasBundle(Class adapterClass, Bundle customEventExtras);
You need to pass the Java Class (via Java.Lang.Class.FromType) of your custom event (ICustomEventBanner).
In my case, I have one called SushiHangoverTextEventBanner that is registered with AdMob.
You need to implement ICustomEventBanner, assumably this is a stand alone object (in my case it is) as AdMob will instance it, inherit it from Java.Lang.Object so Xamarin will create the ACW (JNI/Java wrapper) for it.
public class SushiHangoverTextEventBanner : Java.Lang.Object, ICustomEventBanner
{
SushiHangoverTextAdView customAdView;
public void OnDestroy()
{
customAdView?.Dispose();
}
public void OnPause()
{
~~~
}
public void OnResume()
{
~~~
}
public void RequestBannerAd(Context context, ICustomEventBannerListener listener, string serverParameter, AdSize size, IMediationAdRequest mediationAdRequest, Bundle customEventExtras)
{
customAdView = new SushiHangoverTextAdView(context);
~~~
}
}
I also have a custom ad (SushiHangoverAdView based on a TextView) that is used within that ICustomEventBanner implementation.
Once you register it and implement the AdMob callbacks, you can just pass it to your AdRequest.Builder:
using (var requestbuilder = new AdRequest.Builder())
{
var extras = new Bundle();
extras.PutString("npa", "1");
requestbuilder.AddCustomEventExtrasBundle(Java.Lang.Class.FromType(typeof(SushiHangoverTextEventBanner)), extras);
}
I help recommend going through the Admob custom event example:
https://developers.google.com/admob/android/custom-events
It is expecting a class that extends from CustomEvent, per the Documentation
public AdRequest.Builder addCustomEventExtrasBundle (Class<? extends
CustomEvent> adapterClass, Bundle customEventExtras)
Here is a great tutorial on getting started with custom events, directly from Google, where they go over using the CustomEventBanner. It is in Java, but should be easy enough to port to C#
I have a Topshelf windows service that acts as a TCP server. Inside this service, I also have a self-hosted (OWIN) WebAPI.
My goal is to somehow allow the WebAPI to communicate with the TCP server that's contained and running in the same service. Naturally I could simply use something like a "trigger" file or a shared DB that could be polled frequently, though I'd like to know of any more optimal/native ways to achieve this.
To get a better idea of the project, think of a single page application consuming my API and making certain calls with arbitrary string parameters. This data should then be passed to clients (C++ console apps using winsock) that are connected to the running TCP server.
The following Container is instantiated and passed to the Topshelf HostConfigurator
class ContainerService
{
private APIService _apiService;
private EngineService _engineService;
protected IDisposable WebAppHolder { get; set; }
public bool Start(HostControl hostControl)
{
var host = hostControl;
_apiService = new APIService();
_engineService = new EngineService();
// Initialize API service
if (WebAppHolder == null)
{
WebAppHolder = _apiService.Initialize();
}
// Initialize Engine service
_engineService.Initialize();
return true;
}
public bool Stop(HostControl hostControl)
{
// Stop API service
if (WebAppHolder != null)
{
WebAppHolder.Dispose();
WebAppHolder = null;
}
// Stop Engine service
_engineService.Stop();
return true;
}
}
Standard Topshelf stuff in program entry point (as mentioned above):
HostFactory.Run(hostConfigurator =>
{
hostConfigurator.Service<ContainerService>(containerService =>
{
containerService.WhenStarted((service, control) => service.Start(control));
containerService.WhenStopped((service, control) => service.Stop(control));
});
hostConfigurator.RunAsLocalSystem();
hostConfigurator.SetServiceName("Educe Service Host");
hostConfigurator.SetDisplayName("Communication Service");
hostConfigurator.SetDescription("Responsible for API and Engine services");
});
TCP Server:
public void Initialize()
{
_serverListener = new TcpListener(new IPEndPoint(hostAddress, (int)port));
_serverListener.Start();
_threadDoBeginAcceptTcpClient = new Thread(() => DoBeginAcceptTcpClient(_serverListener));
_threadDoBeginAcceptTcpClient.Start();
}
...
public void DoBeginAcceptTcpClient(TcpListener listener)
{
while(!_breakThread)
{
// Set the event to nonsignaled state.
TcpClientConnected.Reset();
// Start to listen for connections from a client.
Console.WriteLine("Waiting for a connection...");
// Accept the connection.
listener.BeginAcceptTcpClient(DoAcceptTcpClientCallback, listener);
// Wait until a connection is made and processed before continuing.
TcpClientConnected.WaitOne();
}
}
// Process the client connection.
public void DoAcceptTcpClientCallback(IAsyncResult ar)
{
// Get the listener that handles the client request.
TcpListener listener = (TcpListener)ar.AsyncState;
// End the operation and display the received data on the console.
Console.WriteLine("Client connection completed");
Clients.Add(listener.EndAcceptTcpClient(ar));
// Signal the calling thread to continue.
TcpClientConnected.Set();
}
WebAPI Controller:
public class ValuesController : ApiController
{
// GET api/values/5
public string Get(int id)
{
return $"Foo: {id}";
}
}
As mentioned earlier, what I seek is "communication" between the WebAPI and the windows service. How can I pass the "id" parameter from the WebAPI call to the _engineService object in my windows service? Perhaps something similar to WPF's MVVM Light Messenger? The idea is that it would then be parsed and sent to the appropriate TcpClient that is stored in the Clients List.
Any advice on how to achieve this will be appreciated. Please feel free to ask for clarification/more code.
Did you find any answer to your issue yet ?
I don't quite understand what you try to achieve looking for a communication between the two of them ? Do you want to somehow rely on TCP/IP to relay this id or in-memory ?
Potentially, you could consider a Mediator pattern and use this kind of library that seems quite useful in the case I understood : https://github.com/jbogard/MediatR
In a simpler approach, I would rely on events to achieve what you are trying to do, which is having a reactive communication from the HTTP request to the c++ users.
Did I understand you needs ? I am quite curious about the solution
I'm assuming you are trying to take an HTTP GET request's ID parameter and send it to TCP clients who are connected to the EngineService. If your EngineService is initialized before your ApiService, I think this is a question of how to get a handle to the one-and-only EngineService instance from within an ApiService's controller instances.
If I'm following you, you could make the EngineService a public static property of your ContainerService and reference it as ContainerService.EngineService from the controller (or anywhere in the app for that matter) or better register your EngineService as a singleton in a DI container an inject it into the ApiService.
Solution (calls to WebAPI trigger EngineService)
I now use RabbitMQ/EasyNetQ to achieve communication between the WebApi and the EngineService object containing my TCP clients.
I have incidentally split them into two separate Projects/Topshelf services now.
The following is the new "communication" component and it is instantiated in the EngineService constructor.
public class Communication
{
private readonly Logger _logger;
private readonly IBus _bus;
public delegate void ReceivedEventHandler(string data);
public event ReceivedEventHandler Received;
protected virtual void OnReceive(string data)
{
Received?.Invoke(data);
}
public Communication()
{
_logger = new Logger();
_bus = RabbitHutch.CreateBus("host=localhost", reg => reg.Register<IEasyNetQLogger>(log => _logger));
SubscribeAllQueues();
}
private void SubscribeAllQueues()
{
_bus.Receive<Message>("pipeline", message =>
{
OnReceive(message.Body);
});
}
public void SubscribeQueue(string queueName)
{
_bus.Receive<Message>(queueName, message =>
{
OnReceive(message.Body);
});
}
}
An event handler is then added.
This means that as soon as a message arrives to the bus, the data will be relayed to the event handler which will subsequently relay it to the first connected TCP client in the list.
public void Handler(string data)
{
//Console.WriteLine(data);
_clients[0].Client.Send(Encoding.UTF8.GetBytes(data));
}
...
_comPipe.Received += Handler;
And finally on the WebApi's controller:
public string Get(int id)
{
ServiceCom.SendMessage("ID: " + id);
return "value";
}
ServiceCom class. Allows sending a string message on the bus.
public static class ServiceCom
{
public static void SendMessage(string messageBody)
{
var messageBus = RabbitHutch.CreateBus("host=localhost");
messageBus.Send("pipeline", new Message { Body = messageBody });
}
}
Now that this is done, I am now looking to implement a way for the connected TCP clients to trigger updates/events in an additional SPA project that will act as a Portal / Client Management App.
My approach will probably make use of KnockOut.js and SignalR to achieve dynamic Views where TCP client events are displayed immediately and similarly actions on to WebAPI will trigger events in the TCP clients. I know it sounds like a bizarre combination of processes but it is all according to plan and working out as expected :)
I am using Microsoft.WebSockets and facing problems in sending messages to perticular client. Currently I have usied WebSocketCollection object and added every new client on it. It allows to broadcast messages to all client. But I want to send message to specific single one i.e. Signalr provides to send messages from server to specific client i.e.
Hub.Clients.Client(connectionId).yourClientSideMethod()
I want to achieve the same using Microsoft.WebSockets. I have searched alot about it on internet but couldn't be able to find any solution. Please help me in it.
My code is as follows:
class ChatWebSocketHandler : WebSocketHandler
{
private static WebSocketCollection _chatClients = new WebSocketCollection();
private string _username;
public ChatWebSocketHandler(string username)
{
_username = username;
}
public override void OnOpen()
{
_chatClients.Add(this);
}
public override void OnMessage(string message)
{
//for broadcasting messages to all clients
//_chatClients.Broadcast(this._username + " : " + message);
//for sending message to individual client i want something like
_chatClients.Single(x=>x._username.Equals("name")).Send(message);
}
public override void OnClose()
{
// Free resources, close connections, etc.
base.OnClose();
}
}
Try This
clients.SingleOrDefault(r => ((SocketHandler)r).userName == "udara").Send("Hello udara");