Frombody in API controller does not properly pull data - c#

In My code, I am trying to receive an API containing a JSON body containing data, I have designed a DataInfo Model class and used the [FromBody] function to translate the data.
My issue is that the data being pulled which I have formatted to be ints and doubles, is being pulled as a series of 0s
My Data Info Model Class:
public class DataInfo
{
[JsonProperty("ID")]
public int JId { get; set; }
[JsonProperty("Temp")]
public double JTemperature { get; set; }
[JsonProperty("Humidity")]
public double JHumidity { get; set; }
[JsonProperty("WindSpeed")]
public double JWindSpd { get; set; }
[JsonProperty("SoilMoisture")]
public double JSM { get; set; }
}
}
My Api Controller:
[HttpPatch("update")]
public async Task<ActionResult<Device>> Update([FromBody] DataInfo data)
{
var dev = await _dbContext.Device.Where(x => x.Id == data.JId).FirstOrDefaultAsync();
if (dev == null)
{
return BadRequest("no device found");
}
dev.Humidity = data.JHumidity;
dev.Temp = data.JTemperature;
dev.WindSpeed = data.JWindSpd;
dev.SoilMoisture = data.JSM;
dev.DateTime = DateTime.Now;
_dbContext.SaveChanges();
return Ok(dev);
}
My JsonBody:
{
"ID":"1",
"Temp":"37",
"Humidity":"42",
"WindSpeed":"12",
"SoilMoisture":"14"
}
I also Used this JSON body and got the same result:
{
"data":{
"ID":"1",
"Temp":"37",
"Humidity":"42",
"WindSpeed":"12",
"SoilMoisture":"14"
}
}
When I run the API call in postman, I receive a 400 error with the text that correlates to an invalid Device ID, when I had it send the Device ID and other data points within the class, all were returned as 0s.
The API call is going to the correct controller, however the JSON data seems only to be exsisting as 0s even though I assign it with the JsonPropertyName or JsonProperty assignment in the model class.

I found the issue to be in My Using inputs. I was including Newtonsoft which was conflicting with system.
using BlazorApp1.Data;
using BlazorApp1.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.EntityFrameworkCore;
//using Newtonsoft.Json;
using System.Net;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;

Related

Unity Newtonsoft is started to not working on iPhone and iPad

I was using using Newtonsoft.Json; to convert json to Objects in Unity like this:
var response = JsonConvert.DeserializeObject<Response<string>>(jsonData);
I don't know what I've changed in project but it stopped to work properly on iPad and iPhone devices. It currently works well on macOS while I am running the project on Unity. Where should I look? What can I do? Any suggesstions?
I tried to do this convertion in also JsonUtility but it did not work in macOS too.
Class Example:
using System;
using Newtonsoft.Json;
[Serializable]
public class Response<T>
{
[JsonProperty("status")]
public bool Status { get; set; }
[JsonProperty("data")]
public T Data { get; set; }
public Response()
{ }
public Response(bool status, T data)
{
Status = status;
Data = data;
}
}
and the example json is:
{"status":true,"data":"someStringValue"}

Getting data from ASP.NET Core API

