Xamarin forms HTTPS data request not work on android - json

I recently downloaded Visual Studio 2017, on Xamarin I start a new proyect, everything goes Ok, when I try to consume REST Api service, the app dont do the request, I install my nugets on all my proyect in this order:
1. Microsoft build
2. Micrososft.net.http
3. Newtonjson
the app only do the request on UWP app, not in Android app, not in IOS App, Im kind of tired to find this error, I need help
here's the link I took for example: https://www.youtube.com/watch?v=xNP-K37mssA&t=785s in in spanish by the way.
---- JSON OBJECT CLASS--
namespace App1
{
public class WingetResult
{
public int userId { get; set; }
public int id { get; set; }
public string title { get; set; }
public string body { get; set; }
}
}
-----Generic get request-----
namespace App1
{
public class RestClient
{
//Metodo generico para cualquier peticion tipo get
public async Task<T> Get<T>(string url)
{
try
{
HttpClient client = new HttpClient();
var response = await client.GetAsync(url);
if (response.StatusCode == System.Net.HttpStatusCode.OK)
{
var jsonString = await response.Content.ReadAsStringAsync();
return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(jsonString);
}
else
{
System.Diagnostics.Debug.WriteLine("else HTTP CLIENT STATUS no es OK");
}
}
catch (Exception e)
{
}
return default(T);
}
}
}
----MAIN PAGE CODE------
namespace App1
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
Device.BeginInvokeOnMainThread(async () => {
RestClient client = new RestClient();
var wingetResult = await client.Get<WingetResult>("https://jsonplaceholder.typicode.com/posts/1");
if (wingetResult != null)
{
label1.Text = wingetResult.title;
}
else {
label1.Text = "no";
}
});
}
}
}

Your issue is with the HTTPS request
i will suggest you to use ModernHttpClient

Related

create a Custom Exception Handler Middleware generating response based on client request

How to create a Custom Exception Handler Middleware. This middleware should generate a custom response based on the Calling Client. If the client is requesting via AJAX then the response should be a JSON Response describing the Error otherwise Redirect the client to Error page.
Controller code
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
middleware code
public class ErrorHandlerMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlerMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception error)
{
var response = context.Response;
var customError = new CustomError();
switch (error)
{
case AppException e:
// custom application error
customError.StatusCode = (int)HttpStatusCode.BadRequest;
break;
case KeyNotFoundException e:
// not found error
customError.StatusCode = (int)HttpStatusCode.NotFound;
break;
default:
// unhandled error
customError.StatusCode = (int)HttpStatusCode.InternalServerError;
break;
}
customError.ErrorMessage = error?.Message;
if (context.Request.ContentType == "application/json;")
{
var result = JsonSerializer.Serialize(customError);
await response.WriteAsync(result);
}
else
{
context.Response.Redirect("/Errors/CustomError");
}
}
}
Custom Error class code
public class CustomError
{
public int StatusCode { get; set; }
public string ErrorMessage { get; set; }
}
Error View model
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
you could add the code in your startup class:
app.UseStatusCodePagesWithReExecute("/errors/{0}");
add a controller(In my case I tested with HttpContext.Request.Headers["Content-Type"] ,it should be context.Request.ContentType == "application/json;" for MVC project ):
public class ErrorsController : Controller
{
[Route("errors/{statusCode}")]
public IActionResult CustomError(int statusCode)
{
if (HttpContext.Request.Headers["Content-Type"] == "application/json")
{
var cuserr = new CustomError() { ErrorMessage = "err", StatusCode = statusCode };
return new JsonResult(cuserr);
}
else
{
if (statusCode == 404)
{
return View("~/Views/Errors/404.cshtml");
}
return View("~/Views/Errors/500.cshtml");
}
}
}
and the views:
The result:
for more details,you could read the offcial document:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/error-handling?view=aspnetcore-6.0

How to upload image in ASP.Net core code first approach and send image using post man

