Good moring Team,
Since yersterday im trying to post an API using Flurl but im still getting this error and the post code block is not executed, i dont know where should be the issue.
bellow is my code:
public async Task<GetCustomerAcctsDetail_Model> GetCustomerAcctsDetail(string num_compte)
{
try
{
//getting fcub endpoint
var customerdetail_api = Configuration.GetValue<string>("APIs:accountdetails");
var api_key = Configuration.GetValue<string>("APIs:Authorisation_key");
var customer_details= await customerdetail_api
.WithHeader("Accept", "application/json")
.WithHeader("Authorization",api_key)
.PostJsonAsync(new
{
channel_code = "MYCHANELCODE",
account_no = num_compte
})
.ReceiveJson<GetCustomerAcctsDetail_Model>();
return customer_details;
}
catch(Exception Ex)
{
_logger.LogError(Ex.Message);
return null;
}
}
i am always getting this error:
Id = 17, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"
and the post is never executed.
can someone help please??
Related
i am new to integration tests. I have a controller method which adds a user to the database, as shown below:
[HttpPost]
public async Task<IActionResult> CreateUserAsync([FromBody] CreateUserRequest request)
{
try
{
var command = new CreateUserCommand
{
Login = request.Login,
Password = request.Password,
FirstName = request.FirstName,
LastName = request.LastName,
MailAddress = request.MailAddress,
TokenOwnerInformation = User
};
await CommandBus.SendAsync(command);
return Ok();
}
catch (Exception e)
{
await HandleExceptionAsync(e);
return StatusCode(StatusCodes.Status500InternalServerError,
new {e.Message});
}
}
As you have noticed my method returns no information about the user which has been added to the database - it informs about the results of handling a certain request using the status codes. I have written an integration test to check is it working properly:
[Fact]
public async Task ShouldCreateUser()
{
// Arrange
var createUserRequest = new CreateUserRequest
{
Login = "testowyLogin",
Password = "testoweHaslo",
FirstName = "Aleksander",
LastName = "Kowalski",
MailAddress = "akowalski#onet.poczta.pl"
};
var serializedCreateUserRequest = SerializeObject(createUserRequest);
// Act
var response = await HttpClient.PostAsync(ApiRoutes.CreateUserAsyncRoute,
serializedCreateUserRequest);
// Assert
response
.StatusCode
.Should()
.Be(HttpStatusCode.OK);
}
I am not sure is it enough to assert just a status code of response returned from the server. I am confused because, i don't know, shall i attach to assert section code, which would get all the users and check does it contain created user for example. I don't even have any id of such a user because my application finds a new id for the user while adding him/her to the database. I also have no idea how to test methods like that:
[HttpGet("{userId:int}")]
public async Task<IActionResult> GetUserAsync([FromRoute] int userId)
{
try
{
var query = new GetUserQuery
{
UserId = userId,
TokenOwnerInformation = User
};
var user = await QueryBus
.SendAsync<GetUserQuery, UserDto>(query);
var result = user is null
? (IActionResult) NotFound(new
{
Message = (string) _stringLocalizer[UserConstants.UserNotFoundMessageKey]
})
: Ok(user);
return result;
}
catch (Exception e)
{
await HandleExceptionAsync(e);
return StatusCode(StatusCodes.Status500InternalServerError,
new {e.Message});
}
}
I believe i should somehow create a user firstly in Arrange section, get it's id and then use it in Act section with the GetUserAsync method called with the request sent by HttpClient. Again the same problem - no information about user is returned, after creation (by the way - it is not returned, because of my CQRS design in whole application - commands return no information). Could you please explain me how to write such a tests properly? Have i missed anything? Thanks for any help.
This is how I do it:
var response = (CreatedResult) await _controller.Post(createUserRequest);
response.StatusCode.Should().Be(StatusCodes.Status201Created);
The second line above is not necessary, just there for illustration.
Also, your response it's better when you return a 201 (Created) instead of the 200(OK) on Post verbs, like:
return Created($"api/users/{user.id}", user);
To test NotFound's:
var result = (NotFoundObjectResult) await _controller.Get(id);
result.StatusCode.Should().Be(StatusCodes.Status404NotFound);
The NotFoundObjectResult assumes you are returning something. If you are just responding with a 404 and no explanation, replace NotFoundObjectResult with a NotFoundResult.
And finally InternalServerErrors:
var result = (ObjectResult) await _controller.Get(id);
result.StatusCode.Should().Be(StatusCodes.Status500InternalServerError);
You can use integrationFixture for that using this NuGet package. This is an AutoFixture alternative for integration tests.
The documented examples use Get calls but you can do other calls too. Logically, you should test for the status code (OkObjectResult means 200) value and the response (which could be an empty string, that is no problem at all).
Here is the documented example for a normal Get call.
[Fact]
public async Task GetTest()
{
// arrange
using (var fixture = new Fixture<Startup>())
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var controller = fixture.Create<SearchEngineController>();
// act
var response = await controller.GetNumberOfCharacters("Hoi");
// assert
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
Assert.Equal(8, ((OkObjectResult)response.Result).Value);
}
}
}
private void SetupStableServer(FluentMockServer fluentMockServer, string response)
{
fluentMockServer.Given(Request.Create().UsingGet())
.RespondWith(Response.Create().WithBody(response, encoding: Encoding.UTF8)
.WithStatusCode(HttpStatusCode.OK));
}
In the example above, the controller is resolved using the DI described in your Startup class.
You can also do an actual REST call using using Refit. The application is self hosted inside your test.
using (var fixture = new RefitFixture<Startup, ISearchEngine>(RestService.For<ISearchEngine>))
{
using (var mockServer = fixture.FreezeServer("Google"))
{
SetupStableServer(mockServer, "Response");
var refitClient = fixture.GetRefitClient();
var response = await refitClient.GetNumberOfCharacters("Hoi");
await response.EnsureSuccessStatusCodeAsync();
var request = mockServer.LogEntries.Select(a => a.RequestMessage).Single();
Assert.Contains("Hoi", request.RawQuery);
}
}
I'm having a bit of difficulty with an AWS issue that doesn't seem to have that great of documentation.
I have my lambda function here:
public async Task<string> FunctionHandler(ConnectRequest request, ILambdaContext context)
{
AmazonLexClient lexClient = new AmazonLexClient();
var response = new PostTextResponse();
PostTextRequest postRequest = new PostTextRequest();
postRequest.BotName = "X";
postRequest.BotAlias = "X";
postRequest.UserId = Guid.NewGuid().ToString();
postRequest.InputText = "What Time Is My Appointment?";
try
{
response = await lexClient.PostTextAsync(postRequest);
context.Logger.Log(response.IntentName);
context.Logger.Log(response.DialogState);
}
catch (Exception ex)
{
context.Logger.Log($"EXCEPTION CAUGHT: {Environment.NewLine} {ex.ToJson()} {Environment.NewLine} {response.Message} {response.IntentName} {response.SlotToElicit}");
return "Error";
}
context.Logger.Log($"Success from lambda {Environment.NewLine} Message: {response.Message} {Environment.NewLine} " +
$"Dialog State:{response.DialogState}");
return "Success";
}
I am invoking this from a connect flow like so:
And what I'm getting back in return is:
"ErrorType": 2,
"ErrorCode": "DependencyFailedException",
"RequestId": "",
"StatusCode": 424,
"Message": "Invalid Lambda Response: Received error response from Lambda: Unhandled",
"Data": {},
"InnerException": {
"Response": {
"StatusCode": 424,
"IsSuccessStatusCode": false,
"ContentType": "application/json",
"ContentLength": 85,
"ResponseBody": {}
},
"Message": "Exception of type 'Amazon.Runtime.Internal.HttpErrorResponseException' was thrown."
Which I read in the Amazon PostText Documentation could mean a couple things:
If Amazon Lex does not have sufficient permissions to call a Lambda
function.
If a Lambda function takes longer than 30 seconds to execute.
If a fulfillment Lambda function returns a Delegate dialog action
without removing any slot values.
I have confirmed that my Lambda does have permission to use PostText and access Lex. I have tried changing my return type of my function to PostTextReponse with no luck, So I'm not sure where to go from here, there isn't much documentation for this kind of thing.
Any help is appreciated, thanks!
For anybody that is curious about this I have found an answer:
First off, when using a Lambda function like this it is a good idea to return an object of what you want. Which is what I ended up doing. You also need to set SessionAttributes in JSON format.
My code is working and is as follows now:
public async Task<LambdaResponseItem> FunctionHandler(ConnectRequest request, ILambdaContext context)
{
var client = new AmazonLexClient();
var response = new PostContentResponse();
var lambdaInfo = new Dictionary<string, string>();
var contentRequest = new PostContentRequest();
var postContentStream = new MemoryStream();
var postContentWriter = new StreamWriter(postContentStream);
try
{
var userInput = request.Details?.Parameters?.GetValueOrDefault("UserInput");
postContentWriter.Write(userInput); // Grab user input (utterance) value from AWS Connect.
postContentWriter.Flush();
postContentStream.Position = 0;
contentRequest.Accept = "text/plain; charset=utf-8";
contentRequest.BotName = "IntroGreeting";
contentRequest.BotAlias = EnvironmentVariables.IsProduction ? "Production" : "Development";
contentRequest.ContentType = "text/plain; charset=utf-8";
contentRequest.UserId = request.Details?.ContactData?.ContactId;
contentRequest.InputStream = postContentStream;
contentRequest.SessionAttributes = request.Details?.Parameters?.ToJson(); // * Must be in Json format or request will return error *
// POST to Lex
response = await client.PostContentAsync(contentRequest);
return new LambdaResponseItem(){
Content = ""
}
}
catch (Exception ex)
{
context.Logger.Log($"POST Request to Amazon Lex Failed {ex.ToJson()}");
}
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.
public IHttpActionResult Save(item)
{
try
{
result = MyRepository.Save(item);
return Ok(result);
}
catch
{
// What should I do here?
// I wish to return an error response how can i do that?
}
}
If it has no exception,I can return Ok.
But if there is an exception what should I do?
Note that I have javascript client
In Web API 2, you can use BadRequest to return an error message.
public IHttpActionResult Save(item)
{
try
{
result = MyRepository.Save(item);
return Ok(result);
}
catch
{
return BadRequest("Error message");
}
}
FYI: Do not use try catch block just to swallow an exception. I personally do not like using try catch block inside Action method. Instead, I let Web API 2 Global Exception Handler handles exceptions. It is the out of the scope of your original question.
Create a model to hold what error information you want to return and pass that.
public IHttpActionResult Save(item) {
try {
result = MyRepository.Save(item);
return Ok(result);
} catch {
// What should I do here? Create a model to hold the data you want to return
var myErrorModel = new {
code = "My custom error code or 500 server error code",
message = "some friendly error message"
};
// I wish to return an error response how can i do that?
var response = Request.CreateResponse(HttpStatusCode.InternalServerError, myErrorModel);
return ResponseMessage(response);
}
}
In your javascript client in the error handler you can then access the model properties and handle the error as you see fit.
var handleResponse = function (data) {
var code = data.code;
var message = data.message
};
UPDATE:
Agreeing with #Win, I personally don't like doing this in the controller actions as it is a Cross-cutting concern and have basically moved everything from within the catch block into a global error handler.
You can use HttpResponseException to send an error message.
public IHttpActionResult Save(item)
{
try
{
result = MyRepository.Save(item);
return Ok(result);
}
catch
{
var resp = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent(string.Format("Error Message!!"),
ReasonPhrase = "Error Reason phrase"
};
throw new HttpResponseException(resp);
}
}
Use HttpResponseException as below:
throw new HttpResponseException(HttpStatusCode.InternalServerError)
Or another way is:
var response = new HttpResponseMessage(HttpStatusCode.NotFound)
{
Content = new StringContent("some error"),
ReasonPhrase = "Not Found"
};
throw new HttpResponseException(response);
I'm looking at creating a REST WebAPI and want to return "error" messages along with my status codes - as desciption to the end client as to what went wrong.
One of the responses will be a 422 status code - but I can't see how to get the data element into my reponse?
public HttpResponseMessage GetValidate(string number)
{
var response = Request.CreateResponse((HttpStatusCode)422);
response.Content new { error = "something wrong here", item = "number" }; // This is wrong!
return response;
}
There is no definition in the HttpStatusCode for 422 code. Take a look at documentation.
You could use the 500 http status code which is Interval Error:
return Request.CreateResponse(HttpStatusCode.InternalServerError, new {error = "something wrong here", item = "number"});
or 400 Bad Request:
return Request.CreateResponse(HttpStatusCode.BadRequest, new { error = "something wrong here", item = "number" });
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "message"); or other overloads.
There is a draft proposal to the IETF for a standard way of returning error information from an API. The details are here https://datatracker.ietf.org/doc/html/draft-nottingham-http-problem-04
I have a library that supports creating this format on Nuget and a GitHub project.
It works like this..
var problem = new ProblemDocument
{
ProblemType = new Uri("http://example.org"),
Title = "Houston we have a problem",
StatusCode = HttpStatusCode.BadGateway,
ProblemInstance = new Uri("http://foo")
};
problem.Extensions.Add("bar", new JValue("100"));
var response = new HttpResponseMessage(HttpStatusCode.BadGateway)
{
Content = new ProblemContent(problem)
};