Xamarin Forms and Asp.Net Web Api - c#

I have been following a youtube tutorial on connecting my a xamarin forms app to an asp.net web api. Unfortunately my Listview is not getting populated by data from the api.
The Xamarin forms app has the following Files:
RestClient.cs
public class RestClient<T> {
private const string WebServiceUrl = "http://localhost:49864/api/Oppotunities/";
public async Task<List<T>> GetAsync()
{
var httpClient = new HttpClient();
var json = await httpClient.GetStringAsync(WebServiceUrl);
var OppotunityList = JsonConvert.DeserializeObject<List<T>>(json);
return OppotunityList ;
} }
MainViewModel.cs
public MainViewModel()
{
InitializeDataAsync();
}
private async Task InitializeDataAsync()
{
var oppotunitiesServices = new OppotunitiesServices();
OppotunitiesList = await oppotunitiesServices.GetOppotunitiesAsync();
}
OppotunityServices.cs
public class OppotunitiesServices
{
public async Task<List<Oppotunity>> GetOppotunitiesAsync()
{
RestClient<Oppotunity> restClient = new RestClient<Oppotunity >();
var oppotunitiesList = await restClient.GetAsync();
return oppotunitiesList;
}
}

If you are debugging from an emulator, you should not use localhost to reach your development machine. You have to use the IP address or your running service.
You can test IP addresses directly from the browser of your emulator so you don't waste time starting/stopping your app to debug this...
Hope it helps

Related

Xamarin app deadlocks when making api call

My Xamarin app deadlocks when trying to make API call (asp.net core web API). The mobile app is using Android emulator. I created both API and client app following Microsoft's own tutorial. Requests run normally when making call with Postman or directly in the browser of my dev machine.
Constants class:
public static class Constants
{
public static string BaseAddress =
DeviceInfo.Platform == DevicePlatform.Android
? "https://10.0.2.2:44348"
:"https://localhost:44348";
public static string AppointmentsUrl = $"{BaseAddress}/api/appointments/";
}
Handler:
public class AppointmentHandler
{
HttpClient client;
JsonSerializerOptions serializerOptions;
private List<Appointment> Appointments { get; set; }
public AppointmentHandler()
{
client = new HttpClient();
serializerOptions = new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
WriteIndented = true
};
}
public async Task<List<Appointment>> GetAppointments()
{
Appointments = new List<Appointment>();
try
{
Uri uri = new Uri(string.Format(Constants.AppointmentsUrl, string.Empty));
// the program deadlocks here
HttpResponseMessage response = await this.client.GetAsync(uri);
if (response.IsSuccessStatusCode)
{
var content = await response.Content.ReadAsStringAsync();
return JsonSerializer.Deserialize<List<Appointment>>(content, serializerOptions);
}
}
catch (Exception e)
{
var m = e.Message;
}
return null;
}
}
Have you tried using
.ConfigureAwait(false)
This is a common issue with async code and user interfaces. More here:
https://forums.xamarin.com/discussion/174173/should-i-use-configureawait-bool-or-not

Can't figure how routing for controllers works