I am working on Market and Financial News app.I took the API from https://www.marketaux.com/. I am trying to display the news from the site into my home page. I have created a model file and controller in ASP.NET Core web app file. In controller file, I get an error in response.data part as its showing response doesn't have data object whereas when I print the output of response.Content, it has data object. Can you tell me how to solve this and get access to the data from the API so that I can display it on my Home page?
Controller class:
using System.Runtime.CompilerServices;
using Azure.Core;
using MarketNews.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MySql.Data.MySqlClient;
using MySqlX.XDevAPI;
using Newtonsoft.Json;
using RestSharp;
namespace MarketNews.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class NewsController : ControllerBase
{
[HttpGet]
public News[] GetNews()
{
List<News> news = new List<News>();
RestClient client = new RestClient("https://api.marketaux.com/v1/news/all");
// client.Timeout = -1;
RestRequest request = new RestRequest("News",Method.Get);
request.AddQueryParameter("api_token", "qIWtsblpK93oeo23o87egUGBoVmVaqkl4fdHRTEc");
request.AddQueryParameter("symbols", "aapl,amzn");
request.AddQueryParameter("limit", "50");
RestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
if (response != null)
{
foreach (var article in response.data)
{
news.Add(new News
{
Title = article.title,
Description = article.description,
Url = article.url,
Url_Image = article.image_url,
Published_At = article.published_at
});
}
}
return news.ToArray();
}
}
}
Model class
namespace MarketNews.Models
{
public class News
{
public string Title;
public string Description;
public string Url;
public string Url_Image;
public DateTime Published_At;
}
}
I wanted to get data from the API and display it on my Home Page. I used RestClient and RestRequest to get response and then from response. I got the output when response.Content printed to console, it is working and it gave me a json file as output. In foreach loop when I tried to set the response data to the model data I created, it's showing response.data doesn't exist.
I want to know what is wrong here or is there any other method to get the data from the API?
Api: Website link
From RestSharp documentation, the Execute() method does support for a generic type.
Execute<T>(IRestRequest request)
Note that, this method is deprecated. You shall look for the method below:
ExecuteAsync<T>(IRestRequest request, CancellationToken cancellationToken)
and revamp your API action to support asynchronous operation.
From the response data shared in the link, you need a Root object which contains the data property with the List<New> type.
Define the data model class for the response.
using System.Text.Json;
public class Root
{
[JsonPropertyName("data")]
public List<News> Data { get; set; }
}
public class News
{
[JsonPropertyName("title")]
public string Title { get; set; }
[JsonPropertyName("description")]
public string Description { get; set; }
[JsonPropertyName("url")]
public string Url { get; set; }
[JsonPropertyName("image_url")]
public string Url_Image { get; set; }
[JsonPropertyName("published_at")]
public DateTime Published_At { get; set; }
}
For the caller, specify the generic type as Root. Next extract the data property from the response with response.Data.Data.
RestResponse<Root> response = client.Execute<Root>(request);
// asynchronous way
// RestResponse<Root> response = await client.ExecuteAsync<Root>(request);
if (response != null)
news = response.Data.Data;

C# ASP.NET | Is there any point in me using a model class when saving data to MongoDB?

