I have the following code in android to send to my cakephp server
val params = JSONObject()
val siteId = sharedPref.getInt("site_id", 0)
try {
params.put("photo", encodeImage)
params.put("lat", latitude)
params.put("lng", longitude)
params.put("status", status)
params.put("site_id", siteId)
} catch (e: JSONException) {
Log.e("JsonException", e.toString())
}
val queue = Volley.newRequestQueue(this#CameraActivity)
val request = object : JsonObjectRequest(Request.Method.POST, ROOT_URL + TRANSACTION,
params, Response.Listener<JSONObject> { response ->
// startActivity(myIntent)
}, Response.ErrorListener {
Toast.makeText(this#CameraActivity, "That didn't work!", Toast.LENGTH_SHORT).show()
}) {
#Throws(AuthFailureError::class)
override fun getHeaders(): MutableMap<String, String> {
val headers = HashMap<String, String>()
headers.put("Accept", "application/json")
headers.put("Content-Type", "application/json; charset=utf-8")
headers.put("Authorization", "Bearer "+ token) // Figure out a way to get JWT
return headers
}
}
And I have this code on cakephp controller to receive it
$transaction = $this->Transactions->newEntity();
if($this->request->is('post')){
$transaction->lat = $this->request->getData('lat');
$transaction->lng = $this->request->getData('lng');
$photo = $this->request->getData('photo');
$transaction->status = $this->request->getData('status');
$decoded = base64_decode($photo);
$transaction->employee_id = $this->Auth->user('id');
$transaction->project_id = $this->Auth->user('project_id');
$transaction->site_id = $this->request->getData('site_id');
if ($this->Transactions->save($transaction)) {
$this->Auth->logout();
$this->set([
'success' => true,
'_serialize' => ['success']
]);
}
}
The problem is on the server side I do not want to equate every request to a cakephp entity variable. Is there a way I can just do an object mapping so i do not need to do the unnecessary equating at the cakephp controller?
Related
I am facing a new issue with a fetch
handleSendToForge(e) {
e.preventDefault();
let formData = new FormData();
formData.append('data', JSON.stringify({
Width: this.state.Width,
Length: this.state.Length,
Depth: this.state.Depth,
Thickness: this.state.Thickness,
BottomThickness: this.state.BottomThickness,
rebarSpacing: this.state.rebarSpacing,
outputrvt: this.state.outputrvt,
bucketId: this.state.bucketId,
activityId: 'RVTDrainageWebappActivity',
objectId: 'template.rvt'
}));
this.setState({
form: formData
})
fetch('designautomation', {
method: 'POST',
body: formData,
//headers: {
// //'Content-Type': 'application/json'
// 'Content-Type': 'application/x-www-form-urlencoded',
//},
})
.then(response => response.json())
.then(data => { console.log(data) })
.catch(error => console.log(error));
}
and the code for the controller is pretty standard and is slightly modified from one of the forge examples
[HttpPost]
[Route("designautomation")]
public async Task<IActionResult> Test([FromForm] StartWorkitemInput input)
{
JObject workItemData = JObject.Parse(input.data);
double Width = workItemData["Width"].Value<double>();
double Length = workItemData["Length"].Value<double>();
double Depth = workItemData["Depth"].Value<double>();
double Thickness = workItemData["Thickness"].Value<double>();
double BottomThickness = workItemData["BottomThickness"].Value<double>();
double rebarSpacing = workItemData["rebarSpacing"].Value<double>();
string outputrvt = workItemData["outputrvt"].Value<string>();
string activityId = workItemData["activityId"].Value<string>();
string bucketId = workItemData["bucketId"].Value<string>();
string objectId = workItemData["objectId"].Value<string>();
// basic input validation
string activityName = string.Format("{0}.{1}", NickName, activityId);
string bucketKey = bucketId;
string inputFileNameOSS = objectId;
// OAuth token
dynamic oauth = await OAuthController.GetInternalAsync();
// prepare workitem arguments
// 1. input file
dynamic inputJson = new JObject();
inputJson.Width = Width;
inputJson.Length = Length;
inputJson.Depth = Depth;
inputJson.Thickness = Thickness;
inputJson.BottomThickness = BottomThickness;
inputJson.rebarSpacing = rebarSpacing;
inputJson.outputrvt = outputrvt;
XrefTreeArgument inputFileArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/aecom-bucket-demo-library/objects/{0}", objectId),
Headers = new Dictionary<string, string>()
{
{ "Authorization", "Bearer " + oauth.access_token }
}
};
// 2. input json
XrefTreeArgument inputJsonArgument = new XrefTreeArgument()
{
Headers = new Dictionary<string, string>()
{
{"Authorization", "Bearer " + oauth.access_token }
},
Url = "data:application/json, " + ((JObject)inputJson).ToString(Formatting.None).Replace("\"", "'")
};
// 3. output file
string outputFileNameOSS = outputrvt;
XrefTreeArgument outputFileArgument = new XrefTreeArgument()
{
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, outputFileNameOSS),
Verb = Verb.Put,
Headers = new Dictionary<string, string>()
{
{"Authorization", "Bearer " + oauth.access_token }
}
};
// prepare & submit workitem
// the callback contains the connectionId (used to identify the client) and the outputFileName of this workitem
//string callbackUrl = string.Format("{0}/api/forge/callback/designautomation?id={1}&bucketKey={2}&outputFileName={3}", OAuthController.FORGE_WEBHOOK_URL, browerConnectionId, bucketKey, outputFileNameOSS);
WorkItem workItemSpec = new WorkItem()
{
ActivityId = activityName,
Arguments = new Dictionary<string, IArgument>()
{
{ "rvtFile", inputFileArgument },
{ "jsonFile", inputJsonArgument },
{ "result", outputFileArgument }
///{ "onComplete", new XrefTreeArgument { Verb = Verb.Post, Url = callbackUrl } }
}
};
DesignAutomationClient client = new DesignAutomationClient();
client.Service.Client.BaseAddress = new Uri(#"http://localhost:3000");
WorkItemStatus workItemStatus = await client.CreateWorkItemAsync(workItemSpec);
return Ok();
}
Any idea why is giving me this error? I have tested the api using postman and it works fine but when I try to call that from a button I keep receive this error. Starting the debug it seems that the url is written correctly. Maybe it is a very simple thing that i am missing.
Cheers!
OK solved...
I was missing to add the service in the Startup and also the Forge connection information (clientid, clientsecret) in the appsettings.json
Now I need to test the AWS deployment and I guess I am done!
I have a problem consuming data from an ASP.NET Core 2.0 Web API with Angular 5+.
Here the steps i have done:
I have built an ASP.NET Core 2.0 WebAPI and deployed it on a server. I can consume data from postman or swagger without any problems.
Then i have created with NSwagStudio the client TypeScript service classes for my angular frontend app.
Now the problem:
I can make a request to the wep api from the frontend app and i am also recieveing the correct data in JSON-Format.
But while the mapping process to the poco object in the generated client service class, something doesnt work. I always get an object with empty attributes.
Here my code:
product.service.ts
export class ProductService {
private http: { fetch(url: RequestInfo, init?: RequestInit): Promise<Response> };
private baseUrl: string;
protected jsonParseReviver: (key: string, value: any) => any = undefined;
constructor() {
this.http = <any>window;
this.baseUrl = "http://testweb01/FurnitureContractWebAPI";
}
getByProductId(productId: string): Promise<Product[]> {
let url_ = this.baseUrl + "/api/Product/GetById?";
if (productId === undefined)
throw new Error("The parameter 'productId' must be defined.");
else
url_ += "productId=" + encodeURIComponent("" + productId) + "&";
url_ = url_.replace(/[?&]$/, "");
let options_ = <RequestInit>{
method: "GET",
headers: {
"Content-Type": "application/json",
"Accept": "application/json"
}
};
return this.http.fetch(url_, options_).then((_response: Response) => {
return this.processGetByProductId(_response);
});
}
protected processGetByProductId(response: Response): Promise<Product[]> {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
return response.text().then((_responseText) => {
let result200: any = null;
let resultData200 = _responseText === "" ? null : JSON.parse(_responseText, this.jsonParseReviver);
if (resultData200 && resultData200.constructor === Array) {
result200 = [];
for (let item of resultData200) {
var x = Product.fromJS(item);
//console.log(x);
result200.push(Product.fromJS(item));
}
}
//console.log(result200);
return result200;
});
} else if (status !== 200 && status !== 204) {
return response.text().then((_responseText) => {
return throwException("An unexpected server error occurred.", status, _responseText, _headers);
});
}
return Promise.resolve<Product[]>(<any>null);
}
And here the methods from the Product-class:
init(data?: any) {
console.log(data);
if (data) {
this.productId = data["ProductId"];
this.productNameDe = data["ProductNameDe"];
this.productNameFr = data["ProductNameFr"];
this.productNameIt = data["ProductNameIt"];
this.supplierProductId = data["SupplierProductId"];
this.supplierProductVarId = data["SupplierProductVarId"];
this.supplierProductVarName = data["SupplierProductVarName"];
this.supplierId = data["SupplierId"];
this.supplierName = data["SupplierName"];
this.additionalText = data["AdditionalText"];
this.installationCost = data["InstallationCost"];
this.deliveryCost = data["DeliveryCost"];
this.sectionId = data["SectionId"];
this.categorieId = data["CategorieId"];
this.price = data["Price"];
this.ean = data["Ean"];
this.brand = data["Brand"];
this.modifiedDate = data["ModifiedDate"] ? new Date(data["ModifiedDate"].toString()) : <any>undefined;
this.categorie = data["Categorie"] ? ProductCategory.fromJS(data["Categorie"]) : <any>undefined;
this.section = data["Section"] ? ProductSection.fromJS(data["Section"]) : <any>undefined;
}
}
static fromJS(data: any): Product {
data = typeof data === 'object' ? data : {};
let result = new Product();
result.init(data);
return result;
}
In the init() method when i look at data, it contains all the values i need. But when i for example use data["ProductId"] the value is null/undefined.
Can anyone please help?
Thanks
Here is a screenshot of my console output of the data object:
enter image description here
Now I could figure out, that i can cast the data object directly to Product:
init(data?: any) {
var p = <Product>data;
This works, but i am asking myself, why does the generated class have an init-method with manually setting of the attributes, when it is possible to cast the object directly?
NSwag is misconfigured, use DefaultPropertyNameHandling: CamelCase for ASP.NET Core
Or use the new asp.net core api explorer based swagger generator which automatically detects the contract resolver. (Experimental)
I've been trying without success today to adapt this example to POST data instead of the example GET that is provided.
http://blogs.msdn.com/b/andy_wigley/archive/2013/02/07/async-and-await-for-http-networking-on-windows-phone.aspx
I've replaced the line:
request.Method = HttpMethod.Get;
With
request.Method = HttpMethod.Post;
But can find no Method that will allow me to stream in the content I wish to POST.
This HttpWebRequest seems a lot cleaner than other ways e.g. sending delegate functions to handle the response.
In Mr Wigley's example code I can see POST so it must be possible
public static class HttpMethod
{
public static string Head { get { return "HEAD"; } }
public static string Post { get { return "POST"; } }
I wrote this class some time ago
public class JsonSend<I, O>
{
bool _parseOutput;
bool _throwExceptionOnFailure;
public JsonSend()
: this(true,true)
{
}
public JsonSend(bool parseOutput, bool throwExceptionOnFailure)
{
_parseOutput = parseOutput;
_throwExceptionOnFailure = throwExceptionOnFailure;
}
public async Task<O> DoPostRequest(string url, I input)
{
var client = new HttpClient();
CultureInfo ci = new CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0]);
client.DefaultRequestHeaders.Add("Accept-Language", ci.TwoLetterISOLanguageName);
var uri = new Uri(string.Format(
url,
"action",
"post",
DateTime.Now.Ticks
));
string serialized = JsonConvert.SerializeObject(input);
StringContent stringContent = new StringContent(
serialized,
Encoding.UTF8,
"application/json");
var response = client.PostAsync(uri, stringContent);
HttpResponseMessage x = await response;
HttpContent requestContent = x.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
if (x.IsSuccessStatusCode == false && _throwExceptionOnFailure)
{
throw new Exception(url + " with POST ends with status code " + x.StatusCode + " and content " + jsonContent);
}
if (_parseOutput == false){
return default(O);
}
return JsonConvert.DeserializeObject<O>(jsonContent);
}
public async Task<O> DoPutRequest(string url, I input)
{
var client = new HttpClient();
CultureInfo ci = new CultureInfo(Windows.System.UserProfile.GlobalizationPreferences.Languages[0]);
client.DefaultRequestHeaders.Add("Accept-Language", ci.TwoLetterISOLanguageName);
var uri = new Uri(string.Format(
url,
"action",
"put",
DateTime.Now.Ticks
));
string serializedObject = JsonConvert.SerializeObject(input);
var response = client.PutAsync(uri,
new StringContent(
serializedObject,
Encoding.UTF8,
"application/json"));
HttpResponseMessage x = await response;
HttpContent requestContent = x.Content;
string jsonContent = requestContent.ReadAsStringAsync().Result;
if (x.IsSuccessStatusCode == false && _throwExceptionOnFailure)
{
throw new Exception(url + " with PUT ends with status code " + x.StatusCode + " and content " + jsonContent);
}
if (_parseOutput == false){
return default(O);
}
return JsonConvert.DeserializeObject<O>(jsonContent);
}
}
Then when I want to call it, I can use it as following :
JsonSend<User, RegistrationReceived> register = new JsonSend<User, RegistrationReceived>();
RegistrationReceived responseUser = await register.DoPostRequest("http://myurl", user);
The Nancy documentation seems to say that Pipelines.OnError should return null - as opposed to BeforeResponse which allows both null and a Response object.
All the examples like this one and many code samples here on StackOverflow show a Response being returned in the OnError, just like in the BeforeRequest.
When I attempt to return an HTTPStatus string for the Pipelines.OnError, everything works OK!
But when I attempt to return a Response, I get a compiler error:
Operator '+=' cannot be applied to operands of type 'Nancy.ErrorPipeline' and 'lambda expression'
I'm emulating almost exactly the code in the Nancy example, except for the fact that mine is a TinyIocContainer while the example's is using a StructureMap container and a StructureMap derived bootstrapper
Here's my code:
const string errKey = "My proj error";
const string creationProblem = "Message creation (HTTP-POST)";
const string retrievalProblem = "Message retrieval (HTTP-GET)";
public void Initialize(IPipelines pipelines)
{
string jsonContentType = "application/json";
byte[] jsonFailedCreate = toJsonByteArray(creationProblem);
byte[] jsonFailedRetrieve = toJsonByteArray(retrievalProblem);
Response responseFailedCreate = new Response
{
StatusCode = HttpStatusCode.NotModified,
ContentType = jsonContentType,
Contents = (stream) =>
stream.Write(jsonFailedCreate, 0, jsonFailedCreate.Length)
};
Response responseFailedRetrieve = new Response
{
StatusCode = HttpStatusCode.NotFound,
ContentType = jsonContentType,
Contents = (stream) =>
stream.Write(jsonFailedRetrieve, 0, jsonFailedRetrieve.Length)
};
// POST - error in Create call
pipelines.OnError += (context, exception) =>
{
// POST - error during Create call
if (context.Request.Method == "POST")
return responsefailedCreate;
// GET - error during Retrieve call
else if (context.Request.Method == "GET")
return responseFailedRetrieve;
// All other cases - not supported
else
return HttpStatusCode.InternalServerError;
};
}
private byte[] toJsonByteArray(string plainString)
{
string jsonString = new JObject { { errKey, plainString } }.ToString();
byte[] result = Encoding.UTF8.GetBytes(jsonString);
return result;
}
I had the same problem and I found a nice approach to the problem: http://paulstovell.com/blog/consistent-error-handling-with-nancy.
you should override RequestStartup on the Bootstrapper, here my test code:
protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
{
pipelines.OnError.AddItemToEndOfPipeline((ctx, ex) =>
{
DefaultJsonSerializer serializer = new DefaultJsonSerializer();
Response error = new JsonResponse(ex.Message,serializer);
error.StatusCode = HttpStatusCode.InternalServerError;
return error;
});
base.RequestStartup(container, pipelines, context);
}
I have the following, and it uploads without errors, but the image is always 0 bytes.
Windows Phone App (this is called after selecting or taking a photo):
private void AddImage(PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
string serviceUri = Globals.GreedURL + #"API/UploadPhoto/test5.jpg";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(serviceUri);
request.Method = "POST";
request.BeginGetRequestStream(result =>
{
Stream requestStream = request.EndGetRequestStream(result);
e.ChosenPhoto.CopyTo(requestStream);
requestStream.Close();
request.BeginGetResponse(result2 =>
{
try
{
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result2);
if (response.StatusCode == HttpStatusCode.Created)
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Upload completed.");
});
}
else
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("An error occured during uploading. Please try again later.");
});
}
}
catch
{
this.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("An error occured during uploading. Please try again later.");
});
}
e.ChosenPhoto.Close();
}, null);
}, null);
}
And here is the Web API:
public class UploadPhotoController : ApiController
{
public HttpResponseMessage Post([FromUri]string filename)
{
var task = this.Request.Content.ReadAsStreamAsync();
task.Wait();
Stream requestStream = task.Result;
// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(ConfigurationManager.ConnectionStrings["StorageConnectionString"].ConnectionString);
// Create the blob client.
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();
// Retrieve reference to a previously created container.
CloudBlobContainer container = blobClient.GetContainerReference("profilepics");
container.CreateIfNotExists();
var permissions = container.GetPermissions();
permissions.PublicAccess = BlobContainerPublicAccessType.Blob;
container.SetPermissions(permissions);
string uniqueBlobName = string.Format("test.jpg");
CloudBlockBlob blob = container.GetBlockBlobReference(uniqueBlobName);
blob.Properties.ContentType = "image\\jpeg";
blob.UploadFromStream(task.Result);
HttpResponseMessage response = new HttpResponseMessage();
response.StatusCode = HttpStatusCode.Created;
return response;
}
}
Any ideas?
Any help would be appreciated.