I'm new to ASP.Net and I'm building a website with Blazor server-side and I'm trying to post a form from the client to a controller like this :
Code for the client (located in /pages) :
private async void LogIn()
{
isSubmitting = true;
var json = JsonConvert.SerializeObject(logInForm);
var data = new StringContent(json, Encoding.UTF8, "application/json");
//The base adress correspond to "https://localhost:port/"
string adress = WebClient.httpClient.BaseAddress + "log_in";
var result = await WebClient.httpClient.PostAsync(adress, data);
isSubmitting = false;
}
Code for the server (located in /controllers) :
public class UserController : Controller
{
private readonly AppDbContext _db;
public UserManager<AppUser> _manager;
public UserController(AppDbContext db, UserManager<AppUser> manager)
{
_db = db;
_manager = manager;
}
[Route("log_in")]
[HttpPost]
private async Task<IActionResult> LogIn([FromBody]LogInForm userForm)
{
var user = new AppUser { UserName = userForm.mail, Email = userForm.mail };
var result = await _manager.CheckPasswordAsync(user, userForm.password);
return null;
}
}
When I execute this code, PostAsync() never redirect to the LogIn() method and return with an HTTP 400 error.
I learned first how to do it with PostJsonAsync() but it was using Blazor WebAssembly, which is in preview so I can't use it in production. I tried to find an answer on Internet first but there is no clear information on how to do it for Blazor server-side.
Any chance I could get a quick and simple explanation on what I'm doing wrong ?
default routing in asp.net is
weburl.com/{controller}/{action}
this would mean the url you're looking for is probably
weburl.com/user/log_in
see : https://learn.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-3.0

Async call works on console but not on webapi

I need to connect to Firebase from a C# WebApi.
For this I have made a Class Library which is the one who connects to Firebase and retrieve the information.
When I call this Class Library from a Console application, everything runs smoothly, but when I try to run it from a WebApi using Postman it starts to get async problems. Specifically DeadLock is happening.
I'm using FirebaseDatabase.net nugget as Firebase client.
EDIT
private async Task<string> LoginAsync()
{
var FirebaseApiKey = "XXXXXXXX";
var authProvider = new FirebaseAuthProvider(new FirebaseConfig(FirebaseApiKey));
var auth = await authProvider.SignInWithEmailAndPasswordAsync("myemail#mail.com", "mypassword");
return auth.FirebaseToken;
}
public FirebaseClient getClient()
{
if (client == null)
{
client = new FirebaseClient("https://approach-197117.firebaseio.com", new FirebaseOptions
{
AuthTokenAsyncFactory = LoginAsync
});
}
return client;
}
public static async Task<Dictionary<string, Location>> Run()
{
FirebaseConnect firebaseConnect = new FirebaseConnect().getInstance();
var firebase = firebaseConnect.getClient();
var list = await firebase.Child("Location").OnceSingleAsync<Dictionary<string, Location>>();
return list;
}
The problem comes that when I try to do a OnceSingleAsync asking for Location, the call works on a console app but doesn't work on a webapi call

Xamarin Form HttpClient Stuck

