Unable to deserialize json array using wcf service - json

I'm trying to DeSerialize data in json array using wcf service in the project.
The data is fetched and can be noticed in the debugging but i'm unable to deserialize, or something else that I'm mistaken. Below is the code that I've tried to deserialize.
Note:- I've separately run the wcf application and its returning json array in correct format with the actual result.
HotelServiceClient.cs
public class HotelServiceClient
{
private string BASE_URL = "http://localhost:50540/ServiceHotel.svc/";
public List<HotelInfo> findall()
{
try
{
var webClient = new WebClient();
var json = webClient.DownloadString(BASE_URL + "findall");
var javaScriptJson = new JavaScriptSerializer();
return javaScriptJson.Deserialize<List<HotelInfo>>(json);
}
catch
{
return null;
}
}
HotelInfo.cs
public class HotelInfo
{
private int _hotelid;
private string _hotelname;
private string _hoteldesc;
private string _hotelprice;
private byte[] _hotelpicture;
[Key]
[Display(Name = "Id")]
public int Hotelid
{
get
{
return _hotelid;
}
set
{
_hotelid = value;
}
}
[Display(Name = "Name")]
public string Hotelname
{
get
{
return _hotelname;
}
set
{
_hotelname = value;
}
}
[Display(Name = "description")]
public string Hoteldesc
{
get
{
return _hoteldesc;
}
set
{
_hoteldesc = value;
}
}
[Display(Name = "price")]
public string Hotelprice
{
get
{
return _hotelprice;
}
set
{
_hotelprice = value;
}
}
[Display(Name = "picture")]
public byte[] Hotelpicture
{
get
{
return _hotelpicture;
}
set
{
_hotelpicture = value;
}
}
}
WebService
Hotel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace CRUDwithHotels
{
public class Hotel
{
public int Id { get; set; }
public string Name { get; set; }
public string description { get; set; }
public string price { get; set; }
public byte[] picture { get; set; }
}
}
IServiceHotel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
namespace CRUDwithHotels
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IServiceHotel" in both code and config file together.
[ServiceContract]
public interface IServiceHotel
{
[OperationContract]
[WebInvoke(Method ="GET", UriTemplate ="findall", ResponseFormat =WebMessageFormat.Json)]
List<Hotel> findall();
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "find/{id}", ResponseFormat = WebMessageFormat.Json)]
Hotel find(string id);
[OperationContract]
[WebInvoke(Method = "POST", UriTemplate = "create", ResponseFormat = WebMessageFormat.Json, RequestFormat =WebMessageFormat.Json)]
bool create(Hotel hotel);
[OperationContract]
[WebInvoke(Method = "PUT", UriTemplate = "edit", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
bool edit(Hotel hotel);
[OperationContract]
[WebInvoke(Method = "DELETE", UriTemplate = "delete", ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)]
bool delete(Hotel hotel);
}
}
ServiceHotel.svc.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace CRUDwithHotels
{
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ServiceHotel" in code, svc and config file together.
// NOTE: In order to launch WCF Test Client for testing this service, please select ServiceHotel.svc or ServiceHotel.svc.cs at the Solution Explorer and start debugging.
public class ServiceHotel : IServiceHotel
{
public bool create(Hotel hotel)
{
using (ModelMyDemo hie = new ModelMyDemo())
{
try
{
HotelInfoEntities info = new HotelInfoEntities();
info.Hotelname = hotel.Name;
info.Hoteldesc = hotel.description;
info.Hotelprice = hotel.price;
info.Hotelpicture = hotel.picture;
hie.HotelInfoEntities.Add(info);
hie.SaveChanges();
return true;
}
catch
{
return false;
}
};
}
public bool delete(Hotel hotel)
{
using (ModelMyDemo hie = new ModelMyDemo())
{
try
{
int id = Convert.ToInt16(hotel.Id);
HotelInfoEntities info = hie.HotelInfoEntities.Single(p => p.Hotelid == id);
hie.HotelInfoEntities.Remove(info);
hie.SaveChanges();
return true;
}
catch
{
return false;
}
};
}
public bool edit(Hotel hotel)
{
using (ModelMyDemo hie = new ModelMyDemo())
{
try
{
int id = Convert.ToInt16(hotel.Id);
HotelInfoEntities info = hie.HotelInfoEntities.Single(p => p.Hotelid == id);
info.Hotelname = hotel.Name;
info.Hoteldesc = hotel.description;
info.Hotelprice = hotel.price;
info.Hotelpicture = hotel.picture;
hie.SaveChanges();
return true;
}
catch
{
return false;
}
};
}
public Hotel find(string id)
{
int hid = Convert.ToInt16(id);
using (ModelMyDemo hie = new ModelMyDemo())
{
return hie.HotelInfoEntities.Where(pe => pe.Hotelid == hid).Select(pe => new Hotel
{
Id = pe.Hotelid,
Name = pe.Hotelname,
description = pe.Hoteldesc,
price = pe.Hotelprice,
picture = pe.Hotelpicture
}).First();
};
}
public List<Hotel> findall()
{
//var imagesrc = string.Format("data:image/jpeg;base64,{0}", base64);
using (ModelMyDemo hie = new ModelMyDemo())
{
return hie.HotelInfoEntities.Select(pe => new Hotel
{
Id = pe.Hotelid,
Name = pe.Hotelname,
description = pe.Hoteldesc,
price = pe.Hotelprice,
picture = pe.Hotelpicture
// picture = pe.Hotelpicture
}).ToList();
};
}
}
}

