I am trying to invoke External APIs from AWS lambda function written in c#. The Lamda function is deployed in No VPC mode. I am calling this function from Alexa skill. The code works fine for an http request, but its not working for https.
The below code works when I use http://www.google.com.
But, if I replace http with https, then I get the error in the cloud watch saying:
"Process exited before completing request."
Even the log written in catch is not getting logged in cloud watch.
public class Function
{
public const string INVOCATION_NAME = "bingo";
public async Task<SkillResponse> FunctionHandler(SkillRequest input, ILambdaContext context)
{
var requestType = input.GetRequestType();
if (requestType == typeof(IntentRequest))
{
string response = "";
IntentRequest request = input.Request as IntentRequest;
response += $"About {request.Intent.Slots["carmodel"].Value}";
try
{
using (var httpClient = new HttpClient())
{
Console.WriteLine("Trying to access internet");
//var resp=httpClient.GetAsync("http://www.google.com").Result // this works perfect!
var resp = httpClient.GetAsync("https://www.google.com").Result; // this throws error
Console.WriteLine("Call was successful");
}
}
catch (Exception ex)
{
Console.WriteLine("Exception from main function " + ex.Message);
Console.WriteLine(ex.InnerException.Message);
Console.WriteLine(ex.StackTrace);
}
return MakeSkillResponse(response, true);
}
else
{
return MakeSkillResponse(
$"I don't know how to handle this intent. Please say something like Alexa, ask {INVOCATION_NAME} about Tesla.",
true);
}
}
private SkillResponse MakeSkillResponse(string outputSpeech, bool shouldEndSession,
string repromptText = "Just say, tell me about car models to learn more. To exit, say, exit.")
{
var response = new ResponseBody
{
ShouldEndSession = shouldEndSession,
OutputSpeech = new PlainTextOutputSpeech { Text = outputSpeech }
};
if (repromptText != null)
{
response.Reprompt = new Reprompt() { OutputSpeech = new PlainTextOutputSpeech() { Text = repromptText } };
}
var skillResponse = new SkillResponse
{
Response = response,
Version = "1.0"
};
return skillResponse;
}
}
The issue was resolved by updating the library version.
System.Net.Http v4.3.4 was not completely compatible with dotnet core v1.
So outbound http calls were working but not https calls. Changing the version of System.net.http resolved the issue.
Related
I am a total noob in C# and tried to add an automated mail services to my backend API for an Angular FrontEnd.
It works properly as intended for one time, but cannot be used a second time. I guess I am violating some object rules, maybe someone is able to point out my mistake.
This is an excerpt of my file UserAuthController.cs which includes the register function. When registration on my website is successful it shall also call the API Service from my automated mail system.
I didn't know how to include the function properly so I've added it with a new namespace.
namespace Gogo_Api.Controllers
{
[RoutePrefix("UserAuth")]
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class UserAuthController : ApiController
{
private readonly IUserAuthManager _userAuthManager;
public UserAuthController()
{
}
public UserAuthController(IUserAuthManager userAuthManager)
{
this._userAuthManager = userAuthManager;
}
[HttpPost]
[Route("Register")]
public HttpResponseMessage Register(UserDetails user)
{
var response = new RegisterResponse();
response.code = _userAuthManager.Register(user);
if (response.code == 1)
{
response.message = "Registration successful ";
//Including API Service here...
Sendinblue.Program RegisterMail = new Sendinblue.Program();
RegisterMail.Main(user.email, user.displayName, user.country);
RegisterMail = null;
}
else if (response.code == 2)
{
response.message = "User already registered ";
}
else if (response.code == 0)
{
response.message = "Error occured";
}
return Request.CreateResponse(HttpStatusCode.OK, response);
}
}
}
namespace Sendinblue
{
class Program
{
public void Main(string userMail, string userName, string userCountry)
{
Configuration.Default.ApiKey.Add("api-key", "MYKEY");
var apiInstance = new ContactsApi();
string email = userMail;
JObject attributes = new JObject();
attributes.Add("USERNAME", userName);
attributes.Add("COUNTRY", userCountry);
List<long?> listIds = new List<long?>();
listIds.Add(5);
try
{
var createContact = new CreateContact(email, attributes, emailBlacklisted, smsBlacklisted, listIds, updateEnabled, smtpBlacklistSender);
CreateUpdateContactModel result = apiInstance.CreateContact(createContact);
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
Console.WriteLine(e.Message);
}
}
}
}
I have added 'RegisterMail = null;' because I thought I need to delete my object first before using it again, but still it works only for the first time.
How would I be able to call my function multiple times?
Thanks
Thanks #Richard Barker, your comment helped me fix it.
I have moved everything out of the Controller and had to move
Configuration.Default.ApiKey.Add...
apiInstance = new ContactsApi();
to a one-time call in the Initializer, so the API Call and ContactsApi is only created once, instead of everytime.
I'm performing a simple GET request to a ASP.NET Core Web API, I created, within Xamarin.Forms 4.8. For this I'm using the following code:
public async Task<Result<bool>> GetSomeResult()
{
var client = service.Client;
HttpResponseMessage response = null;
try
{
response = await client.GetAsync(new UriHelper(endpoint, "someEndpoint")).ConfigureAwait(false);
response.EnsureSuccessStatusCode(); // will throw a exception on a non-success status code
return await response.Content.ReadAsAsync<bool>().ConfigureAwait(false);
}
catch (Exception ex)
{
if (response?.StatusCode == HttpStatusCode.InternalServerError)
{
// !!! The error occurs in the next line !!!
SomeErrorClass id = await response.Content.ReadAsAsync<SomeErrorClass>().ConfigureAwait(false);
return new Result<bool>(SomeErrorClass.ToString());
}
return new Result<bool>(ex);
}
}
The service is a singleton that's being injected into the constructor (via DryIoc) of the surrounding class. This service is a wrapper around a HttpClient instance and does nothing more than providing a facility to configure the HttpClient (as well as disposing and replacing the instance when its configuration has been chaned). So after configuration the same HttpClient instance will be returned whenever service.Client is used. The code is something like this:
public class ServiceConnection
{
private const string Localhost = "https://127.0.0.1";
private readonly PreferenceService preferences;
private readonly IHttpClientHandlerProvider handlerProvider;
public HttpClient Client { get; private set; }
public ServiceConnection(PreferenceService preferences, IHttpClientHandlerProvider handlerProvider)
{
this.preferences = preferences;
this.handlerProvider = handlerProvider;
Client = CreateClient();
}
private HttpClient CreateClient()
{
var handler = new TimeoutHandler()
{
DefaultTimeout = TimeSpan.FromSeconds(10),
InnerHandler = handlerProvider?.GetHandler(opt =>
{
opt.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
opt.UseDefaultCredentials = true;
opt.AllowAutoRedirect = true;
})
};
Uri.TryCreate($"{preferences.Server ?? Localhost}/api/", UriKind.Absolute, out var baseAddress);
var client = new HttpClient(handler, true)
{
BaseAddress = baseAddress,
Timeout = TimeSpan.FromSeconds(20),
};
client.DefaultRequestHeaders.Add(CustomHttpHeaders.DeviceId, preferences.UUID);
return client;
}
public void RefreshConnection()
{
Client?.Dispose();
Client = CreateClient();
}
}
The problem is the line in which I try to read the HttpContent from the HttpResponseMessage. Whenever I call it I get a System.ObjectDisposedExceptionsaying 'Cannot access a disposed object.
Object name: 'System.Net.Http.StreamContent'.'.
I already tried setting the disposeHandler parameter of the HttpClient to true and false since I've seen some people on the internet suggesting that that'll fix the issue, but no luck for me so far.
The problem isn't disposal. There are two problems here, one causing the other:
Exceptions are used for flow control. Instead of throwing on failure, you could check the response's status code
Before .NET Core 3, EnsureStatusCode closes the stream.
The root cause is the use of exceptions for flow control.
This can be solved by fixing the first problem, which would also improve performance a lot. Throwing exceptions is expensive, several orders of magnitude more expensive than an if. As in 100-1000x times faster :
if (response.IsSuccessStatusCode)
{
var value=await response.Content.ReadAsAsync<bool>();
return value; //Should this be `new Result(value) ??
}
else if (response.StatusCode == HttpStatusCode.InternalServerError)
{
var id = await response.Content.ReadAsAsync<SomeErrorClass>();
return new Result<bool>(SomeErrorClass.ToString());
}
else
{
var reason=$"{response.StatusCode}:{response.ReasonPhrase}";
return new Result<bool>(reason);
}
Throwing would obfuscate the response phrase too, which would make troubleshooting a lot harder
I have a MVC 5 backend written in C#. It serves MVC views written in Razor and also some Angular 2 pages.
What is the best way to handle potential errors when calling server from client? I really would like to establish a pattern that is robust and works in all situations. Below is what I have tried so far.
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new Exception("Dummy error");
return GetCompressedResult(json);
}
catch (Exception ex)
{
throw new HttpException(501, ex.Message);
}
}
private FileContentResult GetCompressedResult(string json)
{
// Transform to byte array
var bytes = Encoding.UTF8.GetBytes(json);
// Compress array
var compressedBytes = bytes.Compress();
HttpContext.Response.AppendHeader("Content-encoding", "gzip");
return new FileContentResult(compressedBytes, "application/json");
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleError);
response.subscribe(response => {
// Process valid result ...
},
err => { console.error(err); }
);
};
private handleError(error: Response | any) {
let errMsg: string;
if (error instanceof Response) {
const body = JSON.parse(JSON.stringify(error || null))
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
return Observable.throw(errMsg);
}
This is a printscreen of the error object processed by handleError method:
This all raises some questions:
Is it correct to throw custom HttpException from server?
Is handleError method correct or maybe too complex?
On client side I would like to see the custom error message, but currently it is just found in an enormous "blob" of HTML that is nasty to parse.
Is client side error handling necessary BOTH in get call and subscribe action?
My current suggestion is to let server respond with Json object for all handled exceptions.
On client side I check result object for possible error property before handling valid result.
The handleResponseError method will parse typed Response object and throw observable message. But at least my browser (Chrome 57) seems to automatically log response errors to console. So if subscriber need no specific extra handling for different errors, then the subscriber need no extra action for err object.
Please feedback if there are better ways!
Backend C# code:
public class MyController : Controller
{
[HttpGet]
public ActionResult GetUsers()
{
try
{
// Lot of fancy server code ...
throw new ArgumentException("Dummy error");
// Normal return of result ...
}
catch (Exception ex)
{
return Json(new { error = $"{ex.GetType().FullName}: '{ex.Message}'" }, JsonRequestBehavior.AllowGet);
}
}
}
Client side Angular 2 code:
public loadDataFromServer() {
let response = this.http.get(this.urlGetData)
.map((res: Response) => res.json())
.catch(this.handleResponseError);
response.subscribe(result => {
if (result.error) {
this.displayJsonError(this.urlGetUsers, result.error);
}
else {
// Process valid result
}
});
};
private handleResponseError(value: Response | any) {
let errorMessage = value.toString();
let response = value as Response;
if (response) {
errorMessage = `${response.status}: ${response.statusText}\n${response.toString()}`;
}
if (value.error) {
errorMessage = value.error;
}
if (value.message) {
errorMessage = value.message;
}
return Observable.throw(errorMessage);
}
private displayJsonError(url: string, error: string) {
console.error(`Call to '${url}' failed with ${error}`);
}
So I am looking for a pattern on how to handle exceptions. Specifically I want to be able to pass the exception message on to the client from a Web API controller.
The client is using a third party library which deals with a call to the API
as
this.msgs = [];
let xhr = new XMLHttpRequest(),
formData = new FormData();
for(let i = 0; i < this.files.length; i++) {
formData.append(this.name, this.files[i], this.files[i].name);
}
xhr.upload.addEventListener('progress', (e: ProgressEvent) => {
if(e.lengthComputable) {
this.progress = Math.round((e.loaded * 100) / e.total);
}
}, false);
xhr.onreadystatechange = () => {
if(xhr.readyState == 4) {
this.progress = 0;
if(xhr.status == 200)
this.onUpload.emit({xhr: xhr, files: this.files});
else
this.onError.emit({xhr: xhr, files: this.files});
this.clear();
}
};
xhr.open('POST', this.url, true);
xhr.send(formData);
My current call back function is such
errorComplete(event: any) {
console.log("upload error");
}
notice that on error the library just wraps up the XMLHttpRequest and passes it on to my call back function.
so in the controller I have created a test line as follows
throw new Exception("This is a test message");
This is to simulate an unexpected exception
currently the return code in the XMLHttpRequest is a 500 and the text is the html that .Net generates when an exception occurs.
yes the method in my controller will need to wrapper in a try-catch but I am not sure of what code to put in the catch so I can send the error message down to the client and it can handle it and not take down the application.
the current use case I am looking at is the user uploads a file to the system but there is already a file with the specified name in the system. And renaming the file is not an option! I need to notify the user that there is already a file with that name in the system.
google has not revealed a way to pass the message back so I can process it.
Thank you Nkosi- your comment got me on the right track.
I implemented some middleware.
public class UIExceptionHandler
{
RequestDelegate _next;
public UIExceptionHandler(RequestDelegate next)
{
this._next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await this._next(context);
}
catch (Exception x)
{
if (!context.Response.HasStarted)
{
context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
context.Response.Headers["Message"] = x.Message;
}
}
}
}
public static class UIExcetionHandlerExtensions
{
public static IApplicationBuilder UseUIExceptionHandler(this IApplicationBuilder builder)
{
return builder.UseMiddleware<UIExceptionHandler>();
}
}
and in the configure method of the startup
app.UseUIExceptionHandler();
then on the client I can do
errorComplete(event: any) {
var errorMessage = event.xhr.getResponseHeader('Message');
console.log(errorMessage);
}
If anyone sees an issue with this solution please let me know
I am developing client-server application. The server side is asp.net web api. I did simple web api application and simple android client. When I set up web api it works. And I get json. But how I can get data from my clietn application? I conncted my Android-device and trying to get data via WI-FI from my web api. For web api I create a seld hosting.
protected Boolean doInBackground(String... urls) {
BufferedReader in = null;
try {
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet("http://124.18.240.169:3890/api/values/1/");
HttpResponse response = client.execute(request);
in = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();
String page = sb.toString();
System.out.println(page);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return true;
}
It is my web api
static void Main(string[] args)
{
var config = new HttpSelfHostConfiguration("http://124.18.240.169:3890");
config.Routes.MapHttpRoute(
"API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
using (HttpSelfHostServer server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
where
124.18.240.160 is my IP whcih i found in ipconfig. What I should to do (I tried to do like
http://localhost) but it not wrok for Android app
You should consider using a library to help handle async callbacks. It can be super helpful for this.
This is the one I usually use:
LoopJ's Async HTTP Callback Library
This will handle GET and POST requests with a lot of cool features such as custom timeouts, JSON format, onSuccess() and onFailure() methods, etc. There's a lot of working examples of this library too. I've used it in all my apps and haven't had any problems yet!
Hopefully this helps.