I have the snippet in C# and was looking for some advice converting it to PHP.
Basically, what is happening here, I am building somewhat of a middleware site.
A user submits a form named "Basket" and creates a POST request with XML body to this file, which will parse it, create a new URL with parameters which will afterwards be sent to Shopify cart.
Any help is appreciated.
public class DefaultController : ApiController
{
public IHttpActionResult Post()
{
var query = "";
var domain = "https://shop.shopify.io/cart";
try
{
var content = Request.Content.ReadAsFormDataAsync().Result;
var document = XDocument.Parse(content["basket"]);
if (document.Root != null)
{
var products = document.Root.Elements().Select(x => x.Element("productid").Value + ":" + x.Element("amount").Value);
query = string.Join(",", products);
}
}
catch
{ }
if (string.IsNullOrEmpty(query))
return Redirect(domain);
return Redirect($"{domain}?query={query}");
}
}
```
Related
I have a requirement where I have been posting data to a web API as a json string in a POST request and the post method retrieves the data from the body. This works perfectly for most data, but it does not work when I include a long dash(—) as part of the data in any fields.
I have a Email class with some string fields and I am passing it to the API to save in the database.
Here is how I am implementing the call:
public string PostNewEmailRecord(string APIEndpoint, CampaignWave Email)
{
string StrEmailId = string.Empty;
_endpoint = APIEndpoint;
try
{
string strData = JsonConvert.SerializeObject(Email);
_client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
_client.UploadString(APIEndpoint, _requestType, strData);
}
catch (Exception ex)
{
}
return StrEmailId;
}
And here is the post method of Web API:
public void Post([FromBody]CampaignWave email)
{
try
{
using (var transaction = new TransactionScope())
{
CampaignWaveRepository cr = new CampaignWaveRepository();
object objReturnValue = cr.Insert(email);
transaction.Complete();
}
}
catch (Exception ex)
{
}
finally
{
}
}
When I include a dash the API post method receives a null value as email.
Please help me how I can successfully pass the '—' without any issue. Thanks in advance.
Based on comments it could be caused by encoding:
client.Encoding = Encoding.UTF8
I was trying to call the Put method through Postman and always getting error: "405 Method Not Allow" and "Message": "The requested resource does not support http method 'PUT'."
I'm using DocumentDB and C#. Here is my code:
[Route("multilanguage/Resources/{id}/{Language}")]
[HttpPut]
public async Task<IHttpActionResult> UpdateResource(string Id, string Language, string text)
{
client = new DocumentClient(new Uri(EndPoint), AuthKey);
var collectionLink = UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId);
var query = new SqlQuerySpec("SELECT * FROM MultiLanguage as m where m.id = #pmId",
new SqlParameterCollection(new SqlParameter[] { new SqlParameter { Name = "#pmId", Value = Id } }));
Document doc = client.CreateDocumentQuery<Document>(
collectionLink, query).AsEnumerable().FirstOrDefault();
List<Models.Translations> d = doc.GetPropertyValue<List<Models.Translations>>("Translations");
Models.Translations temp = d.Find(p => p.Language == Language);
temp.Content = text;
temp.LastModified = DateTimeOffset.Now;
temp.ModifiedBy = "admin";
doc.SetPropertyValue("Translations", d);
Document updated = await client.ReplaceDocumentAsync(doc);
return Ok();
}
When I call the Put method throught Postman, I call "http://localhost:XXXX/multilanguage/resources/2/En". "2" and "En" are the first two parameters in my code. And I also specify the "text" parameter value in the Postman request Body with x-www-form-urlencoded type: key = text, value = Test! This put method suppose to update the temp.Content value to "Test!". However, it always failed with the error I mentioned above.
Did I miss anything here?
The 405 error when performing a PUT request to web api is a well known topic. You can find many solutions in this or this SO question.
And for the design of you controller:
PUT are designed to have a body, just like POST and in your case
you should send all parameters in the body instead.
You should create a class which contains the objects you want to send to the server:
public class resourceClass
{
public string Id { get; set; }
public string Language { get; set; }
public string text { get; set; }
}
Then specify the route without the attribute routing and get the object from the request body
[Route("multilanguage/Resources/PutResource")]
[HttpPut]
public async Task<IHttpActionResult> UpdateResource([FromBody] resourceClass obj)
{
client = new DocumentClient(new Uri(EndPoint), AuthKey);
var collectionLink = UriFactory.CreateDocumentCollectionUri(DatabaseId, CollectionId);
var query = new SqlQuerySpec("SELECT * FROM MultiLanguage as m where m.id = #pmId",
new SqlParameterCollection(new SqlParameter[] { new SqlParameter { Name = "#pmId", Value = Id } }));
Document doc = client.CreateDocumentQuery<Document>(
collectionLink, query).AsEnumerable().FirstOrDefault();
List<Models.Translations> d = doc.GetPropertyValue<List<Models.Translations>>("Translations");
Models.Translations temp = d.Find(p => p.Language == Language);
temp.Content = text;
temp.LastModified = DateTimeOffset.Now;
temp.ModifiedBy = "admin";
doc.SetPropertyValue("Translations", d);
Document updated = await client.ReplaceDocumentAsync(doc);
return Ok();
}
From the client you could add an object to the PUT request of Content-Type application/json like this
var data = {
Id: clientId,
Language: clientLanguage,
text: clientText
};
Don't forget to stringify the json when adding it to the http request
data: JSON.stringify(data),
The PUT controller will then be reached at "http://localhost:XXXX/multilanguage/resources/putresource".
Check the URL for which you are posting the data, in my case the URL was incorrect because of which I got these errors, also verify that in Body you should select raw and change the Text to JSON if you are passing a JSON as a data.
I am implementing webhook test code and I am running into a problem.
After I POST a sample notification to my webhook listener the Params are not in the request:
Request.Params["bt_signature"]
Request.Params["bt_payload"]
So the listener fails.
Below is both my Post Webhook code and Listener code; I'm not sure if I'm using gateway.WebhookTesting.SampleNotification correctly.
POST Test Webhook
private async Task PostTestNotification()
{
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:50709/");
var gateway = config.GetGateway();
// Create sample notification
Dictionary<String, String> sampleNotification = gateway.WebhookTesting.SampleNotification(
WebhookKind.SUBSCRIPTION_CHARGED_SUCCESSFULLY, "sub_id_1234"
);
// Convert sample notification to JSON
string payloadJson = JsonConvert.SerializeObject(sampleNotification);
// Create StringContent of json sample notificaiton
var data = new StringContent(payloadJson);
// data looks like this when debugging { "bt_payload":"PG5vdGlmaWNhdGlvbj48dGltZXN0YW1wIHR5cGU9ImRhdGV0aW1lIj4yMDE2LTA1LTI3IDEzOjM2OjEwWjwvdGltZXN0YW1wPjxraW5kPnN1YnNjcmlwdGlvbl9jaGFyZ2VkX3N1Y2Nlc3NmdWxseTwva2luZD48c3ViamVjdD48c3Vic2NyaXB0aW9uPjxpZD5zdWJfaWRfMTIzNDwvaWQ+PHRyYW5zYWN0aW9ucz48dHJhbnNhY3Rpb24+PGlkPnN1Yl9pZF8xMjM0PC9pZD48YW1vdW50PjQ5Ljk5PC9hbW91bnQ+PHN0YXR1cz5zdWJtaXR0ZWRfZm9yX3NldHRsZW1lbnQ8L3N0YXR1cz48ZGlzYnVyc2VtZW50LWRldGFpbHM+PGRpc2J1cnNlbWVudC1kYXRlIHR5cGU9ImRhdGUiPjIwMTMtMDctMDk8L2Rpc2J1cnNlbWVudC1kYXRlPjwvZGlzYnVyc2VtZW50LWRldGFpbHM+PGJpbGxpbmc+PC9iaWxsaW5nPjxjcmVkaXQtY2FyZD48L2NyZWRpdC1jYXJkPjxjdXN0b21lcj48L2N1c3RvbWVyPjxkZXNjcmlwdG9yPjwvZGVzY3JpcHRvcj48c2hpcHBpbmc+PC9zaGlwcGluZz48c3Vic2NyaXB0aW9uPjwvc3Vic2NyaXB0aW9uPjwvdHJhbnNhY3Rpb24+PC90cmFuc2FjdGlvbnM+PGFkZF9vbnMgdHlwZT0iYXJyYXkiPjwvYWRkX29ucz48ZGlzY291bnRzIHR5cGU9ImFycmF5Ij48L2Rpc2NvdW50cz48L3N1YnNjcmlwdGlvbj48L3N1YmplY3Q+PC9ub3RpZmljYXRpb24+\n","bt_signature":"69r68j6hnzjpnq4j|508a7b4b3bbbe15c241c742331acfc5bacf37c54"}
// POST
HttpResponseMessage response = await client.PostAsync("webhooks/accept", data);
// RESPONSE
if (response.IsSuccessStatusCode == true)
{
// SUCCESS CONTENT
string resultJSON = await response.Content.ReadAsStringAsync();
}
else
{
// FAIL CONTENT
dynamic problem = await response.Content.ReadAsStringAsync();
}
}
}
catch (Exception ex)
{
//
Console.WriteLine("Exception: " + ex.Message);
}
}
Webhook LISTENER
// webhooks/accept endpoint
public async Task<ActionResult> accept()
{
try
{
var gateway = config.GetGateway();
if (Request.HttpMethod == "POST")
{
var bt_signature = Request.Params["bt_signature"]; <<<<<<< ALWAYS EMPTY >>>>>>>>>
var bt_payload = Request.Params["bt_payload"]; <<<<<<< ALWAYS EMPTY >>>>>>>>>
WebhookNotification webhookNotification = gateway.WebhookNotification.Parse(
Request.Params["bt_signature"],
Request.Params["bt_payload"]
); <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< EXCEPTION WHEN HIT - Value cannot be null, Parameter name: Input >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// ACTION Webhook
if (webhookNotification.Kind == WebhookKind.SUBSCRIPTION_CANCELED)
{
IsActive = false;
await Logger.LogInsight("", "WEBHOOK: SUBSCRIPTION_CANCELED " + webhookNotification.Subscription.Id );
}
else if (webhookNotification.Kind == WebhookKind.SUBSCRIPTION_CHARGED_SUCCESSFULLY)
{
IsActive = true;
await Logger.LogInsight("", "WEBHOOK: SUBSCRIPTION_CHARGED_SUCCESSFULLY " + webhookNotification.Subscription.Id);
}
// code ommitted for brevity, similar to above checking all 'kind' values
}
}
}
Why are the Braintree Request Params empty?
The problem was in the Webhook endpoint, the Braintree sample code is incorrect, it implies using MVC but developers need to use the Web Api for this, and the sample code will not work.
To get this working I left the Sample Notification POST above unchanged and created a new Webhook listener :
First create a class to receive the two braintree strings from the POST:
public class bt
{
public string bt_payload { get; set; }
public string bt_signature { get; set; }
}
And now create an empty Web Api 2 Controller:
[HttpPost]
[Route("api/webhooks/accept")]
public async Task<IHttpActionResult> accept(bt bt_lot)
{
var gateway = config.GetGateway();
WebhookNotification webhookNotification = gateway.WebhookNotification.Parse(
bt_lot.bt_signature,
bt_lot.bt_payload
);
if (webhookNotification.Kind == WebhookKind.SUBSCRIPTION_CANCELED)
{
// take your action here...
}
Im posting all my experiences with Braintree here on SO as there isn't a great deal of help here and I hope it helps others.
I have to say the Braintree Help staff are excellent and always answer questions with very detailed answers that 95% of the time resolved any issues I had, but this issue had me scratching my head as their example didn't work and the help staff assumed like me that the code should work.
ASP.NET
[HttpPost]
[Route("apitest")]
public string apitest([FromBody]string str)
{
Console.Writeline(str); // str is always null
return null;
}
Angular 2:
var creds = "str='testst'" ;
var headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
http.post('http://localhost:18937/apitest', creds, {
headers: headers
})
.map(res => res.json())
.subscribe(
(res2) => {
console.log('subsribe %o', res2)
}
);
I also tried creds = {"str":"test"}; without headers JSON.stringify() etc. without success. How do I Post data to ASP.NET?
var creds = {
str: 'testst'
};
$http.post('http://localhost:18937/apitest', JSON.stringify(creds));
No changes in Web API controller and it should work.
This is probably an issue with the way that ASP.NET and MVC handle data POSTS.
[HttpPost]
public ActionResult Index(int? id)
{
Stream req = Request.InputStream;
req.Seek(0, System.IO.SeekOrigin.Begin);
string json = new StreamReader(req).ReadToEnd();
InputClass input = null;
try
{
// assuming JSON.net/Newtonsoft library from http://json.codeplex.com/
input = JsonConvert.DeserializeObject<InputClass>(json)
}
catch (Exception ex)
{
// Try and handle malformed POST body
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
//do stuff
}
You can refer to my answer here and the referenced links as to a potential cause of the issue. There are quite a few server side web frameworks that inappropriately handle data POSTS and by default doesn't add the data to your request object.
You shouldn't [have to] try and change the behavior of your angular post, and modify headers to pretend your data post is a form post.
We have scenario where external API returns either User XML or Error XML based on whether request succeed or failed.
At the moment I'm passing User POCO to the restsharp and works fine. But if it fails, this object is NULL. And we won't know why it failed unless we parse the Error XML manually.
Is there a way to workaround this?
e.g.
var restClient = new RestClient(baseURL);
var request = new RestRequest(uri);
request.Method = Method.POST;
var response = restClient.Execute<User>(request);
On execution of above method the API can return Error xml object. How do I get Error object on fail and User on success?
This is possible, although the code is a little ugly. RestSharp allows you to specify your own XML deserializer, so we'll need to do that in order to make this work.
First, though, you need a data type that can store either an Error or a User (I made it generic so it works for more than just Users):
public class Result<T>
{
public T Data { get; set; }
public Error Error { get; set; }
}
So the idea is, now when you execute the request, you ask RestSharp for a Result<User> instead of just a User, i.e.:
var result = client.Execute<Result<User>>(request);
Now here's the magic required to deserialize as either an Error or a User. It's a custom deserializer that inherits from RestSharp's XmlDeserializer. Warning: this code is not tested at all, but it can hopefully point you in the right direction.
public class XmlResultDeserializer : XmlDeserializer
{
public override T Deserialize<T>(IRestResponse response)
{
if (!typeof(T).IsGenericType || typeof(T).GetGenericTypeDefinition() != typeof(Result<>))
return base.Deserialize<T>(response);
// Determine whether the response contains an error or normal data.
var doc = XDocument.Parse(response.Content);
var result = Activator.CreateInstance<T>();
if (doc.Root != null && doc.Root.Name == "Error")
{
// It's an error
var error = base.Deserialize<Error>(response);
var errorProperty = result.GetType().GetProperty("Error");
errorProperty.SetValue(result, error);
}
else
{
// It's just normal data
var innerType = typeof(T).GetGenericArguments()[0];
var deserializeMethod = typeof(XmlDeserializer)
.GetMethod("Deserialize", new[] { typeof(IRestResponse) })
.MakeGenericMethod(innerType);
var data = deserializeMethod.Invoke(this, new object[] { response });
var dataProperty = result.GetType().GetProperty("Data");
dataProperty.SetValue(result, data);
}
return result;
}
}
Then you would wire it all up like this:
var restClient = new RestClient(baseURL);
client.AddHandler("application/xml", new XmlResultDeserializer());
var request = new RestRequest(uri);
request.Method = Method.POST;
var result = restClient.Execute<Result<User>>(request);
if (response.Data.Data != null)
{
var user = response.Data.Data;
// Do something with the user...
}
else if (response.Data.Error != null)
{
var error = response.Data.Error;
// Handle error...
}