at first we need an object in order to deserilize the the result in it.
public class RootObject
{
public int Id { get; set; }
public string Name { get; set; }
public string description { get; set; }
public List<byte> picture { get; set; }
}
now all we need is to deserilize the json result in to the object. but your json is twice serilized so you need to deserilized it twice like this:
public RootObject findall()
{
try
{
var webClient = new WebClient();
var json = webClient.DownloadString(BASE_URL + "findall");
return JsonConvert.DeserializeObject<RootObject[]>(json);
}
catch
{
return null;
}
}

Related

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.

c# JsonConvert.DeserializeObject<List<Movie>>(content) doesn't work if return JSON is nested

I'm new to xamarin forms. i'm using a third party api to retrieve a list of movies based on search text of the title. The third party movie api I'm using is below
[movie api][1]
http://www.omdbapi.com/?apikey==*******&s=man
This returns JSON data as below
{"Search":[{"Title":"Iron Man","Year":"2008","imdbID":"tt0371746","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTczNTI2ODUwOF5BMl5BanBnXkFtZTcwMTU0NTIzMw##._V1_SX300.jpg"},{"Title":"Iron Man 3","Year":"2013","imdbID":"tt1300854","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMjE5MzcyNjk1M15BMl5BanBnXkFtZTcwMjQ4MjcxOQ##._V1_SX300.jpg"},{"Title":"Iron Man 2","Year":"2010","imdbID":"tt1228705","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTM0MDgwNjMyMl5BMl5BanBnXkFtZTcwNTg3NzAzMw##._V1_SX300.jpg"},{"Title":"Man of Steel","Year":"2013","imdbID":"tt0770828","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMTk5ODk1NDkxMF5BMl5BanBnXkFtZTcwNTA5OTY0OQ##._V1_SX300.jpg"},{"Title":"Spider-Man","Year":"2002","imdbID":"tt0145487","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BZDEyN2NhMjgtMjdhNi00MmNlLWE5YTgtZGE4MzNjMTRlMGEwXkEyXkFqcGdeQXVyNDUyOTg3Njg#._V1_SX300.jpg"},{"Title":"Ant-Man","Year":"2015","imdbID":"tt0478970","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMjM2NTQ5Mzc2M15BMl5BanBnXkFtZTgwNTcxMDI2NTE#._V1_SX300.jpg"},{"Title":"The Amazing Spider-Man","Year":"2012","imdbID":"tt0948470","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMjMyOTM4MDMxNV5BMl5BanBnXkFtZTcwNjIyNzExOA##._V1_SX300.jpg"},{"Title":"Spider-Man 2","Year":"2004","imdbID":"tt0316654","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BMzY2ODk4NmUtOTVmNi00ZTdkLTlmOWYtMmE2OWVhNTU2OTVkXkEyXkFqcGdeQXVyMTQxNzMzNDI#._V1_SX300.jpg"},{"Title":"Spider-Man: Homecoming","Year":"2017","imdbID":"tt2250912","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BNTk4ODQ1MzgzNl5BMl5BanBnXkFtZTgwMTMyMzM4MTI#._V1_SX300.jpg"},{"Title":"Spider-Man 3","Year":"2007","imdbID":"tt0413300","Type":"movie","Poster":"https://m.media-amazon.com/images/M/MV5BYTk3MDljOWQtNGI2My00OTEzLTlhYjQtOTQ4ODM2MzUwY2IwXkEyXkFqcGdeQXVyNTIzOTk5ODM#._V1_SX300.jpg"}],"totalResults":"10750","Response":"True"}
with three parts in the JSON data -"Search","totalResult" and "Response"
I need to access the data in the "Search" section and deserialised that to my POCO class Movie. How should I do it?
My POCO class for Movie is below
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;
namespace NetflixRouletteApp.Models
{
public class Movie
{
[JsonProperty("Title")]
public string Title { get; set; }
[JsonProperty("Year")]
public int Year { get; set; }
[JsonProperty("Released")]
public DateTime Released { get; set; }
[JsonProperty("Rated")]
public string Rated { get; set; }
[JsonProperty("Runtime")]
public string Runtime { get; set; }
[JsonProperty("Genre")]
public string Genre { get; set; }
[JsonProperty("Director")]
public string Director { get; set; }
[JsonProperty("Writer")]
public string Writer { get; set; }
[JsonProperty("Actors")]
public string Actors { get; set; }
[JsonProperty("Plot")]
public string Plot { get; set; }
[JsonProperty("Language")]
public string Language { get; set; }
[JsonProperty("Country")]
public string Country { get; set; }
[JsonProperty("Awards")]
public string Awards { get; set; }
[JsonProperty("Poster")]
public string Poster { get; set; }
[JsonProperty("Type")]
public string mtype { get; set; }
}
}
MovieService.cs is
using NetflixRouletteApp.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using RestSharp;
using RestSharp.Authenticators;
using System.Threading;
using System.Net.Http.Headers;
using Newtonsoft.Json.Linq;
namespace NetflixRouletteApp.Services
{
public class MovieService
{
public static readonly int MinSearchLength = 3;
private const string Url = "http://www.omdbapi.com/?apikey=d09e0406";
private HttpClient _client = new HttpClient();
public static Exception CreateExceptionFromResponseErrors(HttpResponseMessage response)
{
var httpErrorObject = response.Content.ReadAsStringAsync().Result;
// Create an anonymous object to use as the template for deserialization:
var anonymousErrorObject =
new { message = "", ModelState = new Dictionary<string, string[]>() };
// Deserialize:
var deserializedErrorObject =
JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject);
// Now wrap into an exception which best fullfills the needs of your application:
var ex = new Exception();
// Sometimes, there may be Model Errors:
if (deserializedErrorObject.ModelState != null)
{
var errors =
deserializedErrorObject.ModelState
.Select(kvp => string.Join(". ", kvp.Value));
for (int i = 0; i < errors.Count(); i++)
{
// Wrap the errors up into the base Exception.Data Dictionary:
ex.Data.Add(i, errors.ElementAt(i));
}
}
// Othertimes, there may not be Model Errors:
else
{
var error =
JsonConvert.DeserializeObject<Dictionary<string, string>>(httpErrorObject);
foreach (var kvp in error)
{
// Wrap the errors up into the base Exception.Data Dictionary:
ex.Data.Add(kvp.Key, kvp.Value);
}
}
return ex;
}
public async Task<IEnumerable<Movie>> FindMoviesByActor(string title)
{
_client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await _client.GetAsync($"{Url}&s={title}");
response.EnsureSuccessStatusCode();
try
{
if (response.StatusCode == HttpStatusCode.NotFound)
return Enumerable.Empty<Movie>();
var content = response.Content.ReadAsStringAsync().Result;
List<Movie> movies = JsonConvert.DeserializeObject<List<Movie>>(content);
movies.ForEach(Console.WriteLine);
return movies;
}
catch {
// Unwrap the response and throw as an Api Exception:
var ex = CreateExceptionFromResponseErrors(response);
throw ex;
}
}
public async Task<Movie> GetMovie(string title)
{
var response = await _client.GetAsync($"{Url}&t={title}");
if (response.StatusCode == HttpStatusCode.NotFound)
return null;
var content = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<Movie>(content);
}
}
}
MoviePage.Xaml
<? xml version = "1.0" encoding = "utf-8" ?>
< ContentPage xmlns = "http://xamarin.com/schemas/2014/forms"
xmlns: x = "http://schemas.microsoft.com/winfx/2009/xaml"
x: Class = "NetflixRouletteApp.Views.MoviesPage" >
< StackLayout >
< SearchBar x: Name = "searchBar"
Placeholder = "Enter value..."
SearchCommand = "{Binding SearchButtonPressed}"
SearchCommandParameter = "{Binding Source={x:Reference searchBar}, Path=Text}" />
< !--< ActivityIndicator IsRunning = "{Binding IsSearching}" /> -->
< Frame x: Name = "notFound" Padding = "20" HasShadow = "False" IsVisible = "False" >
< Label Text = "No movies found matching your search." TextColor = "Gray" ></ Label >
</ Frame >
< ListView x: Name = "moviesListView" ItemSelected = "OnMovieSelected" >
< ListView.ItemTemplate >
< DataTemplate >
< ImageCell ImageSource = "{Binding Poster}"
Text = "{Binding Title}"
Detail = "{Binding Year}" ></ ImageCell >
</ DataTemplate >
</ ListView.ItemTemplate >
</ ListView >
</ StackLayout >
</ ContentPage >
MoviePage.xaml.cs
using NetflixRouletteApp.Models;
using NetflixRouletteApp.Services;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace NetflixRouletteApp.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MoviesPage : ContentPage
{
private MovieService _movieService = new MovieService();
// Note that IsSearching is a bindable property. This is required for
// binding ActivityIndicator's IsRunning property. If we do not define
// IsSearching as a bindable property, its initial value (false) will
// be used to set ActivityIndicator.IsRunning. Later when we change
// the value of IsSearching, ActivityIndicator will be unaware of this.
// So, we need to implement it as a bindable property.
//private BindableProperty IsSearchingProperty = BindableProperty.Create("IsSearching",
// typeof(bool), typeof(MoviesPage), false);
public ICommand SearchButtonPressed { private set; get; }
public MoviesPage()
{
BindingContext = this;
SearchButtonPressed = new Command<string>(HandleSearchPressed);
InitializeComponent();
}
async void HandleSearchPressed(string searchText)
{
if (searchText == null)
return;
await FindMovies(title: searchText);
}
async Task FindMovies(string title)
{
try
{
var movies = await _movieService.FindMoviesByActor(title);
moviesListView.ItemsSource = movies;
moviesListView.IsVisible = movies.Any();
notFound.IsVisible = !moviesListView.IsVisible;
}
catch (Exception)
{
await DisplayAlert("Error", "Could not retrieve the list of movies.", "OK");
}
}
async void OnTextChanged(object sender, TextChangedEventArgs e)
{
if (e.NewTextValue == null)
return;
await FindMovies(title: e.NewTextValue);
}
async void OnMovieSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem == null)
return;
var movie = e.SelectedItem as Movie;
moviesListView.SelectedItem = null;
await Navigation.PushAsync(new MovieDetailsPage(movie));
}
}
}
go to json2csharp.com and paste your json, it will generate this C# class
public class Movie {
public string Title { get; set; }
public string Year { get; set; }
public string imdbID { get; set; }
public string Type { get; set; }
public string Poster { get; set; }
}
public class Root {
public List<Movie> Search { get; set; }
public string totalResults { get; set; }
public string Response { get; set; }
}
then deserialize the response in your service layer
Root root = JsonConvert.DeserializeObject<Root>(content);
List<Movie> Movies = root.Search;

