I have written a method in web api to partial update/patch a user. The code goes like this :
// PATCH API USER
[AcceptVerbs("PATCH")]
public HttpResponseMessage PatchDoc(int id, Delta<user> user)
{
user changeduser = db.users.SingleOrDefault(p => p.iduser == id);
if (changeduser == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
user.Patch(changeduser);
db.SaveChanges();
return Request.CreateResponse(HttpStatusCode.OK);
}
Its working fine if i am using updating/patching a string property like :
{location: "London,Uk"}
It works fine. But if i update/patch an integer property it doesnt makes changes, the field remains the same.
{profileviews: 43}
I even tried using json like
{profileviews: "43"}
But still no change. So what am i missing? Thanks.
Related
I have implemented some front end code which when a user clicks the checkout button they are redirected to a stripe page where they can input their card payment details. the code has a successful URL and failed URL. if the customer enter valid payment details - they are redirected to the successful URL, i need to update my database to ensure that my backend knows that this specific user has paid and can now view subscribed content. I am trying to setup web hooks in order to do this, so I know if the user has paid, cancelled etc.
using System;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using Stripe;
namespace workspace.Controllers
{
[Route("api/[controller]")]
public class StripeWebHook : Controller
{
// You can find your endpoint's secret in your webhook settings
const string secret = "whsec_...";
[HttpPost]
public async Task<IActionResult> Index()
{
var json = await new StreamReader(HttpContext.Request.Body).ReadToEndAsync();
try
{
var stripeEvent = EventUtility.ConstructEvent(json,
Request.Headers["Stripe-Signature"], secret);
// Handle the checkout.session.completed event
if (stripeEvent.Type == Events.CheckoutSessionCompleted)
{
var session = stripeEvent.Data.Object as Checkout.Session;
// Fulfill the purchase...
HandleCheckoutSession(session);
}
else
{
return Ok()
}
}
catch (StripeException e)
{
return BadRequest();
}
}
}
}
However when trying to implement this I get errors because I think the custom code provided above uses .NET Core and I am using the full .NET framework.
Is there a way around this or what am I doing wrong?
This may help someone so I'm posting even although it's a bit late to the table as I couldn't find a relevant answer anywhere.
I had this same issue on a dotNet Core MVC web application (so not an exact answer for the question which is .Net Framework) where the Stripe Webhook was constantly giving a 400 Bad Request response. I just couldn't hit it no matter what I tried.
Eventually, and probably obviously the solution for me was to add the [IgnoreAntiforgeryToken] attribute to the Index() method as you have in your question above. As .dotNet Core enables the Validation Token on forms I had to explicitly ignore it. The Webhooks worked as soon as I did that.
So the solution for me was:
[HttpPost]
[IgnoreAntiforgeryToken]
public async Task<IActionResult> Index()
This apparently applies to dot Net Core versions: see Microsofts Documentation
Hope this helps someone.
That's works in my Asp.net Framework 4.7, try below code for the webhook
[HttpPost]
[Route("api/[controller]/webhook")]
public async Task<HttpResponseMessage> ProcessRequest()
{
var json = await new StreamReader(HttpContext.Current.Request.InputStream).ReadToEndAsync();
try
{
var stripeEvent = EventUtility.ParseEvent(json);
// Handle the event
if (stripeEvent.Type == Events.PaymentIntentSucceeded)
{
var paymentIntent = stripeEvent.Data.Object as PaymentIntent;
// Then define and call a method to handle the successful payment intent.
// handlePaymentIntentSucceeded(paymentIntent);
}
else if (stripeEvent.Type == Events.PaymentMethodAttached)
{
var paymentMethod = stripeEvent.Data.Object as PaymentMethod;
// Then define and call a method to handle the successful attachment of a PaymentMethod.
// handlePaymentMethodAttached(paymentMethod);
}
// ... handle other event types
else
{
// Unexpected event type
Console.WriteLine("Unhandled event type: {0}", stripeEvent.Type);
}
return Request.CreateResponse(HttpStatusCode.OK);
}
catch (StripeException e)
{
return Request.CreateResponse(HttpStatusCode.BadRequest);
}
//Modification and Saving Data
}
After adding this webhook , you can test on locally from https://stripe.com/docs/webhooks/test this link
So i have this ASP.NET Core on my local machine, i have installed the prerequisites and after running the application locally, the response was correct from the web browset that it was not found.
Okay, i am trying to invoked this API via Postman and i couldnt determine why i cant access it though i already checked the routings.
Below is the sample template
[HttpGet]
[Route("Details")]
public async Task<IActionResult> GetDetails(string value = null)
{
var response = new ListModelResponse<SomeModel>() as IListModelResponse<SomeModel>;
try
{
response.Model = await GetDetailsRepository
.GetDetailsSS(value)
.Select(item => item.ToViewModel())
.OrderBy(item => item.Name)
.ToListAsync();
}
catch (Exception ex)
{
response.DidError = true;
response.ErrorMessage = ex.Message;
}
return response.ToHttpResponse();
}
And in application insights of visual studio, i can see that it is invoking the API but it seems it can't get through.
Check this insights snippet
Other API's are working fine, it seems that i am missed something that i can't figure out right now.
For the routing i have this.
[Route("api/[controller]")]
I have also checked the Token and as i parsed it, i am getting the required info to access this API.
Thanks Lads!
It doesn't seem that you have the name of the controller in the request url.
api/[controller]/Details?value=CAT...
This error is due to the incorrect url present in the request. The correct URL has to be https://localhost:44309/api/your-controller-name/Details?value=CAT
ie. If the Controller name is ProductsController, then the URL has to be https://localhost:44309/api/Products/Details?value=CAT.
[Route("api/[controller]")]
public class ProductsController : Controller
{
[HttpPost("Details")]
public async Task<IActionResult> GetDetails(string value = null)
{
...
}
}
I have the following action that gets a Question model from my API given the Question title from an autocomplete input. The action is working fine with titles that do not contain a question mark (Ex. How old are you). But if I give a title containing a question mark (Ex. How old are you?) the model is not returned as the question mark is being removed in the process.
I tried HttpUtility.UrlDecode() method but with no luck .
Below you can find my requests
[HttpGet]
public async Task<IActionResult> GetQuestionAsync(string question) {
Questions q = new Questions();
HttpClient client = _api.Initial();
HttpResponseMessage res = await client.GetAsync("api/Search/" + question);
if (res.IsSuccessStatusCode) {
var result = res.Content.ReadAsStringAsync().Result;
q = JsonConvert.DeserializeObject<Questions>(result);
}
return View(q);
}
[Produces("application/json")]
[HttpGet]
[Route("{keyword}")]
public async Task<IActionResult> GetByString([FromRoute(Name = "keyword")] string keyword) {
if (!ModelState.IsValid) {
return BadRequest(ModelState);
}
var question = await _context.Questions
.SingleOrDefaultAsync(m => m.Question == HttpUtility
.UrlDecode(keyword.ToString()));
if (question == null) {
return NotFound();
}
return Ok(question);
}
I expect to be able to get questions including ? from my API. Is there a way to achieve this?
Note that in Swagger, the API Get request is working fine!
You need to use HttpUtility.UrlEncode - not Decode. You want to change the ? into an encoded character before sending it in the URL. HttpUtility.UrlDecode does the opposite.
Working on a web api restful service.
I have a table called tests. The primary key is auto-increment. Each row contains a username and a test question. This DB is not really optimised, but it doesn't need to be.
Because the primary key is just an int to keep each row unique, there are many rows with duplicate usernames. This is fine.
I want to be able to return all rows with a matching username.
I want to be able to do it with a get request with the url: www.mywebsite.com/api/tests/{username}
The default controller methods in Visual Studio are only able to search by primary key to return one unique result.
This is something like what I want, but it doesn't work. 500 error. I'm not knowledgeable on debugging either, so point me in the right direction there if possible so I can provide more info.
// GET: api/Tests/robert
[ResponseType(typeof(Test))]
public async Task<IHttpActionResult> GetTest(string id)
{
//This is the default approach that just searches by primary key
//Test test = await db.Tests.FindAsync(id);
/*This is roughly what I want. Compiles, but doesn't work.*/
var query = "SELECT* WHERE id=" + id;
Test test = db.Tests.SqlQuery(query, id);
if (test == null)
{
return NotFound();
}
return Ok(test);
}
Let me know where I screwed up. I've been blundering over this for hours. I don't claim to be particularly good at any of this.
Try declaring your method like this
[RoutePrefix("api")]
public class HisController : ApiController
{
[HttpGet]
public HttpResponseMessage Test(string name) {...}
}
Also, I would recommend You to use entity framework
[RoutePrefix("api")]
public class HisController : ApiController
{
[HttpGet]
public HttpResponseMessage Test(string name)
{
using (MyEntities bm = new MyEntities())
{
var usr = bm.Users.Where(u => u.Name == name ).ToList();
if (usr.Count() > 0)
return Request.CreateResponse(HttpStatusCode.OK, new
{
Success = true
,
Message = "Total users: " + usr.Count()
,
Data = usr
});
return Request.CreateResponse(HttpStatusCode.NotFound, new { Success = false, Message = "No users found..." });
}
}
}
I have an MVC5 application, ASP.NET, that, when creating a new record and clicking submit, it calls my WebAPI (version 2 - the new one) to insert the record into the database. Problem is, it's not hitting the POST method in my WebAPI. Anyways, here's my MVC5, front end application code for "Create":
[HttpPost]
public ActionResult Create(BulletinBoard bulletinBoard)
{
bulletinBoard.CreatedDate = DateTime.Now;
bulletinBoard.CreatedBy = HttpContext.User.Identity.Name;
response = client.PostAsJsonAsync("api/bulletinboard", bulletinBoard).Result;
if (response.IsSuccessStatusCode)
{
return View("Index");
}
else
{
LoggerHelper.GetLogger().InsertError(new Exception(string.Format(
"Cannot create a new feedback record due to HTTP Response Status Code not being successful: {0}", response.StatusCode)));
return View("Problem");
}
}
I already defined "client" in my constructor and gave it the base URL for my WebAPI - keep in mind that GET works - so it's not a problem with my URL. I can also manually go to my WebAPI URL and get data back in my browser.
Here's my WebAPI code:
// POST api/bulletinboard
public HttpResponseMessage PostBulletinBoard(BulletinBoard bulletinBoard)
{
if (ModelState.IsValid)
{
db.BulletinBoards.Add(bulletinBoard);
db.SaveChanges();
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Created, bulletinBoard);
return response;
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}
}
This worked when I was using WebAPI version 1 which had a different naming convention for the GET and POST and PUT methods.
So, when the URL for the POST request is called (the line that's response = client.PostAsJsonAsync...), the request never hits my POST method in my WebAPI and consequently, no records are inserted into my database. What am I doing wrong?
According to the comments it appears that you have POSTed invalid data (according to the validation rules you defined in your BulletinBoard model) and this validation simply fails. So to fix the issue make sure you are sending valid data.
I think there might be a few reasons why it doesn't hit your post method. Here is my example of Post method. The things you should note is method name and FromBody attribute
public async Task<HttpResponseMessage> Post([FromBody]FoodProduct foodProduct)
{
UnitOfWork.FoodRepository.Edit(foodProduct);
await UnitOfWork.SaveAsync();
return Request.CreateResponse(HttpStatusCode.OK);
}
I also like to use this new RoutePrefix Attribute on my controller, it works perfectly and looks good.
[RoutePrefix("api/Food")]
public class FoodController : BaseApiController
{
///some code here
}