Cannot Convert List to Json - c#

I have the following action method:
public class MyDeviceController : ApiController
{
// GET api/<controller>
public JsonResult Get()
{
int userId = -1;
List<String> myDevices1 = new List<String>();
myDevices1.Add("1");
>> return Json(myDevices1); << Error here
}
}
The return is underlined red with the following error:
cannot implicitly convert type (JsonResult to List<string>)
I am using Asp.net Web Api. I think its getting confused between the using System.web.http and System.mvc.http
h

your system is confusing between
System.Web.Http.Results.JsonResult<List<string>>
and System.Web.Mvc.JsonResult
try specifiyng the full name which is System.Web.Http.Results.JsonResult>
public System.Web.Http.Results.JsonResult<List<string>> Get()
{
int userId = -1;
List<String> myDevices1 = new List<String>();
myDevices1.Add("1");
return Json(myDevices1);
}
another and preferred approach would be
public HttpResponseMessage Get()
{
int userId = -1;
List<String> myDevices1 = new List<String>();
myDevices1.Add("1");
return Request.CreateResponse(myDevices1);
}
in the latter teh asp.net web api would automatically negotiate between the formats accepted by the client which is specified iin the Accepts header and would send XML or JSON appropriately

My web api project in defined class City JsonResult List Convert by and return.
public class City
{
public int Id { get; set; }
public string CityName{ get; set; }
}
static List<City> _City = InitCitys();
private static List<City> Citys()
{
var returnList = new List<City>();
returnList.Add(new City{ Id = 0, CityName= "Sinop" });
returnList.Add(new City{ Id = 1, CityName= "Ayancık" });
returnList.Add(new City{ Id = 2, CityName= "İstanbul" });
return returnList;
}
// GET api/values
public JsonResult<City> Get(int Id)
{
var cityJsonResult = _City.Where(x => x.Id == Id).SingleOrDefault();
return Json(cityJsonResult);
}

As you are using web api:
You can leave your code this way:
public class MyDeviceController : ApiController
{
// GET api/<controller>
public List<string> Get()
{
int userId = -1;
List<String> myDevices1 = new List<String>();
myDevices1.Add("1");
return myDevices;
}
}
By default it will return XML but
adding this line of code in WebApiConfig.cs, will return json by default:
var appXmlType = config.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml");
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
See more about WEB API media Formatters
There is also another way of doing things(not the best approach):
using Newtonsoft.Json;
public HttpResponseMessage get(){
List<String> myDevices1 = new List<String>();
myDevices1.Add("1");
JsonConvert.SerializeObject(myDevices1);
return Request.CreateResponse(HttpStatusCode.OK, myDevices1);;
}

Related

How to Pass List object to Web API PUT method C#