I have begun writing an ASP.NET Web API for an app that I am building. I have set up a MongoCRUD.cs class to save data from POST requests made by the app to a MongoDB database (and other CRUD actions).
I (following a beginner tutorial), also set up a Submission.cs model class to act as a blueprint for the objects I wanted to save to the database. However, now that I have implemented the InsertRecord() method in MongoCRUD.cs, I cannot see a use for this model.
MongoCRUD.cs:
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace WebAPI.Services
{
public class MongoCRUD
{
private IMongoDatabase db;
public MongoCRUD(string database)
{
var client = new MongoClient();
db = client.GetDatabase(database);
}
public void InsertRecord<T>(string table, T record)
{
var collection = db.GetCollection<T>(table);
collection.InsertOne(record);
}
}
}
Submission.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Web;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace WebAPI.Models
{
public class Submission
{
[BsonId]
public string SubId { get; set; }
public string Url { get; set; }
public string Text { get; set; }
}
}
SubmissionsController.cs:
using WebAPI.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using WebAPI.Services;
using System.IO;
using System.Web.Script.Serialization;
namespace WebAPI.Controllers
{
public class SubmissionsController : ApiController
{
MongoCRUD db = new MongoCRUD("myDb");
Submission[] submission = new Submission[] {
new Submission { SubId = "test", Url = "test", Text = "test" };
};
public IEnumerable<Submission> GetAllSubmissions()
{
//add MongoCRUD functionality for load record
return submission;
}
public IHttpActionResult GetSubmission(string id)
{
//add MongoCRUD functionality for load record
return Ok();
}
public IHttpActionResult PostSubmission(object body)
{
//validate body
db.InsertRecord("Submissions", body);
return Ok();
}
}
}
As you can see at PostSubmission(), the body of the POST request can be saved to the database directly, so my question is what is the benefit of using a model such as Submission.cs instead of just using the object type?
I'm having some trouble traversing the body object to access its values (for carrying out validation etc), so my only guess is that using a model makes it easier to access values?
object is the base type for all classes (See - https://learn.microsoft.com/en-us/dotnet/api/system.object?view=netcore-3.1).
C# is an object-orientated language so we try to model classes based on our business domain, this makes it easier to reason about the code.
Like you said you can have models that can be used to validate the incoming data into the controller, also you might want to add extra methods on the models that related to your business domain.
For example
class CreditCard
{
string CardNumber { get;set; }
string Csv { get;set; }
bool ValidateChecksum()
{ }
}

Retrieving records from another SQL Server database - Umbraco

I'm working on a website, where I need to retrieve pricelists, from another database on the same SQL Server as my Umbraco database.
It's a requirement that it has to be in a separate database.
I have made a new connection string Pricelist and used EF database-first.
PriceList repository:
namespace UmbracoCMS.Repository{
using System;
using System.Collections.Generic;
public partial class Prisliste
{
public string Kode { get; set; }
public string Speciale { get; set; }
public string Ydelsesgruppe { get; set; }
public string Gruppe { get; set; }
public string Ydelse { get; set; }
public string Ydelsestekst { get; set; }
public string Anaestesi { get; set; }
public string Indlæggelse { get; set; }
public Nullable<double> Listepris { get; set; }
public Nullable<int> WebSort { get; set; }
public string YdelsesTekstDK { get; set; }
public string Frapris { get; set; }
public Nullable<int> Sortering { get; set; }
}
}
PriceListController class:
using System;
using System.Linq;
using System.Web.Mvc;
using UmbracoCMS.Repository;
namespace UmbracoCMS.Controllers{
public class PriceListController : Umbraco.Web.Mvc.SurfaceController {
[HttpGet]
public PartialViewResult GetPriceList(string contentTitle){
var db = new PricelistContext();
var query = from b in db.Prislistes orderby b.Speciale select b;
Console.WriteLine("records in the database:");
foreach (var item in query)
{
Console.WriteLine(item.Speciale);
}
return PartialView("~/views/partials/PriceList.cshtml");
}
}
}
What I want is to load the prices for a treatment, based on a property on the document type. I'm just not sure how do this in umbraco since I'm fairly new a umbraco.
So when a treatment page is requested, I need to take the property ContentTitle value. Use it to retrieve all records with the same Speciale and display them in a list/table.
With a query
.where(b.Speciale = contentTitle)
It would be great if someone could help a little, or lead me in the right direction.
Also is it possible to do it in the same http request? Or should I use partial view or macros to both get the properties of the document type, from the umbraco database, and the records from the pricelist database at the same time when a user go to the treatment page?
Or is there a better way to do this?
Update:
Thanks a lot, for the great answer Ryios.
I got a question more.
using System;
using System.Linq;
using System.Web.Mvc;
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public ActionResult GetPriceList(string contentTitle)
{
PricelistContext.RunInContext(db =>
{
var result = db.Prislistes.OrderBy(p => p.Speciale);
});
return View(result);
}
}
}
I got it working, so it call the method and the data from the Pricelist Database is shown in:
var result = db.Prislistes.OrderBy(p => p.Speciale);
Now I just need to get the list of prices out to the view again, so I can show a list or table of the prices.
Do you have a suggestion on how I can this in Umbraco. Normally I would return a ViewModel in MVC like:
return View(new ListViewModel(result));
and use it in the view like:
#model Project.ViewModels.ListViewModel
So I can loop through it.
But I want to still have the properties from the the "Home"/"TreatmentPage" Document type.
Should I do it with a partialView or is there a better way?
Solved
I thought I wanted to share it, if anyone else is in a similar situaction.
Controller:
namespace UmbracoCMS.Controllers
{
public class PriceListSurfaceController : Umbraco.Web.Mvc.SurfaceController
{
public PartialViewResult PriceList(string contentTitle)
{
List<Prisliste> result = null;
PricelistContext.RunInContext(db =>
{
result = db.Prislistes.Where(p => p.Speciale == contentTitle)
.OrderBy(p => p.Speciale).ToList();
});
var model = result.Select( pl => new PrislistVm()
{
Speciale = pl.Speciale,
Listepris= pl.Listepris
});
return PartialView(model);
}
}
}
ViewModel:
namespace UmbracoCMS.ViewModels
{
public class PrislistVm
{
public PrislistVm()
{
Results = new List<Prisliste>();
}
public List<Prisliste> Results { get; set; }
public string Speciale { get; set; }
public double listepris { get; set; }
}
}
View/PriceListSurface:
#model IEnumerable<UmbracoCMS.ViewModels.PrislistVm>
#{
ViewBag.Title = "PriceList";
}
<h2>PriceList</h2>
#foreach (var item in Model)
{
#item.Speciale
#item.Listepris
}
Your going to have a memory leak if you load your EF context like that. I recommend creating a method to wrap it for you with a llambda callback. Put it in your context class.
public static void RunInContext(Action<PricelistContext> contextCallBack)
{
PricelistContext dbContext = null;
try
{
dbContext = new PricelistContext();
contextCallBack(dbContext);
}
finally
{
dbContext.Dispose();
dbContext = null;
}
}
//Example Call
PricelistContext.RunInContext(db => {
var result = db.PrisListes.OrderBy(p => p.Speciale);
//loop through your items
});
To get the Value of the DocumentType, it depends on the calling context. Assuming you are using a Razor Template that is attached to the document type, that is associated with a Content Page.
#inherits Umbraco.Web.Mvc.UmbracoTemplatePage
#{
Layout = "ContentPageLayout.cshtml";
}
#* Call GetPriceList on PriceListController with Parameter contentTitle *#
#Html.Action("GetPriceList", "PriceListSurface", new { contentTitle = Model.Content.GetPropertyValue<string>("ContentTitle") });
In the above example, I have created a document type with a property called ContentTitle that is associated with a view called ContentPage. Then I created content in the backoffice Content section called "Home" that uses the document type. Giving me a url like
http://localhost/home
Also, your SurfaceController will not work. Umbraco's logic for mapping the routes for surface controllers has some requirements for your surface controller's naming conventions. You have to end the name of the class with "SurfaceController" and then it get's called PriceListSurfaceController, then it maps the controller with a name of "PriceListSurface".
Here's the documentation for the SurfaceController features.
http://our.umbraco.org/documentation/Reference/Mvc/surface-controllers
Using a surface controller is the right logic. It's not good practice to have your Data Layer code calls in the UmbracoTemplatePage. 1, because RazorTemplates are interpreted/compiled and SurfaceController's are JIT compiled int the dll, so SurfaceController code is WAY faster. 2 Because you can make asynchronous Controller calls in MVC Razor. If it was all in the view it would make it really difficult to convert everything to be asynchronous. It's best to keep server side logic in a controller.
Optionally, you can Hijack an Umbraco route and replace it with a custom controller that doesn't have to inherit from SurfaceController, which makes it possibly to surface content to the browser that is or isn't part of umbraco.
http://our.umbraco.org/documentation/Reference/Mvc/custom-controllers
You can also create a new section in the backoffice to manage your Price List "the ui framework for building one is written against AngularJS"
http://www.enkelmedia.se/blogg/2013/11/22/creating-custom-sections-in-umbraco-7-part-1.aspx

