I need the "WinForm" application for correspondence in viber.
"Webhook" is planned to receive data (events) from viber, then the data will be used in the application "WinForm".
I did:
created the project "ASP.NET Web Application (.NET Framework)";
chose a template - "Empty" + "MVC" + "API";
added controller "Controller MVC 5 - empty". Controller name "HookController";
I run the application "Postman";
"Postman". I set the request "POST";
"Postman". I set the link http://localhost:44836/Hook;
"Postman". Click "SEND";
The result, see the picture "- = RESULT = -";
If I understand the theory correctly, then after performing the "Postman" action. I click "SEND", the ViberProcess (HttpContext context) method should be executed in the HookController.cs controller and the code should stop at the breakpoint.
This is not happening.
Documentation Viber REST API - link
Question.
How to make a Webhook?
Code HookController.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
//
using System.Runtime.Remoting.Contexts;
namespace WebAppl1.Controllers
{
public class HookController : Controller
{
// GET: Hook
//public ActionResult Index()
//{
// return View();
//}
[HttpPost]
// [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public void ViberProcess(HttpContext context)
{
try
{
Stream s = context.Request.InputStream;
// Stream s = Context.Request.InputStream;
// or Stream s = HttpContext.Current.Request.InputStream;
s.Position = 0;
StreamReader reader = new StreamReader(s);
string jsonText = reader.ReadToEnd();
// Other code that converts json text to classes
}
catch (Exception e)
{
// .....
}
}
}
}
7. "Postman". Click "SEND";
8. The result, see the picture "- = RESULT = -";
Server error in application '/'.
Could not find this resource.
Description: HTTP 404. The resource (or one of its dependencies) may have been deleted, received a different name, or may be temporarily unavailable. Review the following URL and verify that it is correct.
Requested URL: / Hook
Version Information: Microsoft .NET Framework Version 4.0.30319; ASP.NET version: 4.7.3062.0
Update_1
I use the link http://localhost:44836/api/Hook
The code does not stop at breakpoint.
Result:
{
"Message": "Could not find the HTTP resource corresponding to the request URI \" http://localhost:44836/api/Hook\ ".",
"MessageDetail": "Could not find the type corresponding to the controller \" Hook \ " . "
}
I use the link http://localhost:44836/Hook/ViberProcess
The code does not stop at breakpoint.
Result
Server error in application '/'.
For this object, no parameterless constructors are defined.
Description: An unhandled exception occurred during the execution of the current web request.
Examine the stack trace for more information about this error and the code snippet that caused it.
Exception Details: System.MissingMethodException: No parameter-less constructors are defined for this object.
Source Error:
An unhandled exception occurred during the execution of the current web request.
Information on the origin and location of the exception can be obtained using the following exception stack trace.
Just remove the HttpContext context in your ViberProcess action.
So, the method will become
public IActionResult ViberProcess()
{
Stream s = HttpContext.Current.Request.InputStream;
//... continue your code from here.
}
The reason behind this is, You have mention HttpContext context as an Argument of ViberProcess but while you are sending request it will search with the Exact schema.
So, in your request, you can not pass the HttpContext from anywhere. So, this request will never be found.
Here is the screenshot:
Try this an let me know if you still have an issue.
Related
I would like to make a successful API call, then print the values in order to see if it works. My main goal is to analyze the data, after I can make a successful API call, and build a systematic strategy for trading.
System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)
namespace marketstacktest
{
class Program
{
static async Task Main(string[] args)
{
Console.WriteLine("Hello World!");
var options = Options.Create(new MarketstackOptions() { ApiToken = "secretTokenHere" });
var marketstackService = new MarketstackService(options, NullLogger<MarketstackService>.Instance);
var appleSymbol = "AAPL";
var fromDate = DateTime.Now.AddDays(-200);
var toDate = DateTime.Now;
//error at the await System.Net.Http.HttpRequestException: "Response status code does not indicate success: 403 (Forbidden)."
List<Marketstack.Entities.Stocks.StockBar> stock = await marketstackService.GetStockEodBars(appleSymbol, fromDate, toDate);
foreach (var stock_i in stock)
{
Console.WriteLine($"close: {stock_i.Close}");
}
}
}
}
In the API manual, which is directly linked from the github, it gives information about all of the error codes. The relevant ones here are these two:
Code
Type
Description
403
https_access_restricted
HTTPS access is not supported on the current subscription plan.
403
function_access_restricted
The given API endpoint is not supported on the current subscription plan.
Their class library on github is just wrapping a json REST api. Every call to the API is just an http request, returning data as json objects. The 403 error indicates that your request was accepted as a valid request, but intentionally rejected by the server for some reason. And according to the docs, the error was because your account is not allowed access to either https or to the type of request.
Their free-tier subscription only includes end-of-day data, which is what you requested, so it wouldn't make sense for that not to be allowed. So, your app is almost certainly making an https call.
I went to the examples at the very beginning of their quick start guide, and chose the end-of-day example to match your app, and clicked on the link. It worked, and gave a bunch of json records. But, the request they made was using 'http' not 'https'.
Changing the requst to 'https' elicited a 403 response with this content (formatted for readability):
{
"error":
{
"code": "https_access_restricted",
"message": "Access Restricted - Your current Subscription Plan does not support HTTPS Encryption."
}
}
At this point we have enough to be almost certain that this is your issue. The final thing is to go look up how to turn https requests off in their class library. To avoid having to go through the code, I checked the help at the bottom of the page one more time, and found this (formatted for readability):
var options = Options.Create(new MarketstackOptions(){
ApiToken = apiKey,
MaxRequestsPerSecond = 3,
Https = true
});
Welp. This should probably be in their first example, since that's what people are most likely to try first, but it's not. So, to stop trying to make http requests, you just need to set the Https option to false in your code. You just need to add that to the options in your code, like so:
var options = Options.Create(new MarketstackOptions(){
ApiToken = "secretTokenHere",
Https = false
});
I will leave the testing to you, but from the browser test, we know that the request should work, unless there's a bug in their library. Given the information that was available, this is almost certainly the issue.
I am working on a project in ASP.NET Core 3.1. by using clean architecture which is composed of 4 different layers namely Persistence - Domain - Application - Web.
In the Web layer, I have an Admin area which is going to be made with React and also I have an online store which will be using this Admin area but it will be made as an html online store without using REST API. My REST API routes is like this: localhost:5001/api/v1/...
I wanted to know, how could I make a custom error handling middleware which will be able to send status code and error message as json when there is an error in my REST API service and at the same time, it will be able to send them as html views when there is an error in html pages which don't consume REST APIs.
One way would be to differentiate the requests by path.
In your Configure method:
app.UseWhen(o => !o.Request.Path.StartsWithSegments("/api", StringComparison.InvariantCultureIgnoreCase),
builder =>
{
builder.UseStatusCodePagesWithReExecute("/Error/{0}");
}
);
This assumes that your API Controllers are marked with [ApiController] attribute and that you use at least compatibility version of 2.2 which will render JSON Problem Details (RFC7807).
Edit: Unintentionally left out the HTML part. You also need a controller action that routes the Error codes to render HTML results. Something like
[AllowAnonymous]
[Route("/Error/{code:int?}")]
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error(int? code)
{
ViewBag.Code = code.GetValueOrDefault(500);
return View();
}
and a matching Razor page such as
<h1>Error #(ViewBag.Code ?? 500)</h1>
I have not tested this code, however, what do you think about using customExceptions and then handling your response based on the exception thrown?
public async Task Invoke(HttpContext httpContext)
{
try {
await _next.Invoke(httpContext);
}
catch (RestApiException ex) {
httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
httpContext.Response.ContentType = "application/json";
string jsonString = JsonConvert.SerializeObject(ex.Message);
await httpContext.Response.WriteAsync(jsonString, Encoding.UTF8)
}
catch (HtmlPagesException ex)
{
httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/html";
//write the html response to the body -> I don't know how to do this yet.
}
}
I am trying to call an API like this:
var client = new HttpClient();
client.DefaultRequestHeaders.Add("apiKey", Token);
**var result = await client.GetStringAsync(GetUrl($"accounts/{accountID}/menu?skip=0&limit=1"));**
var menuList = JsonConvert.DeserializeObject<List<Menu>>(result);
but getting System.AggregateException on GetStringAsync, error CS0103: The name 'InnerExceptionCount' does not exist in the current context
and Exception Message
One or more errors occurred. (Response status code does not indicate success: 404 (Not Found).)
I see that this is returned in result
Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}
I tried to make call using postman with same url and apikey in header and I see the results.
Can you please suggest what is wrong with above code. Api key expects only an apiKey in header.
Thanks.
Anytime that an async call fails you'll get an AggregateException, what's important is the inner exception within that.
It looks like your inner exception is 404 Not Found, which means that you're not calling the correct URL.
You said it's working in postman, that's great. To find the root cause I suggest the following:
Start Fiddler
Make the call through postman, view the request in Fiddler
Make the call through your C# code, view the request in Fiddler
Comparing the Postman request against the C# request should tell you where the error is.
Strange one here, code calls the method, and the method grabacat is executed on the server (I debug it and step through right to the end). The code returns to the client, but the response it received was 500 Internal Server Error with the above message. So it's saying it couldn't find the web API method that it just called successfully.
using (var response = await client.PostAsXmlAsync("cats/grabacat", mycatprefs))
{
if (response.IsSuccessStatusCode) // 500 cats/grabacat not found
Controller code:
[Route("~/api/cats/grabacat")]
[HttpPost]
public async Task GrabACat()
{
}
After debugging, if I change it to public async Task<SomeObject> GrabACat() then it works OK. This lets me return an object back to the client. However I don't want to return anything back; I want it to be equivelent to calling a void method. It will examine the status code to determine if it was successful.
I have got it working by changing GrabACat to Task and returning new object(); but I am not sure why this is required. It seems crude to return an empty object just to get it to work.
Any ideas?
The WebAPI method has a Route attribute like this:
[Route("~/api/cats/grabacat")]
Which means the URL is wrong in the POST request - you are missing the /api prefix:
using (var response = await client.PostAsXmlAsync("api/cats/grabacat", mycatprefs))
//snip
This SO answer presents an elegant solution to handling 404 errors. I modified the code given in that answer to also handle 400 errors (the response that happens when someone feeds a "potentially dangerous" character my website). My code looks like this:
/// <summary> Handle "page not found" (HTTP 404) and "dangerous/invalid syntax" (HTTP 400) errors. </summary>
protected void Application_EndRequest()
{
// This code is adapted from: https://stackoverflow.com/a/9026941/1637105
var code = Context.Response.StatusCode;
if (code == 404 || code == 400) {
Response.Clear();
var rd = new RouteData();
rd.DataTokens["area"] = "AreaName"; // In case controller is in another area
rd.Values["controller"] = "Errors";
rd.Values["action"] = "NotFound";
IController c = new ErrorsController();
c.Execute(new RequestContext(new HttpContextWrapper(Context), rd));
}
}
My problem is that if I have glimpse installed then, when I get a 400 error (for example, if I navigate to http://example.com/HiBob:), I get:
An exception of type 'System.NullReferenceException' occurred in Glimpse.Core.dll
Since glimpse doesn't seem to have any problem with the 404 errors that get rerouted through this code, I assume that glimpse is choking on the request path.
Is there something I can do in this code to URL-encode the request path before I send the new request off to be executed by the MVC pipeline?
EDIT: I updated the glimpse NuGet package to the latest version and the problem seems to be gone. Life is good. I'm an idiot (for not making sure I have the latest stuff before complaining that it doesn't work).