Issue is why my Web API not returning JSON - asp.net-web-api

see my web api controller actions. i am return a response class from my action which has wrapped customer data ,status and message etc. but when i am invoking my web action from browser then action returning this symbol {} only which is very odd. see my web api code
my code as follows
[RoutePrefix("api/customer")]
public class CustomerController : ApiController
{
static readonly ICustomerRepository repository = new CustomerRepository();
[HttpGet, Route("GetAll")]
public HttpResponseMessage GetAllCustomers()
{
var Response=new Response(true, "SUCCESS", repository.GetAll());
//return Response;
//return Request.CreateResponse(HttpStatusCode.OK, Response);
HttpResponseMessage response = Request.CreateResponse<Response>(HttpStatusCode.OK, Response);
return response;
}
[HttpGet, Route("GetByID/{customerID}")]
public Response GetCustomer(string customerID)
{
Customer customer = repository.Get(customerID);
if (customer == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return new Response(true, "SUCCESS", customer);
//return Request.CreateResponse(HttpStatusCode.OK, response);
}
[HttpGet, Route("GetByCountryName/{country}")]
public IEnumerable<Customer> GetCustomersByCountry(string country)
{
return repository.GetAll().Where(
c => string.Equals(c.Country, country, StringComparison.OrdinalIgnoreCase));
}
public HttpResponseMessage PostCustomer(Customer customer)
{
customer = repository.Add(customer);
var response = Request.CreateResponse<Customer>(HttpStatusCode.Created, customer);
string uri = Url.Link("DefaultApi", new { customerID = customer.CustomerID });
response.Headers.Location = new Uri(uri);
return response;
}
public void PutProduct(string customerID, Customer customer)
{
customer.CustomerID = customerID;
if (!repository.Update(customer))
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
}
public void DeleteProduct(string customerID)
{
Customer customer = repository.Get(customerID);
if (customer == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
repository.Remove(customerID);
}
}
public class Response
{
bool IsSuccess = false;
string Message;
object ResponseData;
public Response(bool status, string message, object data)
{
IsSuccess = status;
Message = message;
ResponseData = data;
}
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
public string ContactName { get; set; }
public string ContactTitle { get; set; }
public string Address { get; set; }
public string Region { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
}
this way i am calling from winform using httpclient
var baseAddress = "http://localhost:38762/api/customer/GetAll";
using (var client = new HttpClient())
{
using (var response = client.GetAsync(baseAddress).Result)
{
if (response.IsSuccessStatusCode)
{
var customerJsonString = await response.Content.ReadAsStringAsync();
var cust = JsonConvert.DeserializeObject<Response>(customerJsonString);
}
else
{
Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
}
}
}
tell me what is wrong in my code for GetAll actions which is not returning json rather return {}
i have to return my response class instead of IEnumerable<Customer> so show me the path what to change in code.
if my method looks like
[HttpGet, Route("GetAll")]
public Response GetAllCustomers()
{
var Response = new Response(true, "SUCCESS", repository.GetAll());
//return Response;
//return Request.CreateResponse(HttpStatusCode.OK, Response);
//HttpResponseMessage response = Request.CreateResponse<Response>(HttpStatusCode.OK, Response);
return Response;
}
OR
[HttpGet, Route("GetAll")]
public HttpResponseMessage GetAllCustomers()
{
var Response=new Response(true, "SUCCESS", repository.GetAll());
//return Response;
//return Request.CreateResponse(HttpStatusCode.OK, Response);
HttpResponseMessage response = Request.CreateResponse<Response>(HttpStatusCode.OK, Response);
return response;
}
but not returning any data or json. just return {} means null.
this way i give instruction to my web api as a result it should return json.
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
}

I think the issue could be that you are already sending SUCCESS in your Response then creating another response using the Request.CreateResponse(..) method.
You can try to modify your method as below
public Response GetAllCustomers()
{
var data = repository.GetAll();
if (data !=null)
return Request.CreateResponse(HttpStatusCode.OK, data);
else
return Request.CreateErrorResponse(HttpStatusCode.NotFound,"No records found");
}
You can return these
HttpStatusCodes

Related

Asp.NET core 3 custom model attribute error handling

I need to catch the exception form my custom model attribute on validating it.
Here is my HttpStatusCodeExceptionMiddleware:
public class HttpStatusCodeExceptionMiddleware
{
private readonly RequestDelegate _next;
public HttpStatusCodeExceptionMiddleware(RequestDelegate next)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (HttpStatusCodeException ex)
{
if (context.Response.HasStarted)
{
throw;
}
context.Response.Clear(); //<-possible Angular CORS error
context.Response.StatusCode = ex.StatusCode;
context.Response.ContentType = ex.ContentType;
ProblemDetails responseBody = new ProblemDetails(ex.Message, ex.StatusCode, "Request error", ex.Key);
await context.Response.WriteAsync(JsonConvert.SerializeObject(responseBody));
return;
}
}
public class HttpStatusCodeException : Exception
{
public int StatusCode { get; set; }
public string ContentType { get; set; } = #"text/plain";
//key for translation
public string Key { get; set; }
public HttpStatusCodeException(HttpResponseType statusCode)
{
this.StatusCode = (int)statusCode;
}
public HttpStatusCodeException(HttpResponseType statusCode, string message, string key) : base(message)
{
StatusCode = (int)statusCode;
Key = key;
}
public HttpStatusCodeException(HttpResponseType statusCode, Exception inner, string key) : base(inner.ToString())
{
Key = key;
}
public HttpStatusCodeException(HttpResponseType statusCode, JObject errorObject, string key) : this(statusCode, errorObject.ToString(), key)
{
this.ContentType = #"application/json";
}
}
public static class HttpStatusCodeExceptionMiddlewareExtensions
{
public static IApplicationBuilder UseHttpStatusCodeExceptionMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<HttpStatusCodeExceptionMiddleware>();
}
}
And I am using it in the Startup.cs Configure method like this:
app.UseHttpStatusCodeExceptionMiddleware();
But in this scenario I need to catch the model attribute validation exception, but my solution only catches the controller exceptions.
Is there a way to do it?
thnx
You need to throw a HttpStatusCodeException then you could hit the catch (HttpStatusCodeException ex):
1.Custom validation attribute:
public class TestNameAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value,
ValidationContext validationContext)
{
if (value.ToString().StartsWith("a"))
{
throw new HttpStatusCodeException(HttpStatusCode.BadRequest, "Name could not start with a", value.ToString());
//return new ValidationResult("Name could not start with a");
}
return ValidationResult.Success;
}
}
2.Model:
public class YourModel
{
public long Id { get; set; }
[TestName]
public string Name { get; set; }
public string DisplayName { get; set; }
}
3.Test action:
[HttpPost]
public async Task<ActionResult<Mood>> Post(YourModel model)
{
_context.YourModel.Add(model);
await _context.SaveChangesAsync();
return CreatedAtAction("Get", new { id = model.Id }, model);
}

