Movart
Movart

Reputation: 151

Xamarin - Using httpClient in .Net Standard Library

I've created Xamarin project, and I added several .Net standard class libraries to it (one for each layer: data access, service layer etc.). Then, In ServiceLayer project, I implemented method, which fetch data from my Web API (external ASP Net Core project). When it comes to httpClient.GetAsync(), android app crash. What's more, when I cut this piece of code, and paste it in default xamarin .Net standard library, everything works. Any ideas?

Code is here:

HttpClient httpClient = new HttpClient();
var responseMessage = await httpClient.GetStringAsync(uri);

UPDATE:

In Viewmodel:

constructor(IServiceLayerService service){
        _ServiceLayerService = service;
        GetTestCommand = new DelegateCommand(async () => await GetTests());
        }     

        public async Task GetTests()
        {
            TestObservableCollection = new ObservableCollection<List<Test>>(await _ServiceLayerService.GetTestModels());
        }

Update 2: I've changed my async method call, in the way presented in first answer. Now, when I'm trying to execute code, app also crashes, but I'm receiving error messages:

07-05 14:39:04.518 F/        (25383): /Users/builder/jenkins/workspace/xamarin-android-d15-7/xamarin-android/external/mono/mono/mini/debugger-agent.c:4897: Could not execute the method because the containing type is not fully instantiated. assembly:<unknown assembly> type:<unknown type> member:(null) signature:<none>
07-05 14:39:04.518 F/libc    (25383): Fatal signal 6 (SIGABRT), code -6 in tid 25383 (com.companyname), pid 25383 (com.companyname)

Maybe I'm doing something wrong with Unity dependency injection, so here is registration of service layer classes in App.xaml.cs

 protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
            containerRegistry.RegisterForNavigation<NavigationPage>();
            containerRegistry.RegisterForNavigation<TestsListPage, TestsListViewModel>();
            containerRegistry.Register<IServiceLayerService, ServiceLayerService>();
}

Upvotes: 2

Views: 1383

Answers (1)

Nkosi
Nkosi

Reputation: 246998

The problem is with the async command delegate

GetTestCommand = new DelegateCommand(async () => await GetTests());

The command delegate results in an async void, which wont allow exceptions to be caught as they are considered fire and forget methods

Reference Async/Await - Best Practices in Asynchronous Programming

Create an event and handler to manage the async call

private event EventHandler gettingTests = delegate { };
private async void OnGettingTests(object sender, EventArgs args) {
    try {
        await GetTests();
    } catch (Exception ex) {
        //...handle exception
    }
}

Note that event handlers are the one exception to the rule that allows async void

Subscribe to the event in the constructor and raise the event in the command delegate

constructor (IServiceLayerService service) {
    _ServiceLayerService = service;
    this.gettingTests += OnGettingTests;
    GetTestCommand = new DelegateCommand(() => gettingTests(this, EventArgs.Empty));
} 

So now when the command is invoked, it will raise the event and the async handler can make async calls correctly.

Upvotes: 3

Related Questions