Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
4.6k views
in Technique[技术] by (71.8m points)

c# - How to integrate a rabbitmq Client in a BackgroundService in a Xamarin Forms Android App?

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神解答

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...