I am trying to pass a List to my Web API but I am getting a null value always. I am converting the list in to a string before passing it to the API. How can I send a list to API and Update the data correctly? Please help me to figure out the correct code.
Class: MatrixProcessData.cs
namespace AHS.IBP.BO
{
[Serializable, DataContract]
public class MatrixProcessData
{
#region Variables
// private int _id;
private int _processYear;
private DateTime _processDate;
#endregion
#region Constructor
public MatrixProcessData()
{
// _id = 0;
_processYear = 0;
_processDate = DateTime.Today;
}
#endregion
#region Properties
[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Key]
// [DataMember]
//public int ID { get { return _id; } set { _id = value; } }
[DataMember]
public int ProcessYear
{
get { return _processYear; }
set { _processYear = value; }
}
[DataMember]
public DateTime ProcessDate
{
get { return _processDate; }
set { _processDate = value; }
}
#endregion
}
}
Method to call API:
public void ProcessData()
{
DataSet dsProcessData = new DataSet();
dsProcessData = new TempMatrixClass().GetProcessData(DateTime.Now.Year,771);
List<MatrixProcessData> li = new List<MatrixProcessData>();
if (dsProcessData.Tables[0].Rows.Count > 0)
{
foreach (DataRow dr in dsProcessData.Tables[0].Rows)
{
MatrixProcessData mtrixProcessData = new MatrixProcessData();
mtrixProcessData.ProcessYear = Convert.ToInt32(dr["ProcessYear"]);
mtrixProcessData.ProcessDate = Convert.ToDateTime(dr["ProcessDate"]);
li.Add(mtrixProcessData);
}
string apiUrl = string.Format("{0}api/MatrixProcessData/{1}/", aplilink, 2019);
HttpClient httpClient = new HttpClient();
httpClient.MaxResponseContentBufferSize = 256000;
string strObject = Newtonsoft.Json.JsonConvert.SerializeObject(li, Newtonsoft.Json.Formatting.None);
HttpContent httpContent = new StringContent(strObject, Encoding.UTF8, "application/json");
var response = httpClient.PutAsync(apiUrl, httpContent, new System.Threading.CancellationToken(false)).Result;
if (response != null && response.IsSuccessStatusCode)
{
var data = response.Content.ReadAsStringAsync().Result;
// mtrixProcessData = Newtonsoft.Json.JsonConvert.DeserializeObject<MatrixProcessData>(data);
}
}
}
Controller PUT API Method (List) is getting null:
MatrixProcessDataController.cs
[Route("{processyear}")]
[ResponseType(typeof(List<MatrixProcessData>))]
public IHttpActionResult PutmatrixProcessData(int processyear, List<MatrixProcessData> matrixProcessData)
{
foreach (var item in matrixProcessData)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
db.Entry(matrixProcessData).State = EntityState.Modified;
if (!matrixProcessDataExists(item.ProcessYear, item.ScenarioID, item.ModuleID, item.MeasureID, item.SKUID, item.ProcessDate))
{
db.MatrixProcessDatas.Add(item);
}
db.SaveChanges();
}
return StatusCode(HttpStatusCode.NoContent);
}
Not sure if you have any other problem with your Processing code, but for the Controller code, you need to specify where the data binding happens, depending on how you make the HTTP request. You may need [FromBody] or [FromForm]:
[Route("{processyear}")]
[ResponseType(typeof(List<MatrixProcessData>))]
public IHttpActionResult PutmatrixProcessData([FromRoute]int processyear, [FromBody] List<MatrixProcessData> matrixProcessData)
{
...
}

How to mock a post request?

Controller:
private IBeer _beerService;
public BeerController(IBeer beerService)
{
_beerService = beerService;
}
[HttpPost]
public async Task<IActionResult> Post([FromBody]Beer model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var beer = await _beerService.Add(model);
return Ok(CreatedAtAction("Add Item", new { beer.id }, beer));
}
Model:
public class Beer
{
public int id { get; set; }
public string name { get; set; }
public int cost { get; set; }
}
Interface :
public interface IBeer
{
Task<Beer> Add(Beer beer);
}
Test:
[Fact]
public void TestPostWithMock()
{
// Arrange
var serviceMock = new Mock<IBeer>();
List<Beer> expected = new List<Beer>()
{
new Beer{id=2, beer="Kingfisher", cost=170 },
};
serviceMock.Setup(x => x.Add(expected)).Returns(() => Task.FromResult(beer));
var controller = new BeerController(serviceMock.Object);
// Act
var result = controller.Get(2);
// Assert
var okResult = result.Should().BeOfType<OkObjectResult>().Subject;
var actual = okResult.Value.Should().BeAssignableTo<IEnumerable<Beer>>().Subject;
Assert.Equal(expected, actual);
}
I'm trying to mock the post request but when I try to mock it here:
x => x.Add(expected)
It gives me an error - Generic.list cannot be converted to Controller.Beer. What should be done ?
As error description mentions, you send list of beer (List<Beer>) to your Add() method while setuping your service. You should instead send Beer class instance (like in your interface) as parameter like shown below.
// Update your request object without List
var expected = new Beer()
{
id=2,
beer="Kingfisher",
cost=170
};
And also, update your Setup function as below.
serviceMock.Setup(x => x.Add(expected)).Returns(() => Task.FromResult(expected));
Lastly, you need to get your result from controller.Post() method as in the controller, not from controller.Get(2). Hope this helps you.

Why does my web API not return JSON?