C# JSON.net - Trying to deserialize JSON into C# results in correct number of objects but no properties set

I'm working on a custom add in for excel, I want it to get a list of projects from a remote web service. The JSON is coming back from the web servive to excel, but I'm having trouble turning the JSON into objects in C#.
Here is the AddIn code:
using Microsoft.Office.Tools.Ribbon;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Diagnostics;
using System.Web;
namespace TestAddIn
{
class Project
{
static string currentProject;
static List<Project> validProjects;
public int id { get; set; }
public string name { get; set; }
public int svar_reserved_space { get; set; }
// Set the current project we're working on
internal static void setCurrentProject(string path)
{
Match match = Regex.Match(path, #"^[A-Za-z]:\\(\w+)");
Project.currentProject = match.Groups[1].Value;
foreach (Project validProject in validProjects)
{
RibbonDropDownItem dropDown = Globals.Ribbons.Ribbon1.Factory.CreateRibbonDropDownItem();
dropDown.Label = validProject.name;
if (validProject.name.Equals(Project.currentProject))
{
Globals.Ribbons.Ribbon1.projectComboBox.Items.Add(dropDown);
}
}
}
// Connect to a web service and get a list of valid projects
internal static void getValidProjects()
{
string url = "http://192.168.118.128/projects/json";
WebRequest webRequest;
webRequest = WebRequest.Create(url);
Stream objStream;
objStream = webRequest.GetResponse().GetResponseStream();
StreamReader objReader = new StreamReader(objStream);
string sLine = objReader.ReadLine();
Debug.WriteLine("begin: " + sLine);
validProjects = JsonConvert.DeserializeObject<List<Project>>(sLine);
Debug.WriteLine("end");
}
}
}
When using this json:
[{"Project":{"id":1,"name":"test1","svar_reserved_space":2}},{"Project":{"id":2,"name":"test2","svar_reserved_space":0}}]
I get two Project objects in validProjects but the id and svar_reserver_space are 0, and the name is null. Thoguhts?
This is the easiest with some addins/nuget magic:
Install web essentials in Visual studio
Add the nuget package newtonsoft.json
Copy the JSON output string
Paste JSON as class
And use this code:
WebClient wc = new WebClient();
string json = wc.DownloadString("http://192.168.118.128/projects/json");
var a = JsonConvert.DeserializeObject<YourGeneratedMainClass>(json);
Where YourGeneratedMainClass is a class generated by pasting the json as classes.
If you use the method above, you will probably see that it has a parent object
public class Project
{
public int id { get; set; }
public string name { get; set; }
public int svar_reserved_space { get; set; }
}
public class Parent
{
public Project Project { get; set; }
}
More about it in these two S.O. questions:
Json.net deseralize to a list of objects in c# .net 2.0
Deserialized Object Has All Values Set to Null
I would suspect you need the JSON to look like:
[{"id":1,"name":"test1","svar_reserved_space":2},{"id":2,"name":"test2","svar_reserved_space":0}]
In order to use the default Json deserialization.

Categories