I am writing a WebAPICore to return the JSON objects from the database. For unknown reason, the properties are returned as camelCase by default.
I have checked the SQL Script and it does return the correct case for the DataFields. But when I consume the service, the properties of the objects are changed to camelCase automatically.
For example, OfferingID is returned as offeringID
The existing Return JSON object
{
"offeringID": 120842,
"courseCode": "FLTE2A1F/1",
"courseName": "FLT - E2 Certificate in Skills for Working Life (Animals) (QCF)"
}
The format which I want to return
{
"OfferingID": 120842,
"CourseCode": "FLTE2A1F/1",
"CourseName": "FLT - E2 Certificate in Skills for Working Life (Animals) (QCF)"
}
The Model - Offering:
public class Offering
{
[Key]
public int OfferingID { get; set; }
public string CourseCode { get; set; }
public string CourseName { get; set; }
}
My WebAPI Controller Get Method
[HttpGet("{id}")]
public async Task<IActionResult> GetOfferingDetail(int id)
{
var obj = await _context.Offerings.FromSql("dbo.GetOfferingDetail #p0", id).SingleOrDefaultAsync();
if (obj == null)
return NotFound("ID not found");
return new ObjectResult(obj);
}
Configure Services Method in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DbContexts.OakCommonsDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("MyConnection")));
services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()));
var mvccore = services.AddMvc();
mvccore.AddJsonOptions(o => o.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore);
}
Could you please advise me how I could return JSON Objects in the Exact Case as I defined in the Model?
Here is the working code. By default, WebAPI Core is going to use CamelCasePropertyNamesContractResolver(). You need to change it to DefaultContractResolver to render as you defined in the Model.
And DefaultContractResolver is under Newtonsoft.Json.Serialization namespace.
services.AddMvc()
.AddJsonOptions(o => o.SerializerSettings.NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)
.AddJsonOptions(o => o.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver());
Related
I recently updated our project from EF Core 2.2.6 to 6.x (along with and upgrade from .NET core 3.1 to .NET 6) and now I'm get errors like the one stated in the title whenever the query gets even a little complicated. One of those cases is when you add a GroupBy clause. Below is an example of a failing query.
_context.MyTable
.Where(a => a.Name.Contains("service"))
.GroupBy(ss => ss.IsServiceSpecific)
The entire error is:
The LINQ expression 'DbSet< MyTable >()
.Where(a => a.Name.Contains("service"))
.GroupBy(ss => ss.IsServiceSpecific)' could not be translated. Either rewrite the query in a form that can be translated, or switch
to client evaluation explicitly by inserting a call to 'AsEnumerable',
'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
The setup at this MySQL::Entity Framework Core Support URL is exactly what I did (there are only two steps to set it up). My DI config looks like this:
builder.Services.AddEntityFrameworkMySQL()
.AddDbContext<MydbContext>(options =>
{
options.UseMySQL(builder.Configuration.GetConnectionString("DefaultConnection"));
});
It will execute simple queries but more complex ones always generate this error. It says to rewrite the query and force client side evaluation by using AsEnumerable or ToList but I don't want to drag all that data to the client and I expect that a simple group by can be translated and handled server side.
I did find one article that talks about this problem but I'm not getting if it's suggesting an actual solution.
This shouldn't be this hard and I feel like I'm missing something simple.
Model
internal class Post
{
public int PostId { get; set; }
public string? Title { get; set; }
public string? Content { get; set; }
public int BlogId { get; set; }
}
DBContext
internal class BloggingContext : DbContext
{
public DbSet<Post>? Posts { get; set; }
public string DbPath { get; }
public BloggingContext()
{
var path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
DbPath = $"{path}{Path.DirectorySeparatorChar}blogging.db";
}
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlite($"Data Source={DbPath}");
}
Main
internal class Program
{
static void Main(string[] args)
{
using (var db = new BloggingContext())
{
var posts = db.Posts.Where(s => s.Title.Contains("Hello")).GroupBy(g => g.BlogId == 1994).Select(s => new { Key = s.Key, Counts = s.Count() }).ToList();
foreach (var p in posts)
{
Console.WriteLine(p);
}
}
}
}
Conclusion: You might add Select statement after GroupBy.
I am trying to use Web API to grab certain fields from my MVC controller. I can't seem to match the right type with the right list. I am fine with converting everything to string.
I either get an error in code (can not convert types), or if I get it to compile, I get this error:
"The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'."
From other similar posts, people responded with how to create a list, but not with the declaration of the return value of the Get. Please include both.
Also I would prefer not to add additional controllers as I need to do this on a number of my models.
Here is my code--note you can see I tried a number of different ways:
public class APICLIENTsController : ApiController
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET api/<controller>
public IEnumerable<string> Get()
//public IEnumerable<CLIENT> Get()
{
//return db.CLIENTs.OrderBy(x => x.CLIENTNAME).ToList();
string[] listOfUsers = db.CLIENTs.OrderBy(x => x.CLIENTNAME).Select(r => new
{
ID = r.CLIENTID.ToString(),
NAME = r.CLIENTNAME
});
return listOfUsers.ToList();
//return db.CLIENTs.Select(x => new { x.CLIENTNAME }).ToArray();
}
If you want to return JSON use the
JsonResult
type.
public JsonResult Get()
{
//return db.CLIENTs.OrderBy(x => x.CLIENTNAME).ToList();
string[] listOfUsers = db.CLIENTs.OrderBy(x => x.CLIENTNAME).Select(r => new
{
ID = r.CLIENTID.ToString(),
NAME = r.CLIENTNAME
});
return Json(listOfUsers.ToList(), JsonRequestBehavior.AllowGet);
}
Your query is returning a collection of anonymous objects, not string[] so it will throw an exception. Even if you were to generate string[] by concatenating the CLIENTID and CLIENTNAME properties, it would be a little use to the client.
Create a model to represent what you need to return to the view
public class ClientVM
{
public int ID { get; set; }
public string Name { get; set; }
}
and modify your method to
public IEnumerable<ClientVM> Get()
{
IEnumerable<ClientVM> model = db.CLIENTs.OrderBy(x => x.CLIENTNAME).Select(r => new ClientVM
{
ID = r.CLIENTID,
Name = r.CLIENTNAME
});
return model;
}
Side note: depending on how your calling and consuming this in the client, you may need to change the Content-Type to specifically return json (refer these answers for more detail)
I am using Dapper in my ASP.NET MVC 5 application and in my query I only want 2 fields to return but the Json returns all of the fields. This is my model
public class thread
{
[Key]
public int id { get; set; }
public int? profileID { get; set; }
public int numberkeeper { get; set; }
public int? photocount { get; set; }
}
This is my controller..
[ResponseType(typeof(thread))]
public IHttpActionResult Getstream()
{
string Connectionstring = ConfigurationManager.ConnectionStrings["db"].ConnectionString;
using (System.Data.SqlClient.SqlConnection sqlConnection = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
sqlConnection.Open();
var statevi = sqlConnection.Query<thread>("Select top 5 id,numberkeeper from threads").ToList();
if (statevi == null)
{
return NotFound();
}
return Ok(statevi);
}
}
That code returns Json as it is using .Net Web API,as you can see from the query I only want 2 fields returned. When I run it and see the Json it displays all fields (4) and off course the 2 fields not selected show up as null . I wanted so that the Json only shows the returnn of id and numberkeeper
Create a View Model class:
public class ThreadViewModel
{
public int id { get; set; }
public int numberkeeper { get; set; }
}
Let Dapper know you want it to create the ThreadViewModel for you:
var statevi = sqlConnection.Query<ThreadViewModel>("Select top 5 id,numberkeeper from threads").ToList();
This way you both query the database for the relevant properties and return just them to the client (without Dapper creating the full object with nulls).
If you create a new model that exposes the only two members that you want to render, that will prevent Web API from returning back additional JSON.
You could also convert the data after loading it into a new anonymous model using LINQ.
return Ok(statevi.Select(s => new { s.id, s.numberkeeper }));
If you want to keep the same model, but suppress null valued members Web API allows you to configure the JSON formatting to exclude null properties.
config.Formatters.JsonFormatter.SerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
};
If you want to use 2 or selected rows from query then you can use query method and extension method...
1. LINQ query method
using (System.Data.SqlClient.SqlConnection sqlConnection = new System.Data.SqlClient.SqlConnection(Connectionstring))
{
sqlConnection.Open();
var statevi = sqlConnection.Query<thread>("Select top 5 id,numberkeeper from threads").ToList();
if (statevi == null)
{
return NotFound();
}
var result = (from d in statevi
select new { d.id, d.numberkeeper }).ToList();
return Ok(result);
}
Extension Method: change this syntax to result of query method of above
var result = query.Select(d => new { d.Id, d.Title }).ToList();
both will give result same.
let me tell if it is working fine for your project or not.
Any suggestions would be most appreciated at this point.
I have a simple method in an MVC controller.
public IHttpActionResult GetCrudeAssessmentPrices(Int32? sellerid, DateTime? pdate, DateTime? pdateend)
{
var data = (dynamic)null;
data = db.CrudeAssessmentPrices.Select(i => new { sellerid, i.Price, i.Assessment, i.PriceDate }).Where(r => r.PriceDate >= pdate).Where(r => r.PriceDate <= pdateend).OrderBy(a => a.Assessment).ThenBy(b => b.PriceDate).ToList();
data = Json(data);
return data;
}
This method returns the following when views from a browser:
[{"sellerid":95,"Price":47.14000,"Assessment":"Argus: ANS","PriceDate":"2015-10-01T00:00:00"},{"sellerid":95,"Price":49.02500,"Assessment":"Argus: ANS","PriceDate":"2015-10-01T00:00:00"}]
In a console application I have this:
using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
namespace ConsumeJson
{
class AssessmentPrice
{
public int sellerid { get; set; }
public double Price { get; set; }
public string Assessment { get; set; }
public DateTime PriceDate { get; set; }
}
class Program
{
static void Main()
{
RunAsync().Wait();
}
static async Task RunAsync()
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:49467/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP GET
try
{
HttpResponseMessage response = await client.GetAsync("api/CrudeAssessmentPrices?sellerid=95&pdate=10/1/2015&pdateend=10/1/2015");
response.EnsureSuccessStatusCode();
if (response.IsSuccessStatusCode)
{
AssessmentPrice assessmentprice = await response.Content.ReadAsAsync<AssessmentPrice>();
Console.WriteLine("{0}\t${1}\t{2}\t{3}", assessmentprice.sellerid, assessmentprice.Price, assessmentprice.Assessment, assessmentprice.PriceDate);
}
}
catch (HttpRequestException e)
{
// Handle exception.
}
}
}
}
}
Running the console application the response object is returned from the api but the content property shows the header and it has a length but there is no content. The following error is produced:
***Message=Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ConsumeJson.AssessmentPrice' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly.
To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) or change the deserialized type to an array or a type that implements a collection interface (e.g. ICollection, IList) like List<T> that can be deserialized from a JSON array. JsonArrayAttribute can also be added to the type to force it to deserialize from a JSON array.
Path '', line 1, position 1.
Source=Newtonsoft.Json***
Your service is returning an array of JSON objects but your console application is expecting a JSON object. You could return a JSON object that contains the array like this: {"arrayOfObjects" : [{"one"}, {"two"}]} or tell it to expect an array.
I have an MVC Web App and a Web API Service that I am trying to retrieve information from. The problem is in the CapitalMailOrders entity collection is missing items when it is deserialized on the web side.
The Service uses the below to retrieve the information
var result = db.Contacts
.Include(a => a.IDXPageLinks)
.Include(b => b.ReboGatewayLoginInfoes)
.Include(c => c.SocialMedias)
.Include(d => d.WebSiteInfoes)
.Include(e => e.ContactImages)
.Include(f => f.RealtorSetUpProcesses.Select(f1 => f1.CapitalMailOrders)
.Include(g => g.Contact_CarrierCode_Assignments)
.FirstOrDefault(c => c.ContactID == id);
This code is good and returns the below on the service side. The below image shows 3 CapitalMailOrders which is what there should be.
But when it's deserialized on the Web side I only get 2 the 3rd is null
here is the Web Side Repository Code
public Contact Get(int id)
{
var responseStream =
requestMethod.GetResponseStream(
requestMethod.getRequest("GET", "application/json",
string.Format("{0}/api/contact/{1}", restService, id)).GetResponse());
var contacts = deSerialize<Contact>(responseStream) as Contact;
return contacts;
}
deSerialize is in the base repository class
public class BaseRepository
{
protected readonly string restService = ConfigurationManager.AppSettings["restService"];
protected readonly RequestMethod requestMethod = new RequestMethod();
protected ISerialization _serializer;
protected BaseRepository()
{ }
protected object deSerialize<T>(Stream stream)
{
var retval = _serializer.DeSerialize<T>(stream);
return retval;
}
protected string serialize<T>(T value)
{
var retval = _serializer.Serialize<T>(value);
return retval;
}
}
public class JsonNetSerialization : ISerialization
{
public string Serialize<T>(object o)
{
return JsonConvert.SerializeObject((T)o);
}
public object DeSerialize<T>(Stream stream)
{
return JsonConvert.DeserializeObject<T>(new StreamReader(stream).ReadToEnd());
}
}
Any ideas? Thanks
This post pointed me to the problem and suggested solution. In a nutshell the poster #Darin advised to return the data collection from the web api using models rather than the entity collection. Since there is no databinding to the db context when serializing the data back to the web app theres really no reason to carry the overhead and problems of trying to serialize the entity collection. This blog post goes into more detail.