How to trigger App Center Push from my asp.net Web API?

I'm making an android Xamarin.Android. I finished the android application and now I want to add remote push notifications based on my item condition in my database that can accessed from ASP.Net Web Api.
I succeeded sent notifications from App Center Push to my application. I already authorized the App Center Client and now can access the app center api. I'm planning to merge the app center api to my asp.net web api if possible. But I don't know where to start it.
Should I put the app center action to my controller (I don't know if its working or not) or there's another way?
here's my controller:
public class InventoriesController : ApiController
{
private InventoryRepository _inventoryRepository;
public InventoriesController()
{
_inventoryRepository = new InventoryRepository();
}
// GET: api/Categories
public IHttpActionResult GetInventories()
{
IEnumerable<InventoryViewModel> inv = _inventoryRepository.GetAll().ToList().Select(e=> new InventoryViewModel(e)).ToList();
return Ok(inv);
}
// GET: api/Categories/5
[ResponseType(typeof(InventoryViewModel))]
public IHttpActionResult GetInventory(Guid id)
{
InventoryViewModel inventory = new InventoryViewModel (_inventoryRepository.GetSingle(e => e.Id == id));
if (inventory == null)
{
return NotFound();
}
return Ok(inventory);
}
// PUT: api/Categories/5
[ResponseType(typeof(void))]
public IHttpActionResult PutInventory(Guid id, InventoryViewModel inventory)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != inventory.Id)
{
return BadRequest();
}
try
{
_inventoryRepository.Edit(inventory.ToModel());
}
catch (DbUpdateConcurrencyException)
{
if (!InventoryExist(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
// POST: api/Categories
[ResponseType(typeof(InventoryViewModel))]
public IHttpActionResult PostInventory(InventoryViewModel inventory)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
try
{
_inventoryRepository.Add(inventory.ToModel());
}
catch (DbUpdateException)
{
if (InventoryExist(inventory.Id))
{
return Conflict();
}
else
{
throw;
}
}
return CreatedAtRoute("DefaultApi", new { id = inventory.Id }, inventory);
}
// DELETE: api/Categories/5
[ResponseType(typeof(Inventory))]
public async Task<IHttpActionResult> DeleteInventory(Guid id)
{
Inventory inventory = _inventoryRepository.GetSingle(e => e.Id == id);
if (inventory == null)
{
return NotFound();
}
await _inventoryRepository.DeleteAsync(inventory);
return Ok(inventory);
}
private bool InventoryExist(Guid id)
{
IQueryable<Inventory> inv = _inventoryRepository.GetAll();
return inv.Count(e => e.Id == id) > 0;
}
And this is my model:
public class InventoryViewModel
{
public Guid Id { get; set; }
public int Quantity { get; set; }
public DateTime ExpirationDate { get; set; }
public bool IsDeleted { get; set; }
public bool IsConsumed { get; set; }
public decimal Price { get; set; }
public string ItemName { get; set; }
public Guid ProductId { get; set; }
public Guid StorageId { get; set; }
public string AddedUserId { get; set; }
public Inventory ToModel()
{
return new Inventory
{
Id = (Id == Guid.Empty) ? Guid.NewGuid() : Id,
ExpirationDate = ExpirationDate,
Price = Price,
ProductId=ProductId,
StorageId=StorageId,
ItemName=ItemName,
IsDeleted=IsDeleted,
IsConsumed=IsConsumed,
AddedUserId = AddedUserId,
};
}
public InventoryViewModel()
{
}
public InventoryViewModel(Inventory i)
{
this.Id = i.Id;
this.ExpirationDate = i.ExpirationDate;
this.Price = i.Price;
this.ProductId = i.ProductId;
this.StorageId = i.StorageId;
this.ItemName = i.ItemName;
this.AddedUserId = i.AddedUserId;
}
}
I want to make the app center send notification based on Expired Date on my Inventories model and AddedUserId. So its my web self made web api who send the notification to my apps.
I read this documentation: [https://learn.microsoft.com/en-us/appcenter/push/pushapi][1] but still don't know where I have to write in my Web Api.
Hope someone here can help me.
Thanks in advance :)
You can find detail here in appcenter REST API documentation
https://learn.microsoft.com/en-us/appcenter/push/rest-api
Appcenter REST API swagger: https://openapi.appcenter.ms/

Ajax post model to controller action

In mvc4 i am trying to Post model data from view to controller using Jquery Ajax but don't now what's wrong with this code can any one help me in this matter.
<script src="~/Scripts/jquery-1.8.2.js"></script>
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#save").click(function () {
$("#content").html("<b>Please Wait...</b>");
var dataObject = {
empid: 1,
EmployeeName: "rizwan",
Address: "lahore",
Country: "pakistan",
Salary: "35000.00",
DepartmentName: "Field"
}
$.ajax({
type: "POST",
url: "/Home/Index",
data: dataObject,
success: function (data)
{
$("#empname").val(''),
$("#empadd").val(''),
$("#empcountry").val(''),
$("#empsalary").val(''),
$("#empdeptname").val(''),
$("#content").html("<div class='success'>"+data+"</div>")
},
error: function (ehr)
{
$("#content").html("<div class='failed'>Error! Please try again</div>");
},
})
});
});
</script>
This is my controller action code who just receive the value of object and save into database
Problem is that i failed to receive values at controller action side.
Please help me.....
[HttpPost]
public ActionResult Index(userview dataObject)
{
department dept = new department();
employee emp = new employee();
string message = "";
try
{
emp.employeeName = dataObject.EmployeeName;
emp.address = dataObject.Address;
emp.country = dataObject.Country;
emp.salary = dataObject.Salary;
dept.departmentName = dataObject.DepartmentName;
db.employees.Add(emp);
db.departments.Add(dept);
db.SaveChanges();
}
catch(Exception ex)
{
message = "Error! Please try again";
}
if (Request.IsAjaxRequest())
{
return new JsonResult { Data = message, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
}
ViewBag.message = message;
return View();
}
This is my model class
public class userview
{
public int empId { get; set; }
public string EmployeeName { get; set; }
public string Address { get; set; }
public string Country { get; set; }
public decimal Salary { get; set; }
public string DepartmentName { get; set; }
}
Try using JSON.stringify
$.ajax({
type: "POST",
url: "/Home/Index",
data: JSON.stringify(dataObject), //Here is the change
success: function (data)
{
$("#empname").val(''),
$("#empadd").val(''),
$("#empcountry").val(''),
$("#empsalary").val(''),
$("#empdeptname").val(''),
$("#content").html("<div class='success'>"+data+"</div>")
},
error: function (ehr)
{
$("#content").html("<div class='failed'>Error! Please try again</div>");
},
})
You can implement BindModel yourself! get the json string and deserialize to your entity.
public class JsonBinder<T> : System.Web.Mvc.IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
using (var reader = new System.IO.StreamReader(controllerContext.HttpContext.Request.InputStream))
{
//set stream position 0, maybe previous action already read the stream.
controllerContext.HttpContext.Request.InputStream.Position = 0;
string json = reader.ReadToEnd();
if (string.IsNullOrEmpty(json) == false)
{
JavaScriptSerializer serializer = new JavaScriptSerializer();
object jsonData = serializer.DeserializeObject(json);
return serializer.Deserialize<T>(json);
}
else
{
return null;
}
}
}
}
and set the JsonBinder to the post method like
[HttpPost]
public ActionResult Index([ModelBinder(typeof(JsonBinder<userview>))] userview dataObject)
{
}
the other solution
I found that you could set DataContract to the class of Model, and set DataMember to the Properties of the class.
edit the class like this
[DataContract]
public class userview
{
[DataMember]
public int empId { get; set; }
[DataMember]
public string EmployeeName { get; set; }
[DataMember]
public string Address { get; set; }
[DataMember]
public string Country { get; set; }
[DataMember]
public decimal Salary { get; set; }
[DataMember]
public string DepartmentName { get; set; }
}
and you should add library reference "System.Runtime.Serialization"
Hope it works for you.

