Xamarin Forms App
I have two pages in my App: News and Announcements.
On these pages I want to display messages received from a rabbitmq Server.
I implemented a Service in Android that is executed after the login is completed. The communication between the Shared Code and the Android-Code is realized with Xamarin.MessagingCenter.
The Problem is that my rabbitmq Client currently doesn't receive any messages.
The Server is running on a VM and the App runs in an Emulator.
Code
Here is my Code
DataTransferTaskService in Android
[Service]
class DataTransferTaskService : Service
{
static User user = new User { Groups = new List<string>() { "Test","Test2" } };
CancellationTokenSource _cts;
public override IBinder OnBind(Intent intent)
{
return null;
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
// From shared code or in your PCL
_cts = new CancellationTokenSource();
PS();
return StartCommandResult.NotSticky;
}
void PS()
{
var factory = new ConnectionFactory() { HostName = "10.0.0.3", UserName = "test", Password = "test", Port = 5672 };
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.ExchangeDeclare(exchange: "Kastner", type: ExchangeType.Direct);
var queueName = channel.QueueDeclare().QueueName;
foreach (string g in user.Groups)
{
channel.QueueBind(queue: queueName,
exchange: "Kastner",
routingKey: g);
}
var consumer = new EventingBasicConsumer(channel);
System.Diagnostics.Debug.WriteLine("vor event");
consumer.Received += (model, ea) =>
{
var body = ea.Body.ToArray();
var message = Encoding.UTF8.GetString(body);
var obj = JObject.Parse(message);
News n;
Announcement a;
System.Diagnostics.Debug.WriteLine("vor if");
if (obj.Properties().Select(p => p.Name).FirstOrDefault() == "NewsId")
{
n = JsonConvert.DeserializeObject<News>(message);
MessagingCenter.Send<object, News>(this, "NewsMessage", n);
}
else
{
a = JsonConvert.DeserializeObject<Announcement>(message);
MessagingCenter.Send<object, Announcement>(this, "AnnouncementMessage", a);
}
};
channel.BasicConsume(queue: queueName,
autoAck: true,
consumer: consumer);
}
}
MainActivity.cs in Android
[Activity(Label = "DA_MessageBrokerApp", Icon = "@mipmap/icon", Theme = "@style/MainTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize )]
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(savedInstanceState);
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer: true);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
global::Xamarin.Forms.Forms.Init(this, savedInstanceState);
CrossMediaManager.Current.Init(this);
LoadApplication(new App());
WireUpDataTransferTask();
}
public override void OnRequestPermissionsResult(int requestCode, string[] permissions, [GeneratedEnum] Android.Content.PM.Permission[] grantResults)
{
Xamarin.Essentials.Platform.OnRequestPermissionsResult(requestCode, permissions, grantResults);
base.OnRequestPermissionsResult(requestCode, permissions, grantResults);
}
void WireUpDataTransferTask()
{
MessagingCenter.Subscribe<NewsViewModel>(this, "StartDataTransferMessage", (sender) =>
{
var intent = new Intent(this, typeof(DataTransferTaskService));
StartService(intent);
});
}
}
NewsViewModel in Shared Code
public class NewsViewModel : BaseViewModel
{
static User user = new User { Groups = new List<string>() { "Test","Test2" } };
private News _selectedItem;
public ObservableCollection<News> Items { get; }
public Command LoadItemsCommand { get; }
public Command AddItemCommand { get; }
public Command<News> ItemTapped { get; }
public NewsViewModel()
{
Title = "News";
Items = new ObservableCollection<News>();
MessagingCenter.Subscribe<object, News>(this, "NewsMessage", async (sender, arg) =>
{
await Task.Run(() =>DataStoreNews.AddItemAsync(arg));
await ExecuteLoadItemsCommand();
});
MessagingCenter.Send<NewsViewModel>(this, "StartDataTransferMessage");
LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
ItemTapped = new Command<News>(OnItemSelected);
}
void AddNewItem(News news)
{
if (!Items.Contains(news))
Items.Add(news);
}
async Task ExecuteLoadItemsCommand()
{
IsBusy = true;
try
{
Items.Clear();
var items = await DataStoreNews.GetItemsAsync(true);
foreach (var item in items)
{
Items.Add(item);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
SelectedItem = null;
}
public News SelectedItem
{
get => _selectedItem;
set
{
SetProperty(ref _selectedItem, value);
OnItemSelected(value);
}
}
async void OnItemSelected(News item)
{
if (item == null)
return;
// This will push the ItemDetailPage onto the navigation stack
await Shell.Current.GoToAsync($"{nameof(NewsDetailPage)}?{nameof(NewsDetailViewModel.NewsId)}={item.NewsId}");
}
}
BaseViewModel in Shared Code
public class BaseViewModel : INotifyPropertyChanged
{
public IDataStore<News> DataStoreNews => DependencyService.Get<IDataStore<News>>();
public IDataStore<Announcement> DataStoreMessage => DependencyService.Get<IDataStore<Announcement>>();
bool isBusy = false;
public bool IsBusy
{
get { return isBusy; }
set { SetProperty(ref isBusy, value); }
}
string title = string.Empty;
public string Title
{
get { return title; }
set { SetProperty(ref title, value); }
}
protected bool SetProperty<T>(ref T backingStore, T value,
[CallerMemberName] string propertyName = "",
Action onChanged = null)
{
if (EqualityComparer<T>.Default.Equals(backingStore, value))
return false;
backingStore = value;
onChanged?.Invoke();
OnPropertyChanged(propertyName);
return true;
}
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var changed = PropertyChanged;
if (changed == null)
return;
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Problem
In the PS() method in the Service Class is the Method where I execute the Code of the rabbitmq Client. But the event that the client receives a message is never raised. I already tried the connection with annother Test Console App and there I received messages. Did I do something wrong with the Service or why is this not working?
Edit: I removed the usings of connection
and channel
in the DataTransferTaskService
class, because I found out that these caused some problems, but it is still not working.