I'm trying to get response from soundcloud API. Here is my code.
public static async Task<string> GetTheGoodStuff()
{
var client = new HttpClient(new NativeMessageHandler());
var response = await client.GetAsync("http://api.soundcloud.com/playlists?client_id=17ecae4040e171a5cf25dd0f1ee47f7e&limit=1");
var responseString = response.Content.ReadAsStringAsync().Result;
return responseString;
}
But it's stucks on var response = await client.GetAsync. How can I fix this?
Thanks!
I did just use your code in a PCL, only thing I changed is the url (to https) to satisfy iOS ATS requirements, and called it from an async method. Seems to work fine running on iOS device. I did grab references to Microsoft.Net.Http in the PCL, and ModernHttpClient in the PCL and in the platform-specific projects (via NuGet).
Your code in some PCL view model class:
using System.Net.Http;
using System.Threading.Tasks;
using ModernHttpClient;
public class ItemsViewModel
{
...
public async Task<string> GetPlaylist()
{
// Use https to satisfy iOS ATS requirements.
var client = new HttpClient(new NativeMessageHandler());
var response = await client.GetAsync("https://api.soundcloud.com/playlists?client_id=17ecae4040e171a5cf25dd0f1ee47f7e&limit=1");
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
...
}
Then in a PCL page class that instantiates and uses an instance of the view model:
public partial class ItemsPage : ContentPage
{
public ItemsPage()
{
InitializeComponent();
Vm = new ItemsViewModel();
BindingContext = Vm;
}
protected override async void OnAppearing()
{
var playlist = await Vm.GetPlaylist();
// Do something cool with the string, maybe some data binding.
}
// Public for data binding.
public ItemsViewModel Vm { get; private set; }
}
Hope this helps.
I have the same problem. I fixed it by:
var response = httpClient.GetAsync(ApiUrl).ConfigureAwait(false).GetAwaiter().GetResult();
you can try it.

How to consume a webApi from asp.net Web API to store result in database?

I'm wondering how to consume a WEBAPI from another ASP.Net Web API to store the response in a database.
I know how to consume a WEBAPI from clients like javascript,console application etc.
But the requirement is to pull the data from third party API by my WEBAPI & store the result in a database so that using my WEBAPI my clients request me for data.
Is it possible to do this with an Asp.Net Web API?
In this tutorial is explained how to consume a web api with C#, in this example a console application is used, but you can also use another web api to consume of course.
http://www.asp.net/web-api/overview/web-api-clients/calling-a-web-api-from-a-net-client
You should have a look at the HttpClient
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost/yourwebapi");
Make sure your requests ask for the response in JSON using the Accept header like this:
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
Now comes the part that differs from the tutorial, make sure you have the same objects as the other WEB API, if not, then you have to map the objects to your own objects. ASP.NET will convert the JSON you receive to the object you want it to be.
HttpResponseMessage response = client.GetAsync("api/yourcustomobjects").Result;
if (response.IsSuccessStatusCode)
{
var yourcustomobjects = response.Content.ReadAsAsync<IEnumerable<YourCustomObject>>().Result;
foreach (var x in yourcustomobjects)
{
//Call your store method and pass in your own object
SaveCustomObjectToDB(x);
}
}
else
{
//Something has gone wrong, handle it here
}
please note that I use .Result for the case of the example. You should consider using the async await pattern here.
For some unexplained reason this solution doesn't work for me (maybe some incompatibility of types), so I came up with a solution for myself:
HttpResponseMessage response = await client.GetAsync("api/yourcustomobjects");
if (response.IsSuccessStatusCode)
{
var data = await response.Content.ReadAsStringAsync();
var product = JsonConvert.DeserializeObject<Product>(data);
}
This way my content is parsed into a JSON string and then I convert it to my object.
public class EmployeeApiController : ApiController
{
private readonly IEmployee _employeeRepositary;
public EmployeeApiController()
{
_employeeRepositary = new EmployeeRepositary();
}
public async Task<HttpResponseMessage> Create(EmployeeModel Employee)
{
var returnStatus = await _employeeRepositary.Create(Employee);
return Request.CreateResponse(HttpStatusCode.OK, returnStatus);
}
}
Persistance
public async Task<ResponseStatusViewModel> Create(EmployeeModel Employee)
{
var responseStatusViewModel = new ResponseStatusViewModel();
var connection = new SqlConnection(EmployeeConfig.EmployeeConnectionString);
var command = new SqlCommand("usp_CreateEmployee", connection);
command.CommandType = CommandType.StoredProcedure;
var pEmployeeName = new SqlParameter("#EmployeeName", SqlDbType.VarChar, 50);
pEmployeeName.Value = Employee.EmployeeName;
command.Parameters.Add(pEmployeeName);
try
{
await connection.OpenAsync();
await command.ExecuteNonQueryAsync();
command.Dispose();
connection.Dispose();
}
catch (Exception ex)
{
throw ex;
}
return responseStatusViewModel;
}
Repository
Task<ResponseStatusViewModel> Create(EmployeeModel Employee);
public class EmployeeConfig
{
public static string EmployeeConnectionString;
private const string EmployeeConnectionStringKey = "EmployeeConnectionString";
public static void InitializeConfig()
{
EmployeeConnectionString = GetConnectionStringValue(EmployeeConnectionStringKey);
}
private static string GetConnectionStringValue(string connectionStringName)
{
return Convert.ToString(ConfigurationManager.ConnectionStrings[connectionStringName]);
}
}

Categories