Xamarin JSON Deserialize

I created a HTTPWebRequest to check if the username and password of the user is correct. If the username and password of the user is correct it will return a JSON Array with the ContactID of the user. I tried to deserialize the JSON but I failed to get the actual data. I want to get the Contact id and send the data to a variable of the next page.
The output of the JSON when the username and password is correct:
[{"ContactID":"1"}]
My code:
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Net;
using System.Text;
using System.Windows.Input;
using TBSMobileApplication.Data;
using TBSMobileApplication.View;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace TBSMobileApplication.ViewModel
{
public class LoginPageViewModel : INotifyPropertyChanged
{
void OnProperyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public string username;
public string password;
public string Username
{
get { return username; }
set
{
username = value;
OnProperyChanged(nameof(Username));
}
}
public string Password
{
get { return password; }
set
{
password = value;
OnProperyChanged(nameof(Password));
}
}
public ICommand LoginCommand { get; set; }
public LoginPageViewModel()
{
LoginCommand = new Command(OnLogin);
}
public void OnLogin()
{
if (string.IsNullOrEmpty(Username) || string.IsNullOrEmpty(Password))
{
MessagingCenter.Send(this, "Login Alert", Username);
}
else
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
var link = "http://192.168.1.25:7777/TBS/test.php?User=" + Username + "&Password=" + Password;
var request = HttpWebRequest.Create(string.Format(#link));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
{
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
}
else
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var usr = JsonConvert.DeserializeObject(content);
App.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true);
}
}
}
}
}
else
{
MessagingCenter.Send(this, "Not Connected", Username);
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
Modify your code else block like below
if (content.Equals("[]") || string.IsNullOrWhiteSpace(content) || string.IsNullOrEmpty(content))
{
MessagingCenter.Send(this, "Http", Username);
}
else
{
var response = JsonConvert.DeserializeObject<List<LoggedInUser>>(content);
var contactId=response[0].ContactID;
//response have your ContactID value. Try to debug & see.
App.Current.MainPage.Navigation.PushAsync(new DatabaseSyncPage(), true);
}
Create one another public class to deserialize your response
public class LoggedInUser
{
public string ContactID { get; set; }
}
If you have more than 1 record in result(as you asked this in comment below)
you can get them using loops
for (int i = 0; i < response.Count; i++)
{
var item = response[i];
var contactId = item.ContactId;
}
Hope it help you.
JSON Response object is not looking standard format for output result. Whatever for JSON deserialization you should create separate class as per below code.
public class RootObject
{
public string ContactID { get; set; }
}
Public Void ServiceRequest()
{
var content = reader.ReadToEnd();
if(!String.IsNullOrEmpty(content)
{
var response = JsonConvert.DeserializeObject<RootObject>(content);
}
}
I hope it will be useful.

BSON Object Being Partially Deserialized

I'm trying to deserialize a BSON HTTP Response Message from a Web API call into a custom type.
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:1234");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/bson"));
HttpResponseMessage result;
result = await client.GetAsync("/endpoint/");
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
new BsonMediaTypeFormatter()
};
if (result.IsSuccessStatusCode)
{
try
{
RootObject res = await result.Content.ReadAsAsync<RootObject>(formatters);
}
catch (Exception e)
{
}
}
I know the Web API is returning BSON, I checked through Fiddler and the above code actually does deserialize most things correctly in the RootObject. It appears that all of the derived classes are not being deserialized and are just being input into the object as null. Here is an example of a derived class that is not being deserialized.
RootObject.Events.Teams.Linescores
RootObject
[DataContract(Namespace = "", Name = "RootObject")]
[Serializable]
public class RootObject: infoBase
{
[DataMember(EmitDefaultValue = false, Order = 30)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 30)]
public IEnumerable<eventInfo> events { get; set; }
public RootObject() { }
}
Events Object
[DataContract(Namespace = "", Name = "event")]
[Serializable]
[KnownType(typeof(subEventTeam))]
public class eventInfo : infoBase
{
[DataMember(EmitDefaultValue = false, Order = 170)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 170)]
public List<eventTeamBase> teams { get; set; }
public eventInfo() { }
}
Teams Base and Specific Team Type
[DataContract(Namespace = "", Name = "team")]
[Serializable]
[KnownType(typeof(bbLinescoreInfo))]
public class eventTeamBase : infoBase {
[DataMember(Order = 20)]
[JsonProperty(Order = 20)]
public string location { get; set; }
[DataMember(Order = 30, EmitDefaultValue = false)]
[JsonProperty(Order = 30, NullValueHandling = NullValueHandling.Ignore)]
public string nickname { get; set; }
[DataMember(EmitDefaultValue = false, Name = "linescores", Order = 130)]
[JsonProperty(NullValueHandling = NullValueHandling.Ignore, Order = 130)]
public IEnumerable<linescoreBase> linescores { get; set; }
public eventTeamBase() { }
}
[DataContract(Namespace = "", Name = "team")]
[Serializable]
public class subEventTeam : eventTeamBase
{
public subEventTeam () { }
}
Linescore Base and Specific Object
[DataContract(Name = "linescores", Namespace = "")]
[Serializable]
[KnownType(typeof(subLinescoreInfo))]
public class linescoreBase : infoBase
{
public bool isProcessing = false;
public int teamId { get; set; }
public linescoreBase() { }
}
[DataContract(Name = "linescores", Namespace = "")]
[Serializable] public class subLinescoreInfo : linescoreBase
{
[DataMember]
public int inning { get; set; }
[DataMember]
public int? score { get; set; }
public subLinescoreInfo() { };
}
Here is the deserialized (and then re-serialized) part of the response that isn't working output into JSON.
{
"status":"OK",
"recordCount":1,
"RootObject":[
{
"events":[
{
"teams":[
{
"location":"Tallahassee",
"nickname":"Razors",
"linescores":[
{},{},{},{},{},{},{},{}]
}
}
}
}
So as you can see, it is filling in some information correctly (There is a lot more, I've cut down significantly just to illustrate the problem). But the linescores are returning null. As mentioned, the data is returning correctly and it is not null.
I feel like I'm doing something wrong with the known types and I've tried numerous combinations of putting them in different places and the results don't change. Any help would greatly appreciated.
After much searching and trying wrong things, I found a similar solution in another thread.
JSON Solution
I solved this by doing pretty much that exact same thing but with BSON instead of JSON.
This is the code that I needed to add in the global config file of the Web API
BsonMediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
bsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
bsonFormatter.AddQueryStringMapping("accept", "bson", "application/bson");
GlobalConfiguration.Configuration.Formatters.Add(bsonFormatter);
And this code went into the client.
BsonMediaTypeFormatter bsonFormatter = new BsonMediaTypeFormatter();
bsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;
MediaTypeFormatter[] formatters = new MediaTypeFormatter[] {
bsonFormatter
};
Everything else remained the same and was deserialized without incident.

MVC3 with JsonFilterAttribute doesn't work anymore

This code was working just fine before i moved to MVC3 ...
[HttpPost]
[ActionName("GetCommentListForServiceCall")]
[UrlRoute(Path = "mobile/servicecalls/{id}/comments", Order=1)]
[UrlRouteParameterConstraint(Name = "id", Regex = #"\d+")]
[OutputCache(CacheProfile = "MobileCacheProfile")]
[JsonFilter(JsonDataType = typeof(ServiceCallCommentNewDTO), Param = "comment")]
public JsonNetResult CreateCommentForServiceCall(int id, ServiceCallCommentNewDTO comment)
{
ServiceCallComment entity = coreSvc.SaveServiceCallComment(id, 0, comment.CategoryId, comment.Comment);
SetResponseCode(HttpStatusCode.Created);
SetContentLocation(string.Format("mobile/servicecalls/{0}/comments/{1}", id.ToString(), entity.Id.ToString()));
return new JsonNetResult(entity); ;
}
here is the JSonFilterAttribute code
public class JsonFilterAttribute : ActionFilterAttribute
{
public string Param { get; set; }
public Type JsonDataType { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if (filterContext.HttpContext.Request.ContentType.Contains("application/json"))
{
string inputContent;
using (var sr = new StreamReader(filterContext.HttpContext.Request.InputStream))
{
inputContent = sr.ReadToEnd();
}
var result = JsonConvert.DeserializeObject(inputContent, JsonDataType, new JsonSerializerSettings{TypeNameHandling = TypeNameHandling.All});
filterContext.ActionParameters[Param] = result;
}
}
}
Now The JsonFilter doesn't get the object anymore. It always return null ?
Is there something i have to do in MVC3 ?
You no longer need this attribute as ASP.NET MVC 3 has this functionality built-in.