This is my model class
public class ImageModel
{
[Key]
public int ImageId { get; set; }
[Column(TypeName = "nvarchar(50)")]
public string Title { get; set; }
[Column(TypeName = "nvarchar(100)")]
[DisplayName("Image Name")]
public string ImageName { get; set; }
[NotMapped]
[DisplayName("Upload File")]
public IFormFile ImageFile { get; set; }
}
This is my controller class for post request
And I create a wwwroot folder to save Image
[Route("api/[Controller]")]
[ApiController]
public class ImageController : Controller
{
private readonly Databasecontext _context;
private readonly IWebHostEnvironment _hostEnvironment;
public ImageController(Databasecontext context, IWebHostEnvironment hostEnvironment)
{
_context = context;
this._hostEnvironment = hostEnvironment;
}
// GET: Image
public async Task<IActionResult> Index()
{
return View(await _context.Images.ToListAsync());
}
// GET: Image/Create
public IActionResult Create()
{
return View();
}
// POST: Image/Create
[HttpPost]
public async Task<IActionResult> Create([Bind("ImageId,Title,ImageName")] ImageModel imageModel)
{
if (ModelState.IsValid)
{
//Save image to wwwroot/image
string wwwRootPath = _hostEnvironment.WebRootPath;
string fileName = Path.GetFileNameWithoutExtension(imageModel.ImageFile.FileName);
string extension = Path.GetExtension(imageModel.ImageFile.FileName);
imageModel.ImageName = fileName = fileName + DateTime.Now.ToString("yymmssfff") + extension;
string path = Path.Combine(wwwRootPath + "/Image/", fileName);
using (var fileStream = new FileStream(path, FileMode.Create))
{
await imageModel.ImageFile.CopyToAsync(fileStream);
}
//Insert record
_context.Add(imageModel);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(imageModel);
}
This is my DB context
public DbSet<ImageModel> Images { get; set; }
I just need to test this using postman and combine it with angular. Can someone help me?
when I send an image through postman I get this error The request entity has a media type that doesn't support server or resource does not support.
That is because you use [ApiController] in your controller, it allows data from body by default. So you need specific the source by using [FromForm] attribute like below:
[HttpPost]
public async Task<IActionResult> Create([Bind("ImageId,Title,ImageName")][FromForm] ImageModel imageModel)
{
//..
return View(imageModel);
}
Besides, if you use [Bind("ImageId,Title,ImageName")], ImageFile cannot be binded to the model.
Sorry for my Spanish in the code.
This is how i upload the file in Base64 and then copy the file to a Directory.
I Pupulate the Object ArchivoAnexoUploadDto using a page http://base64.guru/converter/encode/file for convert a file to a base64.
I Hope tha this extract of the code will be usefull for you
1 - Controller
[HttpPost("UploadFileList")]
public async Task<IActionResult> UploadFileList(List<ArchivoAnexoUploadDto> fileList)
{
IOperationResult<object> operationResult = null;
try
{
operationResult = await _fileService.UploadFileList(fileList);
if (!operationResult.Success)
{
return BadRequest(operationResult.ErrorMessage);
}
return Ok(operationResult.Entity);
}
catch (Exception ex)
{
return BadRequest(operationResult.Entity);
}
}
I Recibe a List of Objects < ArchivoAnexoUploadDto > and the service converts the base 64 to Bytes array.
2 - Service
public async Task<IOperationResult<object>> UploadFileList(List<ArchivoAnexoUploadDto> files)
{
List<ArchivoAnexoCreateDto> fileList = PrepareFileList(files);
Response result = ValidateFiles(fileList);
if (!result.Status)
{
Response responseError = new()
{
Status = false,
Message = ((FormFile)result.Object).FileName,
MessageDetail = result.Message
};
return OperationResult<object>.Ok(responseError);
}
var saveResult = await SaveFileList(fileList);
Response respuesta = new()
{
Status = true,
Message = "Los archivos fueron almacenados exitosamente.",
MessageDetail = ""
};
return OperationResult<object>.Ok(respuesta);
}
private List<ArchivoAnexoCreateDto> PrepareFileList(List<ArchivoAnexoUploadDto> files)
{
List<ArchivoAnexoCreateDto> formFileList = new List<ArchivoAnexoCreateDto>();
foreach (ArchivoAnexoUploadDto newFile in files)
{
byte[] fileBytes = Convert.FromBase64String(newFile.Base64);
string filePath = Path.Combine(_fileSettings.PrincipalPath, _fileSettings.PrincipalFolderName, newFile.NombreArchivo);
MemoryStream memoryStream = new MemoryStream();
memoryStream.Write(fileBytes, 0, fileBytes.Length);
FormFile fileData = new FormFile(memoryStream, 0, memoryStream.Length, newFile.NombreArchivo, newFile.NombreArchivo);
ArchivoAnexoCreateDto fileDto = new()
{
FileId = 0,
Data = fileData,
FileName = newFile.NombreArchivo,
Module = newFile.Modulo
};
formFileList.Add(fileDto);
}
return formFileList;
}
private Response ValidateFiles(List<ArchivoAnexoCreateDto> fileList)
{
foreach (ArchivoAnexoCreateDto fileObj in fileList)
{
IFormFile file = fileObj.Data;
try
{
ValidateFile(file);
}
catch (Exception exception)
{
return new Response { Status = false, Message = exception.Message, Object = file };
}
}
return new Response { Status = true, Message = "" };
}
The Service recibe the Array and PrepareFileList return the same data but the array have IFormFile instead of Base64 string.
3 - Dtos
public sealed class ArchivoAnexoUploadDto
{
public long AnexoFileId { get; set; }
public string Base64 { get; set; }
public string NombreArchivo { get; set; }
public Module Modulo {get; set;}
}
public sealed class ArchivoAnexoCreateDto
{
public long FileId { get; set; }
public IFormFile Data { get; set; }
public int FileTypeId { get; set; }
public string FileName { get; set; }
public Module Module { get; set; }
}
ArchivoAnexoUploadDto Is the Dto that recives the base64 and the name of the file.
ArchivoAnexoCreateDto Is the Dto with IFormFile property and is used to copy the file to a Directory.
4 - Validate IFormFile To Copy to Dir
private void ValidateFile(IFormFile fileToCreate)
{
if (fileToCreate == null)
{
throw new Exception("No ha enviado ningun archivo.");
}
IOperationResult<string> fileExtensionResult = _fileService.GetFileExtension(fileToCreate);
if (!fileExtensionResult.Success)
{
throw new Exception(fileExtensionResult.ErrorMessage);
}
if (!_fileSettings.AllowedExtensions.Contains(fileExtensionResult.Entity))
{
throw new Exception("La extención del archivo no es permitida.");
}
IOperationResult<long> fileSizeResult = _fileService.GetFileSize(fileToCreate);
if (!fileSizeResult.Success)
{
throw new Exception("Ha ocurrido un error obteniendo el tamaño del archivo.");
}
if (fileSizeResult.Entity > _fileSettings.MaxFileSize)
{
throw new Exception("El tamaño del archivo supera el limite.");
}
}
This are Conditions for validate (Only for explain) I Did this stuff because the business configured a list of extensions, a size limit of the files, etc.

Xamarin Forms reading JSON

So I am retrieving JSON data from my site and this is my code:
The model:
class Reservations
{
public string id_reservation { get; set; }
public string spz { get; set; }
public string reservation_day { get; set; }
public string reservation_time { get; set; }
public string ip_address { get; set; }
}
The connection and parsing:
protected async void CheckReservations(string day)
{
if (CrossConnectivity.Current.IsConnected)
{
try
{
private const string Url = "Urltomysite";
private HttpClient _client = new HttpClient();
var content = await _client.GetStringAsync(Url);
List<Reservations> myData = JsonConvert.DeserializeObject<List<Reservations>>(content);
foreach (Reservations res in myData)
{
System.Console.WriteLine("Time:" + res.reservation_time);
}
}
catch (Exception e)
{
Debug.WriteLine("" + e);
}
}
}
And the JSON response from my site:
[
{
id_reservation: "39",
spz: "NRGH67L",
reservation_day: "2019-01-26",
reservation_time: "14:00",
ip_address: "192.168.137.5"
}
]
But when I try to print the reservation_time from List of the Object in the foreach I dont get any results. I am still pretty new to this and got this far from tutorials, so dont know what I am missing.
Thanx for any replies.
I suggest using a crash prone way of this
var response = await client.GetAsync(uri);
if(response.IsSuccessStatusCode)
{
var json = await responseMessage.Content.ReadAsStringAsync(); //using ReadAsStreamAsync() gives you better performance
List<Reservations> myData = JsonConvert.DeserializeObject<List<Reservations>>(json);
//do the rest jobs
}
else
{
//alert the api call failed
}

how to get json data from external rest full web service in asp.net mvc 4

I am trying to get the json data from an external rest url(http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3) and display it on my web page in my asp.net mvc application. For that I have written some code i.e.
Controleer---
namespace MyMVCApplication.Controllers
{
public class EmployeeController : Controller
{
string Baseurl = "http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3";
public async Task<ActionResult> StateDetails()
{
List<State> listStateInfo = new List<State>();
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(Baseurl);
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage Res = await client.GetAsync(Baseurl);
if (Res.IsSuccessStatusCode)
{
//Storing the response details recieved from web api
var StateResponse = Res.Content.ReadAsStringAsync().Result;
//Deserializing the response recieved from web api and storing into the Employee list
listStateInfo = JsonConvert.DeserializeObject<List<State>>(StateResponse);
}
return View(listStateInfo);
}
}
}
}
Model----
namespace MyMVCApplication.Models
{
public class State
{
public int ObjectID { get; set; }
public string StateName { get; set; }
public int Black { get; set; }
public int Population { get; set; }
}
}
While debugging the code getting the error: "Newtonsoft.Json.JsonReaderException: Unexpected character encountered while parsing value: <. Path '', line 10, position 1" at
JsonConvert.DeserializeObject.
Please suggest me how to solve this issue.
Replace your url with http://sampleserver6.arcgisonline.com/arcgis/rest/services/Census/MapServer/3?f=pjson to get the json version of the web service

IIS responses with HTML instead of JSON on ASP .NET MVC3

The subject is selfexplanatory. I've developer and production environments. Developer env. is my localhost machine. I've action methods in contolers that sets response status code to 500 when something wents wrong (error occured, or logical inconsistance) and returns Json-answer. My common method looks like that:
[HttpPost]
public ActionResult DoSomething(int id)
{
try
{
// some useful code
}
catch(Exception ex)
{
Response.StatusCode = 500;
Json(new { message = "error" }, JsonBehaviour.AllowGet)
}
}
On the client side in production env. when such an error occured ajax.response looks like an HTML-code, instead of expected JSON.
Consider this:
<div class="content-container">
<fieldset>
<h2>500 - Internal server error.</h2>
<h3>There is a problem with the resource you are looking for, and it cannot be displayed.</h3>
</fieldset>
</div>
Filter context is not an option. I think it is some sort of IIS or web.config issue.
SOLUTION:
We decided to add TrySkipIisCustomErrors in BeginRequest in Global.asax and it is solved problems in each method in our application.
I guess that IIS is serving some friendly error page. You could try skipping this page by setting the TrySkipIisCustomErrors property on the response:
catch(Exception ex)
{
Response.StatusCode = 500;
Response.TrySkipIisCustomErrors = true;
return Json(new { message = "error" }, JsonBehaviour.AllowGet)
}
Is your IIS configured to treat application/json as a valid mime-type? You may check that in properties for the server in IIS Manager and click MIME Types. If json is not there then click "New", enter "JSON" for the extension, and "application/json" for the MIME type.
I solved this by writing a custom json result, which uses json.net as the serializer. This is overkill for just the IIS fix but it means it's reusable.
public class JsonNetResult : JsonResult
{
//public Encoding ContentEncoding { get; set; }
//public string ContentType { get; set; }
public object Response { get; set; }
public HttpStatusCode HttpStatusCode { get; set; }
public JsonSerializerSettings SerializerSettings { get; set; }
public Formatting Formatting { get; set; }
public JsonNetResult(HttpStatusCode httpStatusCode = HttpStatusCode.OK)
{
Formatting = Formatting.Indented;
SerializerSettings = new JsonSerializerSettings { };
SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
HttpStatusCode = httpStatusCode;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
HttpResponseBase response = context.HttpContext.Response;
response.TrySkipIisCustomErrors = true;
response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
if (ContentEncoding != null)
response.ContentEncoding = ContentEncoding;
response.StatusCode = (int) HttpStatusCode;
if (Response != null)
{
JsonTextWriter writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
JsonSerializer serializer = JsonSerializer.Create(SerializerSettings);
serializer.Serialize(writer, Response);
writer.Flush();
}
}
}
Use:
try
{
return new JsonNetResult()
{
Response = "response data here"
};
}
catch (Exception ex)
{
return new JsonNetResult(HttpStatusCode.InternalServerError)
{
Response = new JsonResponseModel
{
Messages = new List<string> { ex.Message },
Success = false,
}
};
}