I made a very simple web API controller to reproduce an error in a more complex one, this controller only has the minimum amount of code to reproduce the error.
The controller code is as follows
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
namespace NWCloudBorgEmployee.Controllers
{
public class WmsInfo
{
public string StoreName { get; set; }
public string ItemName { get; set; }
public string ItemQty { get; set; }
}
public class WmsInformation
{
public List<WmsInfo> WmsInfos { get; set; }
}
[Produces("application/json")]
[Route("api/WmsInfo")]
public class WmsInfoController : Controller
{
// GET: api/WmsInfo
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "You need to send in a barcode as ID to get the correct return data" };
}
// GET: api/WmsInfo/5
[HttpGet("{id}", Name = "Get")]
public string Get(int id)
{
var test = new WmsInformation();
test.WmsInfos = new List<WmsInfo>
{
new WmsInfo { StoreName = "SE001", ItemName = "Item1" , ItemQty = "10"},
new WmsInfo { StoreName = "SE002", ItemName = "Item2" , ItemQty = "115"}
};
return test.ToString();
}
}
}
When I call the API I get a string as below instead of the JSON data
"NWCloudBorgEmployee.Controllers.WmsInformation"
Why is it not returning the JSON?
Because you're calling .ToString() on an object.
Change your method signature to this:
public IActionResult Get(int id)
and then simply:
return Ok(test);
Note: You can change the signature to return WmsInformation, but using action results lets you return error codes easily, too.
I recommended to use JsonResult instead of string
public JsonResult Get(int id)
{
var test = new WmsInformation();
test.WmsInfos = new List<WmsInfo>
{
new WmsInfo { StoreName = "SE001", ItemName = "Item1" , ItemQty = "10"},
new WmsInfo { StoreName = "SE002", ItemName = "Item2" , ItemQty = "115"}
};
return new JsonResult(test);
}
I hope you find it useful
That is valid JSON. It’s a string, just like your return type.
I imagine you’re trying to serialize the object, rather that use ToString, which will return the type name by default.
You could just return the object instead of using ToString, and adjust your method signature to account for the change.
This will start the content negotiation process and end up serializing your object to (probably) JSON.
public WmsInformation Get(int is)
{
var test = new WmsInformation
{
WmsInfos = ...
}
return test;
}

Add value to list

I am calling a API method that is returning some question and answer as List. I need show this list in View, not sure how to add value to the faq list. As I am sending this List that is part of Model to the View to show in on the screen.
Inside the foreach loop is where I have to add value of web api to the faq List.
This is my method which is returning the Model.
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
HelpCenterViewModel helpCenterViewModel = new HelpCenterViewModel();
helpCenterViewModel.ContactInfo.loanId = loanId;
string json = string.Empty;
List<Faq> FaqObject = null;
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}",
CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
json = responseApi.Content.ReadAsStringAsync().Result;
FaqObject = new JavaScriptSerializer().Deserialize<List<Faq>>(json);
}
var response = new
{
success = FaqObject != null,
data = FaqObject
};
foreach (var faqitem in response.data)
{
//This is where I dont know how to add to faq list.
//helpCenterViewModel.Faq.Answer = faqitem.Answer;
//helpCenterViewModel.Faq.Category = faqitem.Category;
}
return View(helpCenterViewModel);
}
This is the Model that I am retunign it to view:
public class HelpCenterViewModel
{
public List<Faq> Faq { get; set; }
public ContactUsInfo ContactInfo { get; set; }
public HelpCenterViewModel()
{
this.Faq = new List<Faq>();
this.ContactInfo = new ContactUsInfo();
}
}
and this is the faq class:
public class Faq
{
public int Id { get; set; }
public string Category { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
}
and this is my view:
#model IEnum erable<Carfinance.Loans.Web.ViewModels.HelpCenterViewModel>
#foreach (var item in Model)
{
<li>#Html.DisplayFor(faq => item.Faq)</li>
}
But It gave me this error.
The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'CorsMessageHandler' is not null.
Parameter name: handlers
You need to create a new object for each of your items and add them to your list. This can be done in various ways, depending on how verbose you want your implementation to be:
foreach (var faqitem in response.data)
{
var faq = new Faq();
faq.Answer = faqitem.Answer;
faq.Category = faqitem.Category;
helpCenterViewModel.Faq.Add(faq);
}
OR
foreach (var faqitem in response.data)
helpCenterViewModel.Faq.Add(new Faq()
{
Answer = faqitem.Answer;
Category = faqitem.Category;
});
OR
helpCenterViewModel.Faq = response.data.Select(x => new Faq {
Answer = x.Answer,
Category = x.Category
}).ToList();
Cleaned up the code some, but you already have a List<Faq>, so just assign it to your model.
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
string json = string.Empty;
List<Faq> FaqObject = null; // Should probably be new List<Faq>
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}", CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
json = responseApi.Content.ReadAsStringAsync().Result;
FaqObject = new JavaScriptSerializer().Deserialize<List<Faq>>(json);
}
var response = new
{
success = FaqObject != null,
data = FaqObject
};
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=FaqObject
});
}
Not sure what you were doing with the response variable, so I just left it there, but it appears to do nothing useful and could be removed as well. Then you'd have this:
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}", CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=new JavaScriptSerializer().Deserialize<List<Faq>>(
responseApi.Content.ReadAsStringAsync().Result)
});
}
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=new List<Faq>()
});
}
well, the Faq property on HelpCenterViewModel is really a List<Faq> (kind of misleading naming you have there), so use the Add method:
foreach (var faqitem in response.data)
{
var faq = new Faq();
faq.Answer = faqitem.Answer;
faq.Category = faqitem.Category;
helpCenterViewModel.Faq.Add(faq);
//^ this Faq is a List
}
You should pluralize your List<Faq>'s name to Faqs to prevent confusing yourself.

