Returning data/body along with an HttpReponseCode? - c#

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)
};

Related

Flurl Posting with C#

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??

424 Error When Trying To Interact With Lex

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()}");
}

How to filter QnAMaker Question based on Source

I am using QnAMaker REST API in my Bot Framework to query a knowledge base.
It works fine but I would like to filter the 'questions' based on the 'source' as specified on the requestData. Referring to the documentation- https://learn.microsoft.com/en-us/azure/cognitive-services/qnamaker/how-to/metadata-generateanswer-usage I did not see any option to do that. The documentation states that 'source' is only part of the response answer and not the request.
I tried passing 'source' as metadata to strictFilters.
Dictionary<string, object> requestData = new Dictionary<string, object>
{
["question"] = question,
["top"] = top,
["strictFilters"] = new Dictionary<string, object>
{
["source"] = "test.tsv"
}
};
string requestBody = JsonConvert.SerializeObject(requestData);
kbId = _configuration[qnaKbName];
method = "/knowledgebases/" + kbId + "/generateAnswer/";
var uri = host + method;
var response = await Post(uri, requestBody);
return response;
Request JSON format-
{"question":"flexible working","top":5,"strictFilters":{"source":"test.tsv"}}
It does not work and I get below response-
{
"error": {
"code": "BadArgument",
"message": "Parameter is null"
}
}
Tried creating the Request JSON like this-
{"question":"sabbatical","top":5,"strictFilters":[{"name":"source","value":"test.tsv"}]}
Got below response-
{
"error": {
"code": "Unspecified",
"message": "Something happened. Please retry after some time."
}
}
Is there any option to do that? Please let me know if I can provide more details..
the error BadArgument, Parameter is null comes when input json being passed does not match with QnA API request body. For example if API is expecting {"question":"this is my question"} and we pass {"questionAB":"this is my question"}, this will throw error.

How to send sms using Textlocal API?

I am trying to implement the send message functionality using third party api. API-https://api.txtlocal.com/send/
But when we are testing the implementation, we are facing an issue with error code 3 and giving a message as "invalid user details."
C# code:
string UserId = "1234";
String message = HttpUtility.UrlEncode("OTP");
using (var wb = new WebClient())
{
byte[] response = wb.UploadValues("https://api.txtlocal.com/send/", new NameValueCollection()
{
{"username" , "<TextLocal UserName>"},
{"hash" , "<API has key>"},
{"sender" , "<Unique sender ID>"},
{"numbers" , "<receiver number>"},
{"message" , "Text message"}
});
string result = System.Text.Encoding.UTF8.GetString(response);
//return result;
Error Details:
{
"errors": [{
"code": 3,
"message": "Invalid login details"
}],
"status": "failure"
}
Even though I am passing valid credentials.
Please assist me and let me know in case you require any more details.
Thanks and appreciate your help in advance.
The documentation for the API states that you should pass your parameter values either in the header for POST requests or in the url for GET requests. WebClient.UploadValue does a POST per default, but you don't set the header accordingly. So no credentials are found.
You could try to use the WebClient.UploadValues(name, method, values) overload and specify GET as method.
NameValueCollection values = ...;
byte[] response = wb.UploadValues("https://api.txtlocal.com/send/", "GET", values);
I believe you should either send the API Key OR the username and password.
Remove the username from your request and just leave the API key, sender, numbers and message. All should work OK then.
This is what worked for me:
[HttpGet]
public async Task<JObject> SendOtp(string number)
{
using (var client = _httpClientFactory.CreateClient())
{
client.BaseAddress = new Uri("https://api.textlocal.in/");
client.DefaultRequestHeaders.Add("accept","application/json");
var query = HttpUtility.ParseQueryString(string.Empty);
query["apikey"] = ".....";
query["numbers"] = ".....";
query["message"] = ".....";
var response = await client.GetAsync("send?"+query);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return JObject.Parse(content);
}
}
its bit late ...... Try replacing {"hash" , ""} with {"apikey" , ""}

Web API2 ,How to return an error

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);

Categories

Resources