I am getting HTTP 400 when I POST some JSON using RestSharp PCL.
When I send a string, it seems that the \" is included. Which it should not. This might be the reason why the POST does not work.
I am probably missing something that I need to fill in but please do help me to understand what I am missing.
Here is the code I am using
public async Task<bool> DoPost<T>(string endPoint, T content) where T : class
{
var body = JsonConvert.SerializeObject(content);
var request = new RestRequest(endPoint, Method.POST);
request.AddParameter("application/json", body, ParameterType.RequestBody);
try
{
var response = await _client.Execute(request, _cancellationToken.Token);
if (response.IsSuccess)
{
return true;
}
}
catch (Exception e)
{
throw new GTSWebServiceException(e.Message, e);
}
return false;
}
Have you checked this: How to POST request using RestSharp I know you are including the content type in the first argument but maybe you can play with RequestFormat? I doubt that's needed though. Also, have you checked whether your string does actually contain an escaped character like a double quote on it? If you are also seeing that slash on strings could it also be because you are debugging it? What do you receive in the payload coming through in the server that returns you the bad request?
Related
I'm trying to do repeat payments with Form Integration in Sagepay (now Opayo).
From an earlier problem posted on here, I get that the securitykey is needed but is not returned in the Form call, so an additional call needs to be made to the getTransactionDetails command.
I have the securitykey and can now make a call to https://test.sagepay.com/gateway/service/repeat.vsp to initiate the repeat payment. However, the documentation does not say where the response to that call goes. I assume therefore, that it would go to the NotificationURL that is set up with a payment when using the Server or Direct integrations. Since I'm using Form, this is not set.
The question is, is there any way of capturing the response to the https://test.sagepay.com/gateway/service/repeat.vsp call if the initial payment was created using Form integration?
I suppose the second question is, has anybody successfully made repeat payments work with Sagepay Form integration?
Not sure if this helps you and we didn't do repeat payments; but we are looking at releasing deferred payments and I think it is a similar approach.
How do you make the call to 'https://test.sagepay.com/gateway/service/repeat.vsp'?
Could you use a 'HttpWebRequest' to make the call then capture the direct response in 'HttpWebResponse'?
EG:
private static void DeferredSharedApiCall(Dictionary<string, string> data, string type, string url)
{
string postData = string.Join("&", data.Select(x => $"{x.Key}={HttpUtility.UrlEncode(x.Value)}"));
HttpWebRequest request = WebRequest.CreateHttp(url);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
using (TextWriter tw = new StreamWriter(request.GetRequestStream()))
{
tw.Write(postData);
}
HttpWebResponse response = null;
try
{
response = request.GetResponse() as HttpWebResponse;
}
catch (WebException ex)
{
//log.Error($"{type} Error, data: {postData}", ex);
}
catch (Exception ex)
{
//log.Error($"{type} Error, data: {postData}", ex);
}
if (response != null)
{
using (TextReader tr = new StreamReader(response.GetResponseStream()))
{
string result = tr.ReadToEnd();
//log.Info($"{type} Response: {Environment.NewLine}{result}");
}
}
}
I'm currently working on a bot for my Discord server and I was wondering how to implement various image commands (for example, !cat, !meme) to make the bot send a random image each time the command is called.
Almost every bot I've seen has a feature like that but for some reason I can't seem to find a working way to do this in JDA. And any JDA example I found was either outdated or it simply didn't work, so I really hope someone can give me a hand here.
Here's a (very basic) example I already did, but the problem is that the pictures don't randomize with each call and just stay the same until I restart discord
public void sendCatImage() {
EmbedBuilder result= new EmbedBuilder();
result.setTitle("Here's a cat!");
result.setImage("http://thecatapi.com/api/images/get?format=src&type=png");
event.getChannel().sendMessage(result.build()).queue();
}
I'm using JDA Version 4.1.0_100, if it helps
Any help will be greatly appreciated!
Discord will cache the image based on the URL. You can append a random number as a query to prevent this:
public String randomize(String url) {
ThreadLocalRandom random = ThreadLocalRandom.current();
return url + "&" + random.nextInt() + "=" + random.nextInt();
}
...
result.setImage(randomize(url));
...
Furthermore, you can avoid discord updating the image by also uploading it alongside the embed. For that you first need to download the image and then upload it:
// Use same HTTP client that jda uses
OkHttpClient http = jda.getHttpClient();
// Make an HTTP request to download the image
Request request = new Request.Builder().url(imageUrl).build();
Response response = http.newCall(request).execute();
try {
InputStream body = response.body().byteStream();
result.setImage("attachment://image.png"); // Use same file name from attachment
channel.sendMessage(result.build())
.addFile(body, "image.png") // Specify file name as "image.png" for embed (this must be the same, its a reference which attachment belongs to which image in the embed)
.queue(m -> response.close(), error -> { // Send message and close response when done
response.close();
RestAction.getDefaultFailure().accept(error);
});
} catch (Throwable ex) {
// Something happened, close response just in case
response.close();
// Rethrow the throwable
if (ex instanceof Error) throw (Error) ex;
else throw (RuntimeException) ex;
}
It seems a tad cumbersome to add URL Params and also doesn't seem possible to add a body to any kind of request.
Sometimes, I need to add a body (like one would in a POST request) to DELETE, GET, PUT requests. As much as I really enjoy Volley, I feel like it isn't as loose as many would like. To adhere to it, the company has had to change some of the way our back-end is written.
Is there a nice and easy way to add a body to any type of method. Understandable, but upsetting if not.
Further, is there an easy way to add URL Params out of a HashMap or JSONObject?
Lately, I've found myself doing this:
StringBuilder buildUrl = new StringBuilder(BASE_URL);
buildUrl.append("items")
.append("/")
.append(item.getId())
.append("/")
.append("edit.json")
.append("?")
.append("user_id=")
.append(params.optString("user_id"))
.append("&")
.append("auth_token")
.append(params.optString("auth_token"));
and then using that String as the URL. Is there an easier way built into Volley? If not, I'll just cook up my own function for it.
You can certainly add a body to your JSONObject requests.
According to the docs:
JsonObjectRequest—A request for retrieving a JSONObject response body at a given URL, allowing for an optional JSONObject to be passed in as part of the request body.
I've only tried it with POST so can't comment on other HTTP methods - let me know what you find out. I do it like this:
JSONObject listItemData = new JSONObject();
try {
// Do what you're gonna do
} catch (JSONException e) {
e.printStackTrace();
}
Then pass it into your request like so:
JsonObjectRequest createItemRequest = new JsonObjectRequest(Request.Method.POST, CreateItemUrl, listItemData,
new Response.Listener....
//.....
)
I have this example of ASP.NET Web Api controller:
public Mea Get(Int32 id)
{
try
{
return Meas.GetById(id) ?? new Mea(-1, 0D, 0D);
}
catch (Exception)
{
return new Mea(-1, 0D, 0D);
}
}
I want to be able to return a different response code if the GetById returns null or in the catch exception.
All the examples that I see use HttpResponseMessage where you can add the response code.
My question is how to change the response code when not using HttpResponseMessage, like in the above example?
Well if you want to have different response code to be return from your function then you will have to wrap it in in a HttpResponseMessage.
Your function will always return an status code "200". Even if you return a bare object the framework pipeline will convert it to a HttpResponseMessage with default status code HttpStatusCode.OK, so better you do it by yourself.
What I would suggest is do not return bare objects/values from your API function. Always wrap the values in a HttpResponseMessage and then return a response message from your function.Basically by wrapping it in the HttpResponseMessage you can have proper status code in client side. Returning HttpResponseMessage is always the best practice.
So please change your function like this
public HttpResponseMessage Get(Int32 id)
{
try
{
// on successful execution
return this.Request.CreateResponse(HttpStatusCode.OK, Meas.GetById(id) ?? new Mea(-1, 0D, 0D));
}
catch (Exception)
{
return this.Request.CreateResponse(HttpStatusCode.InternalServerError, Mea(-1, 0D, 0D));
}
}
in the case of an error you can also throw an HttpResponseException
You can throw a System.Web.Http.HttpResponseException, specifying an HTTP status code and/or optionally a whole HttpResponseMessage to be returned to the client.
I created some web apis and when an error happens the api returns HttpResponseMessage that is created with CreateErrorResponse message. Something like this:
return Request.CreateErrorResponse(
HttpStatusCode.NotFound, "Failed to find customer.");
My problem is that I cannot figure out how to retrieve the message (in this case "Failed to find customer.") in consumer application.
Here's a sample of the consumer:
private static void GetCustomer()
{
var client = new HttpClient();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
string data =
"{\"LastName\": \"Test\", \"FirstName\": \"Test\"";
var content = new StringContent(data, Encoding.UTF8, "application/json");
var httpResponseMessage =
client.PostAsync(
new Uri("http://localhost:55202/api/Customer/Find"),
content).Result;
if (httpResponseMessage.IsSuccessStatusCode)
{
var cust = httpResponseMessage.Content.
ReadAsAsync<IEnumerable<CustomerMobil>>().Result;
}
}
Any help is greatly appreciated.
Make sure you set the accept and or content type appropriately (possible source of 500 errors on parsing the request content):
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
content.Headers.ContentType = new MediaTypeWithQualityHeaderValue("application/json");
Then you could just do:
var errorMessage = response.Content.ReadAsStringAsync().Result;
That's all on the client of course. WebApi should handle the formatting of the content appropriately based on the accept and/or content type. Curious, you might also be able to throw new HttpResponseException("Failed to find customer.", HttpStatusCode.NotFound);
One way to get the message is to do:
((ObjectContent)httpResponseMessage.Content).Value
This will give you a dictionary that contains also the Message.
UPDATE
Refer to the official page:
http://msdn.microsoft.com/en-us/library/jj127065(v=vs.108).aspx
You have to vary the way you're reading the successful response and the error response as one is obviously in your case StreamContent, and the other should be ObjectContent.
UPDATE 2
Have you tried doing it this way ?
if (httpResponseMessage.IsSuccessStatusCode)
{
var cust = httpResponseMessage.Content.
ReadAsAsync<IEnumerable<CustomerMobil>>().Result;
}
else
{
var content = httpResponseMessage.Content as ObjectContent;
if (content != null)
{
// do something with the content
var error = content.Value;
}
else
{
Console.WriteLine("content was of type ", (httpResponseMessage.Content).GetType());
}
}
FINAL UPDATE (hopefully...)
OK, now I understand it - just try doing this instead:
httpResponseMessage.Content.ReadAsAsync<HttpError>().Result;
This is an option to get the message from the error response that avoids making an ...Async().Result() type of call.
((HttpError)((ObjectContent<HttpError>)response.Content).Value).Message
You should make sure that response.Content is of type ObjectContent<HttpError> first though.
It should be in HttpResponseMessage.ReasonPhrase. If that sounds like a bit of a strange name, it's just because that is the way it is named in the HTTP specification http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
OK this is hilarious, but using QuickWatch I came up with this elegant solution:
(new System.Collections.Generic.Mscorlib_DictionaryDebugView(((System.Web.Http.HttpError)(((System.Net.Http.ObjectContent)(httpResponseMessage.Content)).Value)))).Items[0].Value
That is super readable!