I am working on a personal project, based on the MyCoffeeApp designed by James Montemagno, but the API interactions like pull to refresh (which is linked to the get() httprequest) and clicking the Add button (which is linked to the POST httprequest), crash the app in the VS 2019 emulator and send the project into break mode, whenever they are used and only then.
I tried to look up my problem, but I got stuck...
This is what I get in output
[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.NullReferenceException: Object reference not set to an instance of an object. [mono-rt] at Android.Runtime.JNINativeWrapper._unhandled_exception (System.Exception e) [0x0000e] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:12 [mono-rt] at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V (_JniMarshal_PP_V callback, System.IntPtr jnienv, System.IntPtr klazz) [0x0001c] in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:23 [mono-rt] at (wrapper native-to-managed) Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(intptr,intptr)
Code in Startup.cs
:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyCoffeeApp.WebAPI
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyCoffeeApp.WebAPI", Version = "v1" });
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyCoffeeApp.WebAPI v1"));
}
else
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyCoffeeApp.WebAPI v1"));
app.UseHttpsRedirection();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Code in Program.cs
:
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyCoffeeApp.WebAPI
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "MyCoffeeApp.WebAPI", Version = "v1" });
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyCoffeeApp.WebAPI v1"));
}
else
{
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyCoffeeApp.WebAPI v1"));
app.UseHttpsRedirection();
}
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Code in controller:
using Microsoft.AspNetCore.Mvc;
using MyCoffeeApp.Shared.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyCoffeeApp.WebAPI.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CoffeeController : ControllerBase
{
public static List<Coffee> Coffee { get; } = new List<Coffee>();
// GET: api/Coffee
[HttpGet]
public IEnumerable<Coffee> Get()
{
return Coffee;
}
// GET api/Coffee/5
[HttpGet("{id}")]
public Coffee Get(int id)
{
return Coffee.FirstOrDefault(c => c.Id == id);
}
// POST api/Coffee
[HttpPost]
public void Post([FromBody] Coffee value)
{
Coffee.Add(value);
}
// PUT api/Coffee/5
[HttpPut("{id}")]
public void Put(int id, [FromBody] Coffee value)
{
var coffee = Coffee.FirstOrDefault(c => c.Id == id);
if (coffee == null)
return;
coffee = value;
}
// DELETE api/<CoffeeController>/5
[HttpDelete("{id}")]
public void Delete(int id)
{
var coffee = Coffee.FirstOrDefault(c => c.Id == id);
if (coffee == null)
return;
Coffee.Remove(coffee);
}
}
}
Code in Models/Coffee.cs
:
using SQLite;
namespace MyCoffeeApp.Shared.Models
{
public class Coffee
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Roaster { get; set; }
public string Name { get; set; }
public string Image { get; set; }
}
}
Code in InternetCoffeeService.cs
:
using MonkeyCache.FileStore;
using MyCoffeeApp.Shared.Models;
using Newtonsoft.Json;
using SQLite;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Essentials;
namespace MyCoffeeApp.Services
{
public static class InternetCoffeeService
{
//static string Baseurl = DeviceInfo.Platform == DevicePlatform.Android ?
// "" : "http://localhost:5000";
static string BaseUrl = "http://10.0.2.2:5000";
static HttpClient client;
static InternetCoffeeService()
{
client = new HttpClient
{
BaseAddress = new Uri(BaseUrl)
};
}
public static Task<IEnumerable<Coffee>> GetCoffee() =>
GetAsync<IEnumerable<Coffee>>("api/Coffee", "getcoffee");
static async Task<T> GetAsync<T>(string url, string key, int mins = 1, bool forceRefresh = false)
{
var json = string.Empty;
if (Connectivity.NetworkAccess != NetworkAccess.Internet)
json = Barrel.Current.Get<string>(key);
else if (!forceRefresh && !Barrel.Current.IsExpired(key))
json = Barrel.Current.Get<string>(key);
try
{
if (string.IsNullOrWhiteSpace(json))
{
json = await client.GetStringAsync(url);
Barrel.Current.Add(key, json, TimeSpan.FromMinutes(mins));
}
return JsonConvert.DeserializeObject<T>(json);
}
catch (Exception ex)
{
Debug.WriteLine($"Unable to get information from server {ex}");
throw ex;
}
}
static Random random = new Random();
public static async Task AddCoffee(string name, string roaster)
{
var image = "https://www.yesplz.coffee/app/uploads/2020/11/emptybag-min.png";
var coffee = new Coffee
{
Name = name,
Roaster = roaster,
Image = image,
Id = random.Next(0, 10000)
};
var json = JsonConvert.SerializeObject(coffee);
var content =
new StringContent(json, Encoding.UTF8, "application/json");
var response = await client.PostAsync("api/Coffee", content);
if(!response.IsSuccessStatusCode)
{
}
}
public static async Task RemoveCoffee(int id)
{
var response = await client.DeleteAsync($"api/Coffee/{id}");
if (!response.IsSuccessStatusCode)
{
}
}
}
}
Code in InternetCoffeeViewModel
:
using MvvmHelpers;
using MvvmHelpers.Commands;
using MyCoffeeApp.Services;
using MyCoffeeApp.Shared.Models;
using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;
using Command = MvvmHelpers.Commands.Command;
namespace MyCoffeeApp.ViewModels
{
public class InternetCoffeeViewModel : ViewModelBase
{
public ObservableRangeCollection<Coffee> Coffee { get; set; }
public AsyncCommand RefreshCommand { get; }
public AsyncCommand AddCommand { get; }
public AsyncCommand<Coffee> RemoveCommand { get; }
public InternetCoffeeViewModel()
{
Title = "Internet Coffee";
Coffee = new ObservableRangeCollection<Coffee>();
RefreshCommand = new AsyncCommand(Refresh);
AddCommand = new AsyncCommand(Add);
RemoveCommand = new AsyncCommand<Coffee>(Remove);
}
async Task Add()
{
var name = await App.Current.MainPage.DisplayPromptAsync("Name", "Name of coffee");
var roaster = await App.Current.MainPage.DisplayPromptAsync("Roaster", "Roaster of coffee");
await InternetCoffeeService.AddCoffee(name, roaster);
await Refresh();
}
async Task Remove(Coffee coffee)
{
await InternetCoffeeService<Coffee>.RemoveCoffee(coffee.Id);
await Refresh();
}
async Task Refresh()
{
IsBusy = true;
await Task.Delay(2000);
Coffee.Clear();
var coffees = await InternetCoffeeService.GetCoffee();
Coffee.AddRange(coffees);
IsBusy = false;
}
}
}
If someone can help me figure out what's wrong, I will appreciate it a lot.