How to return from an IHttpActionResult method a custom variable?

I am trying to get this JSON response with an Ihttpstatus header that states code 201 and keep IHttpActionResult as my method return type.
JSON I want returned:
{"CustomerID": 324}
My method:
[Route("api/createcustomer")]
[HttpPost]
[ResponseType(typeof(Customer))]
public IHttpActionResult CreateCustomer()
{
Customer NewCustomer = CustomerRepository.Add();
return CreatedAtRoute<Customer>("DefaultApi", new controller="customercontroller", CustomerID = NewCustomer.ID }, NewCustomer);
}
JSON returned:
"ID": 324,
"Date": "2014-06-18T17:35:07.8095813-07:00",
Here are some of the returns I've tried that either gave me uri null error or have given me a response similar to the example one above.
return Created<Customer>(Request.RequestUri + NewCustomer.ID.ToString(), NewCustomer.ID.ToString());
return CreatedAtRoute<Customer>("DefaultApi", new { CustomerID = NewCustomer.ID }, NewCustomer);
With an httpresponsemessage type method this can be solved as shown below. However I want to use an IHttpActionResult:
public HttpResponseMessage CreateCustomer()
{
Customer NewCustomer = CustomerRepository.Add();
return Request.CreateResponse(HttpStatusCode.Created, new { CustomerID = NewCustomer.ID });
}
This will get you your result:
[Route("api/createcustomer")]
[HttpPost]
//[ResponseType(typeof(Customer))]
public IHttpActionResult CreateCustomer()
{
...
string location = Request.RequestUri + "/" + NewCustomer.ID.ToString();
return Created(location, new { CustomerId = NewCustomer.ID });
}
Now the ResponseType does not match. If you need this attribute you'll need to create a new return type instead of using an anonymous type.
public class CreatedCustomerResponse
{
public int CustomerId { get; set; }
}
[Route("api/createcustomer")]
[HttpPost]
[ResponseType(typeof(CreatedCustomerResponse))]
public IHttpActionResult CreateCustomer()
{
...
string location = Request.RequestUri + "/" + NewCustomer.ID.ToString();
return Created(location, new CreatedCustomerResponse { CustomerId = NewCustomer.ID });
}
Another way to do this is to use the DataContractAttribute on your Customer class to control the serialization.
[DataContract(Name="Customer")]
public class Customer
{
[DataMember(Name="CustomerId")]
public int ID { get; set; }
// DataMember omitted
public DateTime? Date { get; set; }
}
Then just return the created model
return Created(location, NewCustomer);
// or
return CreatedAtRoute<Customer>("DefaultApi", new controller="customercontroller", CustomerID = NewCustomer.ID }, NewCustomer);

Categories