I'm creating rest api MVC, to make model i'm using entity framework and to make my controller i'm using scaffolding item, i have my views(razor) but i dont know how to get data o how to post data from my view to my controller.
Somebody help me please!
Model
public partial class Information
{
public int ID { get; set; }
public string name { get; set; }
public string address { get; set; }
public string phone { get; set; }
public string Email { get; set; }
}
Controller
private BaseNegociosEntities db = new BaseNegociosEntities();
// GET api/Informacion
public IEnumerable<Information> GetInformations()
{
return db.Information.AsEnumerable();
public HttpResponseMessage PostInformacion(Informacion informacion)
{
if (ModelState.IsValid)
{
db.Informacion.Add(informacion);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, information);
response.Headers.Location = new Uri(Url.Link("DefaultApi", new { id = information.Id_Informacion }));
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
You have to create list in model.
List<Information> list1=new List<Information>{get;set;}
Then need to feed data into that list from controller. So you can send your Model's list to view. Then you can serialize your list to xml or json.
Related
I am practicing with web api. My goal is to create a Get endpoint, which receive data from an external api, then return a different result. external api link: https://www.themealdb.com/api/json/v1/1/search.php?f=a, The external api data looks like:
{
"meals": [
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"strDrinkAlternate": null,
"strCategory": "Dessert",
.....
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
....
}
]
}
I want my endpoint provide a different result like the following:
[
{
"idMeal": "52768",
"strMeal": "Apple Frangipan Tart",
"ingredients": ["Apple", "sugar"...]
},
{
"idMeal": "52893",
"strMeal": "Apple & Blackberry Crumble",
"ingredients": ["Apple", "sugar"...]
}
]
The following code is what I attempted so far, It's working, but the moment I changed property ingredient1 from public to private, that ingredient in list will become null, also, there are so many ingredients, some of them are null by default, I don't want to add them if they are null, how can I fix these two issues? Thanks a lot
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Mvc;
using RestSharp;
namespace testAPI.Controllers;
public class Content
{
[JsonPropertyName("meals")]
public List<Meal> Meals { get; set; }
}
public class Meal
{
[JsonPropertyName("idMeal")]
public string MealId { get; set; }
[JsonPropertyName("strMeal")]
public string Name { get; set; }
[JsonPropertyName("strIngredient1")]
public string Ingredient1 { get; set; }
[JsonPropertyName("strIngredient2")]
public string Ingredient2 { get; set; }
[JsonPropertyName("strIngredient20")]
public string Ingredient20 { get; set; }
public List<string> Ingredients
{
get { return new List<string>(){Ingredient1, Ingredient2, Ingredient20};}
}
}
[ApiController]
[Route("api/[controller]")]
public class DishesController : ControllerBase
{
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
var mealList = JsonSerializer.Deserialize<Content>(response.Content);
return Ok(mealList.Meals);
}
}
To address the problems one at a time...
the moment I changed property ingredient1 from public to private, that ingredient in list will become null
Changing the access modifier affects both deserialization and serialization, so this cannot be used to only stop it from serializing the property. You should split the data models up into what you want to receive and what you want to expose/return.
there are so many ingredients, some of them are null by default, I don't want to add them if they are null
Addition to splitting up the data models you can handle this when mapping from one model to the other.
The following code should fix both issues:
namespace TheMealDb.Models
{
// These are the models you receive from TheMealDb
// JSON converted to classes with https://json2csharp.com/
public class Root
{
public List<Meal> meals { get; set; }
}
public class Meal
{
public string idMeal { get; set; }
public string strMeal { get; set; }
public string strIngredient1 { get; set; }
public string strIngredient2 { get; set; }
public string strIngredient3 { get; set; }
// Other properties removed for brevity...
}
}
namespace Internal.Models
{
// This is the model you want to return from your controller action
public class Meal
{
[JsonPropertyName("id")] // No need to use the same name as from themealdb
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("ingredients")]
public List<string> Ingredients { get; set; }
}
}
Now, to fetch, map and return the data in your controller action:
[HttpGet]
public async Task<IActionResult> GetAllRecipes()
{
var client = new RestClient($"https://www.themealdb.com/api/json/v1/1/search.php?s=");
var request = new RestRequest();
var response = await client.ExecuteAsync(request);
// Deserialize to the "TheMealDb" models
var mealList = JsonSerializer.Deserialize<TheMealDb.Models.Root>(response.Content);
// Map to your own models
var myMealList = mealDbList.meals?.Select(MapToInternal);
return Ok(myMealList);
}
// Map "TheMealDb" model to your own model
private Internal.Models.Meal MapToInternal(TheMealDb.Models.Meal externalMeal)
{
return new Internal.Models.Meal
{
Id = externalMeal.idMeal,
Name = externalMeal.strMeal,
Ingredients = new []
{
externalMeal.strIngredient1,
externalMeal.strIngredient2,
externalMeal.strIngredient3,
// ...
}
// Remove empty/null ingredients
.Where(ingr => !string.IsNullOrEmpty(ingr))
.ToList()
};
}
See the code in action.
I got an error while getting json data from POST method, am I doing something wrong
C# Code:
public IActionResult signupapi(UserSignUp user)
{
var model = new Models.SignUpModelAPI(HttpContext);
if (user == null)
{
return Content(model.ResponseJsonText(false, string.Format(model.Language("empty"),
HttpContext.Request.Method, HttpContext.Request.Path.Value), Class.CodeResponse.ERROR), new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
if (!model.isAllowMethod("POST"))
{
return Content(model.ResponseJsonText(false,string.Format(model.Language("notallowmethod"),
HttpContext.Request.Method,HttpContext.Request.Path.Value),Class.CodeResponse.ERROR),new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
}
return Content(JsonConvert.SerializeObject(user));
}
public class UserSignUp
{
public string fullname { get; set; }
public string username { get; set; }
public string email { get; set; }
public string password { get; set; }
}
And this is the result when i try on reqbin every value i get is null
You need to add FromBody attribute to get your data for the POST operation:
public IActionResult signupapi([FromBody]UserSignUp user)
You can read more on parameter binding on MSDN docs.
Currently I am doing an API call via jQuery, my question is, is there away to do this call in C# or away to convert the results of an API call to an ASP.NET List of Model Objects?
Here is my Model
public class TeamStatsClass
{
public int id { get; set; }
public string name { get; set; }
public string league { get; set; }
public string division { get; set; }
}
And here is my current ajax call
$.ajax({
url: "https://statsapi.web.nhl.com/api/v1/teams?sportId=1",
success: function (data) {
for (var team of data.teams) {
console.log(team.name);
}
}
});
UPDATE
I changed my classes to look like so:
public class StatsTeamsClass
{
public IEnumerable<Teams> teams { get; set; }
public string copyright { get; set; }
}
public class Division
{
public int id { get; set; }
public string name { get; set; }
public string link { get; set; }
}
public class Teams
{
public int id { get; set; }
public string name { get; set; }
public string link { get; set; }
public League league { get; set; }
public Division division { get; set; }
}
and created this method which indeeds puts the results in model object:
public async System.Threading.Tasks.Task<StatsTeamsClass> GetTeams()
{
HttpClient Http = new HttpClient();
var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
StatsTeamsClass teams = JsonConvert.DeserializeObject<StatsTeamsClass>(json);
return teams;
}
But when I try to call this method in another controller, it just hangs there, no error, no nothing, I am assuming it will just time out after a while
public class HomeController : Controller
{
APIController webService = new APIController();
public ActionResult Index()
{
var item = webService.GetTeams().Result.teams;
return View();
}
}
(GetTeams() is inside the controller APIController)
So what would be the proper way to A. get the results of an API in object model and then call those results?
The controller action needs to be made async as well to avoid mixing async-await and blocking calls like .Result or .Wait() that could potentially cause deadlocks.
Reference Async/Await - Best Practices in Asynchronous Programming
public class HomeController : Controller {
APIController webService = new APIController();
public async Task<ActionResult> Index() {
var model = await webService.GetTeams();
var teams = model.teams;
return View();
}
}
Assuming APIController is an actual ApiContoller
public class APIController : ApiController {
//Your original code
public async Task<StatsTeamsClass> GetTeams() {
HttpClient Http = new HttpClient();
var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
StatsTeamsClass teams = JsonConvert.DeserializeObject<StatsTeamsClass>(json);
return teams;
}
//...
}
I would suggest not calling APIController directly like that from the HomeController and instead extract the GetTeams() method out into a reusable service
public class WebService {
static Lazy<HttpClient> http = new Lazy<HttpClient>();
public async Task<T> GetAsync<T>(string url) {
var json = await http.Value.GetStringAsync(url);
return JsonConvert.DeserializeObject<T>(json);
}
public Task<StatsTeamsClass> GetTeamsAsync() {
var url = "https://statsapi.web.nhl.com/api/v1/teams?sportId=1";
return GetAsync<StatsTeamsClass>(url);
}
}
Reference You're using HttpClient wrong
that can be properly used in HomeController
public class HomeController : Controller {
public async Task<ActionResult> Index() {
// Ideally web service should be injected but that topic
// is outside of the scope of the question at the moment.
var webService = new WebService();
var model = await webService.GetTeamsAsync();
var teams = model.teams;
//...
return View(teams);
}
}
The assumption here is that the project is a mixed Asp.Net MVC and Web Api 2+
Index.cshtml
#model IEnumerable<Teams>
#{
ViewBag.Title = "Teams";
}
#if(Model != null && Model.Count() > 0) {
#foreach (var #team in Model) {
<p>#team.name</p>
}
}
Yes, the equivalent in C# would be to use HttpClient. You're best off creating a static instance of the class that you reuse for a particular kind of repeated call:
private static readonly HttpClient Http = new HttpClient();
and then used it from an async method using Newtonsoft.Json like this:
var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
You can then parse this string of JSON into a model class like this:
var model = JsonConvert.DeserializeObject<TeamStatsClass>(json);
As the question is answered by #Daniel above just want to add couple of more points here The json you are getting cannot be directly casted to TeamStatsClass you might have to introduce another base class as teams is the collection in the json you are getting.
Im posting it here to get a clearer view
public class ResponseBaseClass
{
public IEnumerable<TeamStatsClass> teams { get; set; }
public string copyright { get; set; }
}
public class TeamStatsClass
{
public int id { get; set; }
public string name { get; set; }
public Division division { get; set; }
}
public class Division
{
public int id { get; set; }
public string name { get; set; }
public string nameShort { get; set; }
public string link { get; set; }
}
HttpClient Http = new HttpClient();
var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
var model = JsonConvert.DeserializeObject<ResponseBaseClass>(json);
var yourTeamModelObj = model.teams;
I've got a list of objects in JSON that isn't recognized by a WebApi2 controller
The JSON list is the following:
{
"FirstObjectType": [{"Name": "the_name"}],
"SecondObjectType": [{"Label": "01_obj"}, {"Label": "02_obj"}]
}
The Model class is:
public class CompositeObject
{
[JsonProperty("FirstObjectType")]
public List<FirstObject> fo { get; set; }
[JsonProperty("SecondObjectType")]
public List<SecondObject> so { get; set; }
}
The controller is:
public IHttpActionResult PostList([FromBody] CompositeObject jsonList)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
List<FirstObject> fo_list = jsonList.fo;
foreach (var item in fo_list)
{
db.FirstObject.Add(item);
db.SaveChanges();
}
return StatusCode(HttpStatusCode.OK);
}
When I submit the Post action, the controller recognize both lists in CompositeObject jsonList as Null
There is a problem in your model, where names are not being matched. You have to update model as:
public class FirstObjectType
{
public string Name { get; set; }
}
public class SecondObjectType
{
public string Label { get; set; }
}
public class RootObject
{
public List<FirstObjectType> FirstObjectType { get; set; }
public List<SecondObjectType> SecondObjectType { get; set; }
}
I have assumed that FirstObjectType contains string with name Name and SecondObjectType contains string with name Label. Make sure to use same names for properties of FirstObjectType and SecondObjectType class as in JSON string.
The issue was in the client code because I missed to set the Content-type as application/json in the header section.
In this way the WebApi server doesn't recognize in the right way the JSON object (I think that the server look for a x-www-form-urlencoded type)
So, the code above is right, but I have found another solution
In the WebApi controller:
using Newtonsoft.Json.Linq;
public IHttpActionResult PostList([FromBody] JObject ReceivedObjectsList)
{
var receivedLists = ReceivedObjectsList.Properties();
List<FirstObject> fo = ReceivedObjectsList["FirstObjectType"].ToObject<List<FirstObject>>();
List<SecondObject> so = ReceivedObjectsList["SecondObjectType"].ToObject<List<SecondObject>>();
...
}
The software that I'm developing uses ASP.NET MVC and Telerik Extensions for ASP.NET MVC frameworks.
The problem that I have is that it is very easy to send unintended data in JSON format to the client browser, if a Telerik grid uses ajax binding.
For example, the following action, when used with a Telerik Grid view which uses ajax binding, will result in all of the Client class's properties being serialized to JSON.
Model class:
public class Client
{
public int ClientId {get; set; }
public string Name { get; set; }
public string Address { get; set; }
...
public string SocialSecurityNumber { get; set; }
public string BankAccountNumber { get; set; }
}
Controller:
[GridAction]
public ActionResult Index()
{
IEnumerable<Client> clients = clientRepository.GetClients();
return View(new GridModel(clients));
}
View:
#Html.Telerik().Grid<Client>()
.Columns(columns =>
{
columns.Bound(client => client.ClientId);
columns.Bound(client => client.Name);
columns.Bound(client => client.Address);
}
.DataBinding(db => db.Ajax().Select("Index"))
Even though SocialSecurityNumber and BankAccountNumber are not bound to the grid, the JSON will contain them, and the data will be viewable with developer tools such as Firebug.
JSON:
{
"data":[
{
"ClientId":101,
"Name":"Matt",
"Address":"Example Road 12",
...
"SocialSecurityNumber":"1234-5678"
"BankAccountNumber":"12345678",
},
{
"ClientId":102,
"Name":"Karen",
"Address":"Example Road 27",
...
"SocialSecurityNumber":"5678-1234"
"BankAccountNumber":"87654321",
}
],
"total":2
}
What solution would you use to make sure that only the intended properties are serialized and sent to the client browser?
Create a ViewModel that contains the exact properties you want to expose and use that instead of the object you are currently using:
public class ClientModel
{
public int ClientId {get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
var model = from c in clients
select new ClientModel {
...
};
return View(new GridModel(model));
you can return list of dynamic object like this -
[GridAction]
public ActionResult Index()
{
IEnumerable<Client> clients = clientRepository.GetClients();
return View(new GridModel(clients.Select(a => new { ClientId = a.ClientId, Name = a.Name, Address = a.Address })));
}