Web API Parameter Binding

Request Payload does not get coverted to Custom Request Object.
payload
appl5=MC~IC&i~PhoneToPhone~inet_ptt_cb_phn~1=440&inet_ptt_cb_phn~3=7406&i~PhoneToPhone~inet_ptt_cb_delay=0&BeenHere=TRUE
It has ~ in keyvalue pair (both in key and value).
I have a Request Model that convert the input params to avalid Object.
Note: I cannot have ~ in my C# property. ( Can i ? )
My Post method has the following code
public HttpResponseMessage Post(ClientRequest request)
{
HttpResponseMessage response;
try
{
ProcessRequest target = new ProcessRequest(myRepository, myService);
response = target.Process(request);
}
catch (Exception exception)
{
response = Request.CreateErrorResponse(HttpStatusCode.NotFound, exception.Message);
//TODO : Log Exception.
}
return response;
}
Model
public class ClientRequest
{
public string Appl5 { get; set; }
public string I_PhoneToPhone_inet_ptt_cb_phn_1 { get; set; }
public string I_PhoneToPhone_inet_ptt_cb_delay { get; set; }
public string Inet_ptt_cb_phn_3 { get; set; }
public string BeenHere { get; set; }
}
My request object does not have the values for i~PhoneToPhone~inet_ptt_cb_phn~1, its null.
My understanding was the model binding is not happening because the payload key does not match
with my model (ClientRequest) which does not have ~ for i~PhoneToPhone~inet_ptt_cb_phn~1
in stead i have i_PhoneToPhone_inet_ptt_cb_phn_1
Should i use Custom Binding ?
At last, Added Custom Model binder
public class PostParameterModelBinder : IModelBinder
{
bool IModelBinder.BindModel(System.Web.Http.Controllers.HttpActionContext actionContext, ModelBindingContext bindingContext)
{
bool success = false;
if (bindingContext.ModelType == typeof(ClientRequest))
{
NameValueCollection postData = null;
postData = actionContext.Request.Content.ReadAsFormDataAsync().Result;
ClientRequest clientrequest = MapPostDataToRequest(postData);
bindingContext.Model = clientrequest;
success = true;
}
return success;
}
}
}

How to use split in linq query?

I am trying to call the following query string but I am getting 'no data' message on the client-side - 'api/data?id=786,899&price_type=cvr'.
public HttpResponseMessage Get([FromUri] Query query)
{
var data = db.database_ICs.AsQueryable();
if (query.id!= null)
{
data = data.Where(c => query.id.Split(',').Contains(c.ID));
}
if (query.price_type != null)
{
data = data.Where(c => c.Cover == query.price_type);
}
if (!data.Any())
{
var message = string.Format("No data was found");
return Request.CreateErrorResponse(HttpStatusCode.NotFound, message);
}
return Request.CreateResponse(HttpStatusCode.OK, data);
}
public class Query
{
public string id{ get; set; }
public string price_type { get; set; }
public Nullable<DateTime> startDate { get; set; }
public Nullable<DateTime> endDate{ get; set; }
}
Any help would be very much appreciated.
Many Thanks.
var data = db.database_ICs.AsQueryable();
if (!string.IsNullOrEmpty(query.id))
{
var ids = query.id.Split(',').ToList();
data = data.Where(c => ids.Contains(c.ID));
}
Assuming c.ID and ids elements are of the same type of course.
Edit: one way of checking if you have the querystring or not

Resources