Xamarin.Forms Connecting to Web Services - c#

Good Day Everyone. I'm creating a simple Xamarin.Forms Portable Application in my Visual Studio 2015.
I want my Mobile Application to connect to the SQL Database I have in my VS2015 and return a LIST OF CUSTOMERS which should be display to my mobile phone.
I have created a Xamarin Portable project and a WebForms project that will handle my Web Services and Database.
In my WebForms project, I created a Controller that should return the List of Customers. This has a web service URL api/Customer that I used to connect to the RestClient in my Xamarin Portable. I also have CustomerViewModel that should represent the data in my application.
In my Xamarin Portable project, I have a ClientList.xaml that should display the List that comes from my database. I also have a CustomerVM that is connected to Services and my RestClient. My RestClient used the WEB SERVICE URL to get the List of Customer from my WebForms project.
Based on the given steps above, I still wasn't able to display the Data in my mobile phone. What do you think is the reason behind this? Thanks for your help.
Here are some of my codes:
RestClient.cs
public class RestClient_Customer<T>
{
private const string WebServiceUrl = "http://localhost:50857/api/Customer/";
public async Task<List<T>> GetCustomerAsync()
{
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var json = await httpClient.GetStringAsync(WebServiceUrl);
var taskModels = JsonConvert.DeserializeObject<List<T>>(json);
return taskModels;
}
}
CustomerServices.cs
using Plugin.RestClient;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using XamarinFormsDemo.Models;
namespace XamarinFormsDemo.Services
{
public class CustomerServices
{
public async Task<List<Customer>> GetCustomerAsync()
{
RestClient_Customer<Customer> restClient = new RestClient_Customer<Customer>();
var customerList = await restClient.GetCustomerAsync(); //yung getasync ay pantawag as restclient
return customerList;
}
}
}
CustomerVM.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.Services;
using XamarinFormsDemo.Views;
namespace XamarinFormsDemo.ViewModels
{
public class CustomerVM : INotifyPropertyChanged
{
private List<Customer> _customerList; // keep all customers
private List<Customer> _searchedCustomerList; // keep a copy for searching
private Customer _selectedCustomer = new Customer();
private string _keyword = "";
public string Keyword
{
get
{
return _keyword;
}
set
{
this._keyword = value;
// while keyword changed we filter Employees
//Filter();
}
}
private void Filter()
{
if (string.IsNullOrWhiteSpace(_keyword))
{
CustomerList = _searchedCustomerList;
}
else
{
// var lowerKeyword = _keyword.ToLower();
CustomerList = _searchedCustomerList.Where(r => r.CUSTOMER_NAME.ToLower().Contains(_keyword.ToLower())).ToList();
// EmployeesList = _searchedEmployeesList.Where(r => r.EMPLOYEE_NAME.Contains(_keyword)).ToList();
}
}
public List<Customer> CustomerList
{
get
{
return _customerList;
}
set
{
_customerList = value;
OnPropertyChanged();
}
}
public CustomerVM()
{
InitializeDataAsync();
}
private async Task InitializeDataAsync()
{
var customerServices = new CustomerServices();
_searchedCustomerList = await customerServices.GetCustomerAsync();
CustomerList = await customerServices.GetCustomerAsync();
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

I think the problem is in your services hope this will help you,
public interface ICustomer
{
Task<string> GetCustomers();
}
public class CustomerService : ICustomer
{
public async Task<string> GetCustomers()
{
var client = new HttpClient();
var response = await client.GetAsync(string.Format("http://mysite/api/Customer"));
var responseString = await response.Content.ReadAsStringAsync();
return responseString;
}
}
Call it anywhere you like
var _custList = new GetCustomers();
var returnJson = await _custList.GetCustomers();
Note the return is json string format or xml format depending on your REST API so you need to parse this first before you can get the value and display it to ListView

Try running it in UWP. If it works in UWP then you have to take a look at
Xamarin HttpClient.GetStringAsync not working on Xamarin.Droid
I had the same issue but when I tried it in UWP it worked fine. I am still seeking for the solution to run xamarin.android using device.

Related

Redis Crashing in .Net 6

I have a weird error in Redis on .Net 6. When I run the test code here:
https://github.com/redis-developer/redis-graph-dotnet-basic-app/blob/main/Program.cs
It works perfectly fine. In this case the code is running in the program.cs file.
When I port that code to a class, in order to better manage encapsulation and complexity. It does not work. What it does is run the code and when it gets to the: await graph.QueryAsync part, it just stops the debugger. Very strange indeed.
Here is the code I am using. Any thoughts or suggestions:
//Program.cs (Relevant Bits)
using RedisTest //PROGRAM //WRITE TO REDIS ENTERPRISE CLOUD Process_LoadGraph process_LoadGraph = new Process_LoadGraph(); process_LoadGraph.Controller(results);
//SHARED CONNECTION CLASS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using StackExchange.Redis;
namespace RedisTest
{
public class RedisSharedConnection
{
public static ConnectionMultiplexer Connection
{
get
{
return lazyConnection.Value;
}
}
private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>
{
ConnectionMultiplexer connectionMultiplexer = ConnectionMultiplexer.Connect(ConfigData.dbConnectionString);
return connectionMultiplexer;
});
}
}
//USAGE CLASS
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NRedisGraph;
namespace RedisTest
{
public class Process_LoadGraph
{
public async void Controller(List<Result> results)
{
//Setup
var redisConnection = RedisSharedConnection.Connection;
//var redisConnection = ConnectionMultiplexer.Connect(ConfigData.dbConnectionString);
var db = redisConnection.GetDatabase(ConfigData.dbId);
var graph = new RedisGraph(db);
string graphName = ConfigData.graphName;
//Test Transaction
// Create Bob
// CRASHES HERE
var createBobResult = await graph.QueryAsync("pets", "MERGE(:human{name:'Bob',age:32})");
}
}
}
Turns out the solution is to use Redis in a static class. Along the following lines:
internal static class WriteToDB
{
public static async Task WriteAsync(List<string> querieS)
{
//Load Graph
//Setup
var redisConnection = RedisSharedConnection.Connection;
//var redisConnection = ConnectionMultiplexer.Connect(ConfigData.dbConnectionString);
var db = redisConnection.GetDatabase(ConfigData.dbId);
var graph = new RedisGraph(db);
string graphName = ConfigData.graphName;
// ** DEBUG
//Test Transaction
// Create Bob
var createBobResult = await graph.QueryAsync("pets", "MERGE(:human{name:'Bob',age:32})");
{ }
//Clear Graph
await graph.QueryAsync(graphName, "MATCH(n) DETACH DELETE n");
{ }
}
}

SignalR only works the first time it is called

I have a ASP.NET Core MVC 5 website. I am using SignalR to send "Notifications" from the model layer to the client / view.
If I open my index page, It uses SignalR to send a list of available cameras as they are discovered. I then again use SignalR to send images that the camera is taking on a different model. However, only the first one works.
If I navigate to https://localhost:44303/camera/live/?IP=192.168.50.212 It starts sending images, but will not discover other cameras. If I navigate to the discovery first, the discovery works just fine.
In both the models, the line Hub.Clients.All.SendAsync("method", data); is executing. In both models, the Hub is defined as
public Microsoft.AspNetCore.SignalR.IHubContext<MasterHub> Hub { get; internal set; }`
and each model has a separate controller, that sets the hub context like so:
private readonly IHubContext<MasterHub> _hubContext;
public CameraController(IHubContext<MasterHub> hubContext)
{
_hubContext = hubContext;
}
However, only the first one I navegate to works.
Do I have to close the SignalR connection after sending a message to use it again? If so, How would I do this?
both controllers look like:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Thermal_Screening.Hubs;
using Thermal_Screening.Models;
namespace Thermal_Screening.Controllers
{
public class CameraController : Controller
{
public string CameraName;
private readonly IHubContext<MasterHub> _hubContext;
public CameraController(IHubContext<MasterHub> hubContext)
{
_hubContext = hubContext;
}
public IActionResult Live(string IP)
{
CameraName = getCameraNameFromIP(IP); // doin it this way causes a 2s delay, should get ip in model
return View(new CameraViewModel(IP) { Hub = _hubContext, IP = IP, CameraName = CameraName });
}
public IActionResult Settings(string IP)
{
CameraName = getCameraNameFromIP(IP);
return View(new CameraViewModel(IP) { Hub = _hubContext, IP = IP, CameraName = CameraName });
}
public IActionResult Log(string IP)
{
CameraName = getCameraNameFromIP(IP);
return View(new CameraViewModel(IP) { Hub = _hubContext, IP = IP, CameraName = CameraName });
}
private string getCameraNameFromIP(string IP)
{
WebClient x = new WebClient();
string source = x.DownloadString("http://" + IP);
return Regex.Match(source, #"\<title\b[^>]*\>\s*(?<Title>[\s\S]*?)\</title\>", RegexOptions.IgnoreCase).Groups["Title"].Value;
}
}
}
both viewmodels look like:
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http.Extensions;
using Flir.Atlas.Live.Discovery;
using Flir.Atlas.Live.Device;
using Flir.Atlas.Live;
using System.IO;
using Flir.Atlas.Image;
using System.Drawing;
using Microsoft.AspNetCore.SignalR;
using Thermal_Screening.Hubs;
namespace Thermal_Screening.Models
{
public class CameraViewModel
{
public Microsoft.AspNetCore.SignalR.IHubContext<MasterHub> Hub { get; internal set; }
//removed for berevity
Hub.Clients.All.SendAsync("method", "data");

How do I use Azure Cognitive Translator to translate a textblock in UWP?

I created an Azure profile, and signed up for a Azure Cognitive Translator service. Now I want to use the translator api to translate a bunch of textblock in UWP xaml. But I'm not sure how to link my xaml textblock into the translator class I created.
Here is the class I made:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;
namespace AlarmClockProject
{
class translator
{
private const string Key = "MY_API_KEY";
private static readonly HttpClient client = new HttpClient
{
DefaultRequestHeaders = { { "Ocp-Apim-Subscription-Key", Key } }
};
public static async Task Main()
{
while (true)
{
var text = Console.ReadLine(); // read the textblock
var translatedText = await Translate(text, "en");
Console.WriteLine(translatedText); //put this into the textblock
}
}
public static async Task<string> Translate(string text, string language)
{
var encodedText = WebUtility.UrlEncode(text);
var uri = "https://api.microsofttranslator.com/V2/Http.svc/Translate?" + $"to={language}&text={encodedText}";
var result = await client.GetStringAsync(uri);
return XElement.Parse(result).Value;
}
}
}
And here is the xaml I wish to translate which is under a page_loaded event.
List<Article> articles = await NewsApi.GetArticlesMain();
newsHeadlineTB.Text = articles.First().title;
descriptionTB.Text = articles.First().description;
newsHeadline1TB.Text = articles.Last().title;
description1TB.Text = articles.Last().description;
I want to translate newsHeadlineTB.text and descriptionTB.text. I'm not sure if it would clash with another class (newsapi.org). How do I link the translator.cs class into my mainpage xaml and translate this two textblocks?
You just need to call the translate method:
var language = "en";
List<Article> articles = await NewsApi.GetArticlesMain();
newsHeadlineTB.Text = await translator.Translate(articles.First().title, language);
descriptionTB.Text = await translator.Translate(articles.First().description, language);
newsHeadline1TB.Text = await translator.Translate(articles.Last().title, language);
description1TB.Text = await translator.Translate(articles.Last().description, language);

C# Throwing unable to resolve controller error

I'm fairly new to .NET and c# and I'm working on a POC where I've run into an issue when a controller throws the error
System.InvalidOperation Exception {"Unable to resolve controller: TenantController"}
The Inner exception details are
No default Instance is registered and cannot be automatically determined for type 'GICS.Web.Managers.Interfaces.ITenantManager'
There is no configuration specified for GICS.Web.Managers.Interfaces.ITenantManager
1.) new TenantController(Default of ITenantManager, Default of IRemedyService)
2.) GICS.Web.Controllers.Api.TenantController
3.) Instance of GICS.Web.Controllers.Api.TenantController
4.) Container.GetInstance(GICS.Web.Controllers.Api.TenantController)
The TenantController looks as follows:
using System.Web.Mvc;
using GICS.Web.Controllers.Api.Abstracts;
using GICS.Web.Managers.Interfaces;
using GICS.Web.Services.Interfaces;
using System.Collections.Generic;
using GICS.Web.ViewModels.Tenant;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Controllers.Api
{
[RoutePrefix("api/tenant")]
public class TenantController : BaseApiController
{
private readonly ITenantManager _tenantsManager;
private readonly IRemedyService _remedyService;
private string token;
public TenantController(ITenantManager tenantsManager, IRemedyService remedyService)
{
_tenantsManager = tenantsManager;
_remedyService = remedyService;
token = null;
}
[HttpGet, Route("{groupId}/{userName}")]
public JsonResult getTenants(string groupId, string UserName)
{
getToken(UserName);
JsonResult result = Json(null);
if (token != null)
{
var tenants = _tenantsManager.GetTenants(token, groupId);
List<TenantViewModel> tenantViewModelList = new List<TenantViewModel>();
foreach (Values x in tenants)
{
TenantViewModel model = new TenantViewModel(x, groupId);
tenantViewModelList.Add(model);
}
result = Json(tenantViewModelList);
}
return result;
}
}
The TenantManager interface is as follows:
using System.Collections.Generic;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Managers.Interfaces
{
public interface ITenantManager
{
IEnumerable<Values> GetTenants(string token, string groupId);
}
}
And the Manager implementation is:
using GICS.Web.Managers.Abstracts;
using GICS.Web.Managers.Interfaces;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using GICS.Web.Models.Tenant;
namespace GICS.Web.Managers
{
public class TentantManager : ManagerBase, ITenantManager
{
public IEnumerable<Models.Tenant.Values> GetTenants(string token, string groupId)
{
Tenant restEntries = null;
List<Models.Tenant.Values> tenantList = new List<Models.Tenant.Values>();
using (WebClient client = new WebClient())
{
client.Headers[HttpRequestHeader.Authorization] = token;
var baseURL = ConfigurationManager.AppSettings["RemedyBaseUrl"];
var apiPath = ConfigurationManager.AppSettings["RemedyAPIPath"];
string getURL = baseURL + apiPath + "ESN%3AAST%3ALogSysComp%5FASTPeople" + "?q=?q=%27PeopleGroup%20Form%20Entry%20ID%27%20%3D%20%22" + groupId + "%22&fields=values(Name)";
string getResponse = client.DownloadString(getURL);
restEntries = JsonConvert.DeserializeObject<Tenant>(getResponse);
foreach (Models.Tenant.Entry x in restEntries.entries)
{
tenantList.Add(x.values);
}
}
return tenantList;
}
}
}
I have other controllers in the project that follow the same approach and all are working except for this one. Anyone spot where I am going wrong here?
Thanks in advance.

Flurl & HttpTest: Unit tests fail when Run All, but pass when run individually

Update: HttpTest is not thread-safe, as per the project's GitHub issue. Until the issue is resolved, tests using HttpTest cannot be run in parallel.
I have a really weird pair of test utilizing Flurl and xUnit that, when Run All in VS Test Explorer, will fail, but if run individually, will pass. I cannot for the life of me see anywhere where the 2 are even related to each other, but they do.
I have extracted them out of my project into a new project and the problem persists. I bundled them into a 7z for anyone interested in loading it to VS, but the full code follows.
Project.Commons
GetApi1:
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
namespace Project.Commons
{
public class GetApi1
{
public async Task<string> ExecuteAsync(string token)
{
string apikeyKeyname = "token";
dynamic response = await "http://www.api.com"
.SetQueryParams(new { token = token })
.GetJsonAsync();
string receivedApiKey = ((IDictionary<string, object>)response)[apikeyKeyname].ToString();
return receivedApiKey;
}
}
}
GetApi2:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
namespace Project.Commons
{
public class GetApi2
{
public async Task<IList<string>> ExecuteAsync()
{
var responses = await "http://www.api.com"
.GetJsonAsync<List<string>>();
var result = new List<string>();
foreach (var response in responses)
{
result.Add("refined stuff");
}
return result;
}
}
}
Project.Tests
UnitTest1:
using Project.Commons;
namespace Project.Tests
{
public class UnitTest1
{
private ITestOutputHelper output;
public UnitTest1(ITestOutputHelper output)
{
this.output = output;
}
[Fact]
public async Task ShouldBeAbleToGetApiKeyFromToken()
{
// Arrange
using (var httpTest = new HttpTest())
{
var jsonResponse = new { token = "abcdef" };
string expectedApiKey = "abcdef";
httpTest.RespondWithJson(jsonResponse);
var api = new GetApi1();
// Act
var receivedApiKey = await api.ExecuteAsync("mockToken");
output.WriteLine("Received apikey = " + receivedApiKey);
// Assert
Assert.Equal(expectedApiKey, receivedApiKey);
}
}
}
}
UnitTest2
using Flurl.Http.Testing;
using Project.Commons;
using Xunit;
using Xunit.Abstractions;
namespace Project.Tests
{
public class UnitTest2
{
#region Mock API JSON Response
private IList<string> mockResponse = new List<string>()
{
"raw stuff", "raw stuff", "raw stuff"
};
#endregion
#region Expected Result
private IList<string> expectedResult = new List<string>()
{
"refined stuff", "refined stuff", "refined stuff"
};
#endregion
[Fact]
public async Task CanGetProjectsByWeek()
{
// Arrange
using (var httpTest = new HttpTest())
{
httpTest.RespondWithJson(mockResponse);
// Act
var api = new GetApi2();
var actualResult = await api.ExecuteAsync();
// Assert
Assert.Equal(expectedResult,actualResult);
}
}
}
}
The comments are correct - lack of thread safety is a known limitation of HttpTest. It is logged and under investigation. Parallel testing is much more prevalent today than just a couple years ago when this was created, so while a fix is not trivial, we are treating it with high priority.

Categories