I'm trying to return an object to an ajax request with an api 2 controller in an MVC 5 app. my controller looks like this:
public class RFQsController : ApiController
{
private ApplicationDBContext db = new ApplicationDBContext();
[HttpGet]
public Models.RFQChecklist.RFQ GetRFQByQuote(string number)
{
var quote = db.QuoteSet.FirstOrDefault(q => q.Number == number);
if(quote != null)
{
return quote.RFQ?.FirstOrDefault();
}
else
{
return null;
}
}
}
RFQ looks like this:
public class RFQ
{
public int ID { get; set; }
public int QuoteID { get; set; }
//other values
[XmlIgnore, JsonIgnore]
public virtual Quote.Quote Quote { get; set; }
public virtual ICollection<RFQ_Signoff> Signoffs { get; set; }
}
It's important to ignore Quote because Quote has a reference to its contained RFQs, so that would be a circular reference. So when serializing an RFQ for consumption, I'm trying to ignore Quote, because Quote has to reference RFQ. The problem is that XmlIgnore isn't... ignoring. I've also tried ScriptIgnore, and the combination of DataContract/DataMember. No matter what I do, the MVC 5 serializer seems to try (and fail) to serialize the Quote object again.
I'm quite certain it is because of this value, because if I remove JsonIgnore then it doesn't work when I try to retrieve as Json, but if I include it it works.
If you want to limit your return data you need to use linq select instead of [XmlIgnore, JsonIgnore] attribute.
you can try to use an anonymous object to contain your expect return fields.
return quote.RFQ?.Select(x => new {
ID = x.ID,
QuoteID = x.QuoteID,
Signoffs = x.Signoffs }).FirstOrDefault();
instead of
return quote.RFQ?.FirstOrDefault();
Try to return IHttpActionResult
[HttpGet]
public IHttpActionResult GetRFQByQuote(string number)
{
var quote = db.QuoteSet.FirstOrDefault(q => q.Number == number);
if(quote != null)
{
var result = quote.RFQ?.Select(x => new {
ID = x.ID,
QuoteID = x.QuoteID,
Signoffs = x.Signoffs }).FirstOrDefault()
return Ok(result);
}
else
{
return null;
}
}
Related
When the below API method is called through the API
public IActionResult FirstStudent()
{
var collection = this.database.GetCollection<BsonDocument>("students");
var filter = Builders<BsonDocument>.Filter.Eq("RollNo", "1");
var document = collection.Find(filter).First();
var firstStudent= document.ToJson();
return Ok(firstStudent);
}
the response has Content-Type as text/plain.
I need the Content-Type as application/json.
Any suggestions?
the easiest thing to do would be to create a student model and simply return an ok result with the student model like this:
public class Student
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id { get; set; }
public int RollNo { get; set; }
public string Name { get; set; }
}
public IActionResult FirstStudent()
{
var collection = this.database.GetCollection<Student>("Student");
var filter = Builders<Student>.Filter.Where(s => s.RollNo == 1);
var document = collection.Find(filter).First();
return Ok(document);
}
This question already has an answer here:
Setting up a C# Test with Moq against Async methods
(1 answer)
Closed 3 years ago.
I will like to write a xunit test for the controller method below
[HttpGet]
[Route("GetPosts")]
public async Task<IActionResult> GetPosts()
{
try
{
var posts = await postRepository.GetPosts();
if (posts == null)
{
return NotFound();
}
return Ok(posts);
}
catch (Exception)
{
return BadRequest();
}
}
My viewmodel looks like this.
public class PostViewModel
{
public int PostId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int? CategoryId { get; set; }
public DateTime? CreatedDate { get; set; }
public string CategoryName { get; set; }
}
Here is what my repository looks like.
public async Task<List<PostViewModel>> GetPosts()
{
if (db != null)
{
return await (from p in db.Post
from c in db.Category
where p.CategoryId == c.Id
select new PostViewModel
{
PostId = p.PostId,
Title = p.Title,
Description = p.Description,
CategoryId = p.CategoryId,
CategoryName = c.Name,
CreatedDate = p.CreatedDate
}).ToListAsync();
}
return null;
}
I started getting this error message
cannot convert from 'System.Collections.Generic.List<CoreServices.ViewModel.PostViewModel>'
to 'System.Threading.Tasks.Task<System.Collections.Generic.List<CoreServices.ViewModel.PostViewModel>>'
Here is what my xunit test looks like.
public class PostControllerTest
{
private readonly Mock<IPostRepository> _mockRepo;
private readonly PostController _controller;
public PostControllerTest()
{
_mockRepo = new Mock<IPostRepository>();
_controller = new PostController(_mockRepo.Object);
}
[Fact]
public void GetPosts_TaskExecutes_ReturnsExactNumberOfPosts()
{
_mockRepo.Setup(repo => repo.GetPosts())
.Returns(new List<PostViewModel>() { new PostViewModel(), new PostViewModel() });
//var result =
//Assert.True()
}
}
I will like to complete my first test which will show the count of the post is 2 (mocking a dependency).
How can I write this/complete this test ?
I think everything else is fine except your Returns value setup. You need to return a Task. Try this
_mockRepo.Setup(repo => repo.GetPosts())
.Returns(Task.FromResult(new List<PostViewModel>() { new PostViewModel(), new PostViewModel() }));
Try using ReturnsAsync instead of Returns. GetPosts is an asynchronous method.
I have file with lines like this: 05122018;surname1;ItemName1;Price1
And OrderModel
public class OrderModel
{
public string ManagerSurname { get; set; }
public DateTime Date { get; set; }
public string CustomerSurname { get; set; }
public string ItemName { get; set; }
public double Price { get; set; }
}
How to make LINQ request to return collection of OrderModels ?
public IEnumerable<OrderModel> Parse(string[] input)
{
return
(input ?? throw new ArgumentNullException(nameof(input)))
.Select(orderModel => new OrderModel()
{
//filling objects
}).Where(orderModel => //Any);
Considering the input[] array consists of one line
05122018;surname1;ItemName1;Price1
for each entry and each line has the same order of items. You could do a split in the select, to get the appropriate values:
public IEnumerable<OrderModel> Parse(string[] input)
{
return
(input ?? throw new ArgumentNullException(nameof(input)))
.Select(orderModel =>
{
var items = orderModel.Split(";");
if (items.Length != 4)
{
throw new ArgumentException();
}
return new OrderModel()
{
//filling objects
ManagerSurname = items[1],
ItemName = items[2],
...
};
}).Where(orderModel => //Any);
}
Basically, you look like you want to deserialize the string that's coming in from semicolon delimited to an object. That's a pretty ugly and potentially fragile way to serialize / deserialize your data, and if you can change it (to JSON, or XML or something else) it might be a good idea.
But you could create a constructor for your OrderModel class that takes the serialized string as a parameter and deserializes in there:
public OrderModel(string inOrderModel){
var splitString = inOrderModel.Split(';');
ManagerSurname = splitString[1];
// etc
}
And then you can use LINQ to create the list from the incoming array:
return input.Select(i => new OrderModel(i));
returning simply return _context.OrderModel will return your entire OrderModel from the context:
public IEnumerable<OrderModel> Parse(string[] input)
{
(input ?? throw new ArgumentNullException(nameof(input)))
return _context.OrderModel;
}
or assuming you would like to filter your dataset by data in the input string array, you can filter with input.contains(model.field). Example filters Item Name based on the input string array:
public IEnumerable<OrderModel> Parse(string[] input)
{
(input ?? throw new ArgumentNullException(nameof(input)))
return _context.OrderModel.Where(m => input.contains(m.ItemName));
}
Here is my API controller's Get method
[HttpGet]
public MyTable GetMyTable(byte id, string langId)
{
MyTable mytable;
if (id == 0)
{
mytable = db.MyTables.Find(langId);
}
else
{
mytable = db.MyTables.Find(id, langId);
}
if (mytable == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return mytable;
}
It has two keys, so a composite key. The DbSet.Find() method requires that both MyTable.ID and MyTable.LanguageId be specified.
My model for this table looks like:
[Table("MyTable", Schema = "MyScheme")]
public class MyTable
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[Required]
[Column(Order = 0)]
public byte ID { get; set; }
[Required]
public string MyCode { get; set; }
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
[Required]
[Column(Order=1)]
public string LanguageId { get; set; }
[Required]
public byte LevelId { get; set; }
public string ConceptName { get; set; }
}
I want to be able to list all entries by given language id, but without specific id given.
I also want to be able to get single entry with id and langId.
How can I do that?
[HttpGet]
public JsonResult GetMyTable(string langId)
{
var mytable = db.MyTables.Find(langId);
return Json(mytable);
}
[HttpGet]
public JsonResult GetMyTable(byte id, string langId)
{
MyTable mytable = db.MyTables.Find(id, langId);
if (mytable == null)
{
return Json(new {Message = "NullreferenceExeption"})
}
return Json(mytable);
}
You have 2 queries which return different result sets. One returns a collection the other one returns a single result. I'm not going to get into describing how a proper RESTful response should look in api controller. That's a different topic. But if we look at what you have so far it should be like this:
[HttpGet]
public MyTable GetMyTable(byte id, string langId)
{
List<MyTable> results = new List<MyTable>();
if (id == 0)
{
results = db.MyTables.Where(x => x.LanguageId == langid).ToList();
}
else
{
var find = db.MyTables.Find(id, langId);
if (find != null) results.Add(find);
}
return results;
}
This way the results always come back as a list and if find is used for unique entry find then you get back a list with a single element.
My working code:
// GET api/MyTable?langid=mk-MK
[HttpGet]
public IQueryable<MyTable> GetMyTable(string langid)
{
IQueryable<MyTable> mytable = db.MyTables.Where(x => x.LanguageId == langid);
if (mytable == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return mytable;
}
// GET api/MyTable?id=5&langid=mk-MK
[HttpGet]
public MyTable GetMyTable(byte id, string langid)
{
MyTable mytable = db.MyTables.Find(id, langid);
if (mytable == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return mytable;
}
I have this class.
public class SDS
{
public Guid A { get; set; }
public Guid B { get; set; }
public String C { get; set; }
}
I return the json like this
public HttpResponseMessage Val()
{
SDS svr = new SDS();
svr.A = ...
svr.B = ...
svr.C = ...
return Request.CreateResponse(HttpStatusCode.OK, json_serializer.Serialize(svr), "application/json");
}
In the client side I use jquery like this
var obj = jQuery.parseJSON(jqXHR.responseText);
The problem is that the json that gets returned is like this and I am unable to iterate ofer the values or access the elements via index:
{"A":"3a9779fe-9c92-4208-b34d-5113e0548d50","B":"206575a5-8a90-4a13-89ec-910e5a9a35a1","C":"Meta"}
To solve this issue I had to do this and this works:
obj = jQuery.parseJSON('{"List":[' + obj + ']}');
My question is is there any way to use an attribute on the class so that it returns a json that I can use?
[SomeAttribute name="List"]
public class SDS
{
public Guid A { get; set; }
public Guid B { get; set; }
public String C { get; set; }
}
...
...
...
Update2:
This question is still open as none of the provided answers were able to produce a fix.
You can return a JsonResult by calling Json() in your action method.
public ActionResult Get(int id)
{
var item = ...
return Json(item);
}
Did you try to use the JsonResult from System.Web.Mvc.JsonResult ?
public JsonResult Val() {}
Hope this Helps.
The JSON returned is correct, don't change anything in your controller
..but in your JS loop the object with a for in loop
for(var propertyName in obj){
...
}
propertyName gives you A, B and C
and...
var value = obj[propertyName]
gives you the value
Well, you're returning a single object, not a list, but you could do:
public HttpResponseMessage Val()
{
SDS svr = new SDS();
svr.A = ...
svr.B = ...
svr.C = ...
var list = new {List = new [] {svr}};
return Request.CreateResponse(HttpStatusCode.OK, json_serializer.Serialize(svr), "application/json");
}
add ApiController and using System.Web.Http;