I am using a REST API in Yii2 with Authorization Bearer
I have configured the actionUpdate completely but somehow when using PUT to update the data, I am getting null value when I try to get the post data,
print_r($request->getBodyParam('member_id'))
Get below result when print_r(Yii::$app->request->bodyParams):
Content -type is multipart/form-data
Array
(
[------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition:_form-data;_name] => "member_id"
274505
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="claim_type"
3
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="visit_date"
2016-10-12
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="provider_id"
0
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="diagnosis"
fevercc
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="reimbursement"
1
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="non_panel"
true
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="provider_name"
klinik abc
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="reimbursement_reason"
near to house
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="invoice_no"
1245
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="medical_leave"
0
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="leave_form"
------WebKitFormBoundaryAF3YWAApi5BxYUb2
Content-Disposition: form-data; name="amount_incurred" 24
------WebKitFormBoundaryAF3YWAApi5BxYUb2--
)
Below is my actionUpdate
public function actionUpdate($id) {
$claim = $this->findModel($id);
$claim->scenario = 'update';
if ( $claim->status_id == 1 ) {
$request = Yii::$app->request;
if (isset($request)) {
$member_id = $request->getBodyParam('member_id');
$claim_type = $request->getBodyParam('claim_type');
$visit_date = $request->getBodyParam('visit_date');
$provider_id = $request->getBodyParam('provider_id');
$diagnosis = $request->getBodyParam('diagnosis');
$reimbursement = $request->getBodyParam('reimbursement');
$userlogin_id = Yii::$app->user->identity->id;
if ($claim->validate() ) {
$claim->save();
return array('id'=>$claim->id,'msg'=>'Successfully update claim');
} else {
return (ActiveForm::validate($claim));
}
}
} else {
throw new \yii\web\MethodNotAllowedHttpException('You are not allowed to update data');
}
}
Related
I develop this scrapy crawler, with a loop to scrap 10 pages from one site
The loop works well and the log show me the correct list of urls
2018-10-08 07:59:54 [scrapy.core.scraper] DEBUG: Scraped from <200 https://www.lazada.vn/trang-diem/?page=8&ajax=true>
2018-10-08 07:59:54 [scrapy.core.scraper] DEBUG: Scraped from <200 https://www.lazada.vn/trang-diem/?page=9&ajax=true>
But the result is always the same, and return the content of page1
I test in shell and it works correctly, from the browser too. Only with scrapy crawler the problem occur
I tried with start_urls, url method, always the same problem
Any idea ?
import scrapy
import json
import urllib
import time
import datetime
import re
from re import sub
from decimal import Decimal
#from prod.items import ProdItem
from staging.items import StagingItem
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor
ts = time.time()
timestamp = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d')
class QuotesSpider(scrapy.Spider):
name = "lazada2"
def start_requests(self):
for i in range(1, 10):
urls = 'https://www.lazada.vn/trang-diem/?page=%s&ajax=true' % i
yield scrapy.Request(url=urls, callback=self.parse)
def parse(self,response):
data = json.loads(response.body)
next_page = data['mainInfo']['page']
for product in data['mods']['listItems']:
item = StagingItem()
item['collector_sku'] = product['name']
if 'originalPrice' in product:
item['collector_price_promo'] = product['originalPrice'],
else:
item['collector_price_promo'] = '',
item['collector_retailer'] = 'Lazada'
item['collector_url'] = product['productUrl'],
item['collector_photo_url'] = product['image']
item['collector_brand'] = product['brandName']
item['collector_quantity'] = 'NA'
item['collector_category'] = 'Makeup',
item['collector_price'] = product['price']
item['collector_timestamp'] = timestamp
item['collector_local_id'] = ''
item['collector_location_id'] = ''
item['collector_location_name'] = ''
item['collector_vendor_id'] = ''
item['collector_vendor_name'] = ''
yield item
With the cookies and headers
:
headers = {
"content-type": "application/json",
"authority": "www.lazada.vn",
"scheme": "https",
"Accept-Language": "en-SG,en;q=0.9,en-US;q=0.8,zh-CN;q=0.7,zh;q=0.6,vi;q=0.5,fr;q=0.4",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36",
"Accept": "*/*",
"Path": "/trang-diem/?page=%s" % i,
"Referer": "https://www.lazada.vn/trang-diem/?page=%s&ajax=true" % i,
"accept-encoding": "gzip, deflate, br"
}
cookies = {
"cookie": "_uab_collina=153864259681792402093714; _bl_uid=qpj7jm4CuXhcUk26er9n7hnhyRqd; t_fv=1538642596635; t_uid=mbei2vPUviVx0oPB6KjX1uVgASJvw7dA; lzd_cid=07e3d81c-bb96-4608-be5d-542d35d39dff; lzd_sid=1d8bf18519bb7fd8fb661ac558726c4d; _tb_token_=58e7f715a30eb; cna=O5A8FGGivzcCAXNPwzeoH+5y; hng=VN|vi|VND|704; userLanguageML=vi; cto_lwid=c9ad6486-acac-465f-ab05-6e0b3744d1dc; _ga=GA1.2.1435138343.1538642600; _gid=GA1.2.19901051.1538642600; cto_axid=zGni0uxNaRyv441RxQNq7EZ_LS8xiGmL; JSESSIONID=85306FF3F7612F91677FC6ED978B42E1; isg=BJ6eL8eUSXz4CZ0YqjCefDlu7zTqVCYsGgm5Z0gmm-DyaztFsOyk6OZNZi9CoFrx"
}
body ="?ajax=true&page=%s" % i
urls = "https://www.lazada.vn/trang-diem/?ajax=true&page=%s" % i
yield scrapy.Request(url=urls, body=body, cookies=cookies, headers=headers, callback=self.parse)
I'm trying to render an user image that comes from soap server response, it not should be difficult but i dont know how start to do.
This is the code of the request way:
this.http.post(wsurl, xml, {withCredentials: true, headers: headers})
.toPromise()
.then((response) =>....
This is the response:
------=_Part_18_19650293.1510067330953
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: binary
Content-Id: <94A7DA36FAAE3F537AD3295BF2DFF5AD>
<?xml version="1.0" encoding="UTF-8"?><soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Body>
..... data of the user
</soapenv:Body></soapenv:Envelope>
------=_Part_18_19650293.1510067330953
Content-Type: image/jpeg
Content-Transfer-Encoding: binary
Content-Id: <ACC047E73E810E9A61470902A1E4483F>
����JFIFdd��C��C��dd��
��6!aR�1AQ�"#q�2�4CSb���������?����9#�P3��9#�P3��9#�P3�s�P3�P3�P3�P3�P3�P3�P3�P3�P3�P3�P3�P3�PC�=�5w�
C��P�x#�=�j8�^��N����]X����4��3fql�]�Ʈ��VG-5m+^�:w���S�+���A���c�8����Yd�9`�t��g8��&W�� صw�
C��P�x#�=�5w��8#��S�
NT���L&��5CY�O�d��:�"ۋ{��z�om�A��I&��� ��$����襉��J�Z湦��75�?��^�#kb�H?-#Zʆ�����x��>�D��� jp���Z������;��j�(8��]����&��WO$������%�'����Z
��*&�ꞟ� O5�1��%�D������;��j�(������r���g(�-��m-e]+&mK)��6T0��Z�=��F##A��8ÍUP�cC��Ml���9sJ��P3��9A8�8�8��s\�5�������q�T����ps]N���p��X��DZ�p�������M8�)VC�
;cO���?�����9#�9#�9#�9AP�x#�=�5w�
C���3 ����ĩ ғ3|��F�!�:��[_��*�-Ѹ]�P��0ʌB(���ߍ�{�7�ͽ����ר{� j���������� jp���
3�h�]ӵ2�M�;�
qh1��!��S`���M�i>��ϧ�r�3! X=�����S5��5�
kE�Ѱ �S�
N58#��-A�~�����|媆�,����{��I��������Sbs�m�F����o��S��'��z��Ӵ�&�F��os���A�##Ac`*���l]����2��k؇X?{nH?����*�Y31hc�.I�����2ٚ���k���n(=��;��<���W�!���̓~�3XF��?���\)�����䩫���)��q���=�A�;�ªSE9������=�=���z�,r���t_�i���no���9!�g(1�QSA5D�ӧc�%��V��YW5uT�u�4�.y������ ����������7Ӹ���Z�`�"���o��?����^Y�(0���8��>^k���b����d��
------=_Part_18_19650293.1510067330953--
Then I cut the image data to :
����JFIFdd��C��C��dd��
��6!aR�1AQ�"#q�2�4CSb���������?����9#�P3��9#�P3��9#�P3�s�P3�P3�P3�P3�P3�P3�P3�P3�P3�P3�P3�P3�PC�=�5w�
C��P�x#�=�j8�^��N����]X����4��3fql�]�Ʈ��VG-5m+^�:w���S�+���A���c�8����Yd�9`�t��g8��&W�� صw�
C��P�x#�=�5w��8#��S�
NT���L&��5CY�O�d��:�"ۋ{��z�om�A��I&��� ��$����襉��J�Z湦��75�?��^�#kb�H?-#Zʆ�����x��>�D��� jp���Z������;��j�(8��]����&��WO$������%�'����Z
��*&�ꞟ� O5�1��%�D������;��j�(������r���g(�-��m-e]+&mK)��6T0��Z�=��F##A��8ÍUP�cC��Ml���9sJ��P3��9A8�8�8��s\�5�������q�T����ps]N���p��X��DZ�p�������M8�)VC�
;cO���?�����9#�9#�9#�9AP�x#�=�5w�
C���3 ����ĩ ғ3|��F�!�:��[_��*�-Ѹ]�P��0ʌB(���ߍ�{�7�ͽ����ר{� j���������� jp���
3�h�]ӵ2�M�;�
qh1��!��S`���M�i>��ϧ�r�3! X=�����S5��5�
kE�Ѱ �S�
N58#��-A�~�����|媆�,����{��I��������Sbs�m�F����o��S��'��z��Ӵ�&�F��os���A�##Ac`*���l]����2��k؇X?{nH?����*�Y31hc�.I�����2ٚ���k���n(=��;��<���W�!���̓~�3XF��?���\)�����䩫���)��q���=�A�;�ªSE9������=�=���z�,r���t_�i���no���9!�g(1�QSA5D�ӧc�%��V��YW5uT�u�4�.y������ ����������7Ӹ���Z�`�"���o��?����^Y�(0���8��>^k���b����d��
EDIT1
These methods are the methods that I have used to convert binary to base64
let b64 = this._arrayBufferToBase64(result)
this.imgStr = 'data:image/jpeg;base64,' + b64
_arrayBufferToBase64( buffer ) {
let binary = '';
let bytes = new Uint8Array( this.str2ab(buffer) );
let len = bytes.byteLength;
console.log("lenbytes " + len)
for (let i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}
return window.btoa( binary );
}
str2ab(str) {
var buf = new ArrayBuffer(str.length*2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i=0, strLen=str.length; i<strLen; i++) {
bufView[i] = str.charCodeAt(i);
}
return buf;
}
The methods generate a src to the image like this:
data:image/jpeg;base64,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
But the image not renders on screen
What can I'm doing wrong?
Thanks
I'm not an image converting expert, but if it's a binary encoded image, try this :
let img = document.createElement('img');
img.src = 'data:image/jpeg;base64,' + btoa('your binary data here');
// image now contains your picture
But I'm not sure this is correct data ... Anyways, try this, and let me know the result
For dealing with blobs coming from a server try the following
// Get the blob via an angular service - with response type "blob" as "json"
getBlob() {
return this.http_.get(`${this.url}/getBlob`, {responseType:"blob" as "json"});
}
//In your component
imageUrl: string;
getBlobUrl(){
this.blobService.getBlob().subscribe((data: Blob) => {
this.createImageFromBlob(data);
})
}
createImageFromBlob(image: Blob) {
let reader = new FileReader();
reader.addEventListener("load", () => {
this.imageUrl= reader.result;
}, false);
if (image) {
reader.readAsDataURL(image);
}
}
<!--HTML-->
<div>
<img [src]="imageUrl">
</div>
If you have blob value, you can directly set the value in image tag in html..
Instead of this.imgStr = 'data:image/jpeg;base64,' + b64;
use this.imgStr = b64;
<img src="data:image/png;base64,{{imgStr}}" />
I am using python url library to get json response from spatial reference website.This is my code. I get response_read="u'{\'type\': \'EPSG\', \'properties\': {\'code\': 102646}}'" but i need this response in this form:"{'type': 'EPSG', 'properties': {'code': 102646}}". How i achieve output in this form?
headers = {'User-Agent': 'Mozilla/5.0'}
req = urllib2.Request("http://spatialreference.org/ref/esri/"nad-1983-stateplane-california-vi-fips-0406-feet"/json/", None, headers)
response = urllib2.urlopen(req)
response_read = response.read().decode('utf-8')
result = json.dumps(response_read)
epsg_json = json.loads(result)
epsg_code = epsg_json['properties']['code']
return epsg_code
you need to first use dumps then loads
json_data = json.dumps(response_read)
json_without_slash = json.loads(json_data)
I am not very sure your is a function or not. Anyways, the response you receive is having the literal character ' and you need to replace it with ".
Here is the working code:
import urllib2,json
headers = {'User-Agent': 'Mozilla/5.0'}
req = urllib2.Request("http://spatialreference.org/ref/esri/nad-1983-stateplane-california-vi-fips-0406-feet/json/", None, headers)
response = urllib2.urlopen(req)
response_read = response.read()
epsg_json = json.loads(response_read.replace("\'", '"'))
epsg_code = epsg_json['properties']['code']
print(epsg_code)
Hope this helps.
Grails 2.4 RESTful controller.
I have a basic question. I have a RESTful controller with simple domain class and my GET, POST works fine.
How do I send PUT JSON request?
I am using default RESTful generated controllers
url -i -X POST -H "Content-Type: application/json" -d '{"roleId":1,"username":"testuser5"}' http://localhost:8090/testapp/User
HTTP/1.1 201 Created
Server: Apache-Coyote/1.1
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 03 Jul 2014 02:07:13 GMT
{"id":null,"userId":79,"username":"testuser5"}
Then I tried PUT using same above JSON response (removed id:null and changed the username):
curl -i -X PUT -H "Content-Type: application/json" -d '{"userId":79,"username":"testuser6"}' http://localhost:8090/testapp/User
Request goes to index and I get list of users. What I am doing wrong? How do I invoke "update' method? If I add my own method and I do PUT, my own method gets invoked.
Domain class:
class User {
Integer userId
String username
static mapping = {
table 'user'
version false
id name:'userId', column: 'user_id'
}
static constraints = {
username blank:false, nullable:false
}
}
RESTful controller:
class UserController extends RestfulController {
static responseFormats = ['json', 'xml']
static allowedMethods = [save: "POST", update: "PUT", delete: "DELETE"]
def index(Integer max) {
params.max = Math.min(max ?: 10, 100)
respond User.list(params), model:[userInstanceCount: User.count()]
}
def show(User userInstance) {
respond userInstance
}
def create() {
respond new User(params)
}
#Transactional
def update(User userInstance) {
println "*** in update "
if (userInstance == null) {
notFound()
return
}
if (userInstance.hasErrors()) {
respond userInstance.errors, view:'edit'
return
}
userInstance.save flush:true
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.updated.message', args: [message(code: 'User.label', default: 'User'), userInstance.id])
redirect userInstance
}
'*'{ respond userInstance, [status: OK] }
}
}
protected void notFound() {
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.id])
redirect action: "index", method: "GET"
}
'*'{ render status: NOT_FOUND }
}
}
}
You're missing the call to user.validate() prior to calling hasErrors(). See
https://github.com/grails/grails-core/blob/master/grails-plugin-rest/src/main/groovy/grails/rest/RestfulController.groovy#L99
I'm writing my own Box SDK for WP8 to make the most out of Tasks. I am having trouble obtaining an access token. I always get this as a return:
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
The code (all in C#) I'm using is:
internal const String TokenURL = "https://api.box.com/oauth2/token";
CloudHttpAsync.DownloadResponceStreamAsync
(
CloudHttpAsync.PostAsync
(
TokenURL,
new MemoryStream
(
UTF8Encoding.UTF8.GetBytes
(
HttpUtility.UrlEncode
(
String.Format
(
"grant_type=authorization_code&code={0}&client_id={1}&client_secret={2}&redirect_uri={3}",
Code,
ClientID,
ClientSecret,
RedirectURI
)
)
)
),
null,
null
),
null
).ContinueWith((AsyncStream) =>
{
try
{
if (AsyncStream.Exception != null)
{
TaskSource.TrySetException(AsyncStream.Exception.InnerExceptions);
return;
}
String Result = "";
using (StreamReader Reader = new StreamReader(AsyncStream.Result))
{
Result = Reader.ReadToEnd();
}
BoxAuthToken Token = JsonConvert.DeserializeObject<BoxAuthToken>(Result);
TaskSource.TrySetResult(Token);
}
catch (Exception e)
{
TaskSource.TrySetException(e);
}
});
and
public static Task<HttpWebResponse> PostAsync(String URL, Stream UploadData, IRequestSigner Signer, IProgress<NetworkProgress> Progress)
{
TaskCompletionSource<HttpWebResponse> TaskSource = new TaskCompletionSource<HttpWebResponse>();
HttpWebRequest Request = WebRequest.CreateHttp(URL);
Request.Method = "POST";
if (Signer != null)
{
Signer.Sign(Request).ContinueWith((o) =>
{
if (o.Exception != null)
{
TaskSource.TrySetException(o.Exception.InnerExceptions);
return;
}
UploadDataAsync(Request, UploadData, Progress).ContinueWith((AsyncRequest) =>
{
if (AsyncRequest.Exception != null)
{
TaskSource.TrySetException(AsyncRequest.Exception.InnerExceptions);
return;
}
GetResponceAsync(Request).ContinueWith((AsyncResponce) =>
{
if (AsyncResponce.Exception != null)
{
TaskSource.TrySetException(AsyncResponce.Exception.InnerExceptions);
return;
}
TaskSource.TrySetResult(AsyncResponce.Result);
});
});
});
}
else
{
UploadDataAsync(Request, UploadData, Progress).ContinueWith((AsyncRequest) =>
{
if (AsyncRequest.Exception != null)
{
TaskSource.TrySetException(AsyncRequest.Exception.InnerExceptions);
return;
}
GetResponceAsync(Request).ContinueWith((AsyncResponce) =>
{
if (AsyncResponce.Exception != null)
{
TaskSource.TrySetException(AsyncResponce.Exception.InnerExceptions);
return;
}
TaskSource.TrySetResult(AsyncResponce.Result);
});
});
}
return TaskSource.Task;
}
internal static Task<HttpWebRequest> UploadDataAsync(HttpWebRequest Request, Stream Data, IProgress<NetworkProgress> Progress)
{
TaskCompletionSource<HttpWebRequest> TaskSource = new TaskCompletionSource<HttpWebRequest>();
if (Data.Length != 0)
{
Request.ContentLength = Data.Length;
Request.AllowWriteStreamBuffering = false;
Request.BeginGetRequestStream(new AsyncCallback((IAR) =>
{
try
{
using (Stream UploadStream = Request.EndGetRequestStream(IAR))
{
Int64 Upload = 0;
Int64 TotalUploaded = 0;
Int64 Total = Data.Length;
Byte[] Buffer = new Byte[4096];
while (TotalUploaded < Total)
{
Upload = Data.Read(Buffer, 0, Buffer.Length);
TotalUploaded += Upload;
UploadStream.Write(Buffer, 0, (Int32)Upload);
if (Progress != null)
{
Progress.Report(new NetworkProgress()
{
Operation = NetworkOperation.Uploading,
TotalBytes = Total,
BytesProcessed = TotalUploaded
});
}
}
}
TaskSource.TrySetResult(Request);
}
catch (Exception e)
{
TaskSource.TrySetException(e);
}
}),
null);
}
else
{
TaskSource.TrySetResult(Request);
}
return TaskSource.Task;
}
internal static Task<HttpWebResponse> GetResponceAsync(HttpWebRequest Request)
{
TaskCompletionSource<HttpWebResponse> TaskSource = new TaskCompletionSource<HttpWebResponse>();
Request.BeginGetResponse(new AsyncCallback((IAR) =>
{
try
{
HttpWebResponse Responce = (HttpWebResponse)Request.EndGetResponse(IAR);
TaskSource.TrySetResult(Responce);
}
catch (Exception e)
{
if (e is WebException && (e as WebException).Response.ContentLength > 0)
{
TaskSource.TrySetResult((HttpWebResponse)(e as WebException).Response);
}
else
{
TaskSource.TrySetException(e);
}
}
}),
null);
return TaskSource.Task;
}
public static Task<StreamAndLength> GetResponceStreamAsync(Task<HttpWebResponse> Task)
{
TaskCompletionSource<StreamAndLength> TaskSource = new TaskCompletionSource<StreamAndLength>();
Task.ContinueWith((AsyncHWR) =>
{
if (AsyncHWR.Exception != null)
{
TaskSource.TrySetException(AsyncHWR.Exception.InnerExceptions);
return;
}
HttpWebResponse Responce = AsyncHWR.Result;
TaskSource.TrySetResult( new StreamAndLength() { Stream = Responce.GetResponseStream(), Length = Responce.ContentLength });
});
return TaskSource.Task;
}
public static Task<MemoryStream> DownloadResponceStreamAsync(Task<HttpWebResponse> Task, IProgress<NetworkProgress> Progress)
{
TaskCompletionSource<MemoryStream> TaskSource = new TaskCompletionSource<MemoryStream>();
GetResponceStreamAsync(Task).ContinueWith((AsyncStream) =>
{
if (AsyncStream.Exception != null)
{
TaskSource.TrySetException(AsyncStream.Exception.InnerExceptions);
return;
}
MemoryStream MemStream = new MemoryStream();
MemStream.SetLength(AsyncStream.Result.Length);
Int64 CurrentRead = 0;
Int64 TotalRead = 0;
Int64 Total = AsyncStream.Result.Length;
Byte[] Buffer = new Byte[4096];
using (Stream DownloadStream = AsyncStream.Result.Stream)
while (TotalRead < Total)
{
CurrentRead = DownloadStream.Read(Buffer, 0, Buffer.Length);
MemStream.Write(Buffer, 0, (Int32)CurrentRead);
TotalRead += CurrentRead;
if (Progress != null)
{
Progress.Report(new NetworkProgress()
{
Operation = NetworkOperation.Downloading,
TotalBytes = Total,
BytesProcessed = TotalRead
});
}
}
MemStream.Position = 0;
TaskSource.TrySetResult(MemStream);
});
return TaskSource.Task;
}
internal class StreamAndLength
{
public Stream Stream { get; set; }
public Int64 Length { get; set; }
}
Sorry there is a lot of code, I like to write generically :)
Edit: Raw Responces (ClientID & Client Secret removed)
When URL encoding each value:
POST https://api.box.com/oauth2/token HTTP/1.1
Accept: */*
Content-Length: 196
Accept-Encoding: identity
User-Agent: NativeHost
Host: api.box.com
Connection: Keep-Alive
Cache-Control: no-cache
grant_type=authorization_code&code=JknaLbfT6lAXmey3FLYrp9eg1jMbpFuQ&client_id=[subbed]&client_secret=[subbed]&redirect_uri=https%3a%2f%2fCloudBoxWP8
Return:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 01 Mar 2013 07:35:22 GMT
Content-Type: application/json
Connection: keep-alive
Set-Cookie: box_visitor_id=51305a3a187f34.52738262; expires=Sat, 01-Mar-2014 07:35:22 GMT; path=/; domain=.box.com
Set-Cookie: country_code=US; expires=Tue, 30-Apr-2013 07:35:22 GMT; path=/
Cache-Control: no-store
Content-Length: 99
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
When URL encode the entire string:
POST https://api.box.com/oauth2/token HTTP/1.1
Accept: */*
Content-Length: 214
Accept-Encoding: identity
User-Agent: NativeHost
Host: api.box.com
Connection: Keep-Alive
Cache-Control: no-cache
grant_type%3dauthorization_code%26code%3d3ikruv5elfdw3fOP55aMDSX7ybLqBFlA%26client_id%3d[subbed]%26client_secret%3d[subbed]%26redirect_uri%3dhttps%3a%2f%2fCloudBoxWP8
Return
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 01 Mar 2013 07:46:03 GMT
Content-Type: application/json
Connection: keep-alive
Set-Cookie: box_visitor_id=51305cbb339de4.03221876; expires=Sat, 01-Mar-2014 07:46:03 GMT; path=/; domain=.box.com
Set-Cookie: country_code=US; expires=Tue, 30-Apr-2013 07:46:03 GMT; path=/
Cache-Control: no-store
Content-Length: 99
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
No URL encoding:
POST https://api.box.com/oauth2/token HTTP/1.1
Accept: */*
Content-Length: 190
Accept-Encoding: identity
User-Agent: NativeHost
Host: api.box.com
Connection: Keep-Alive
Cache-Control: no-cache
grant_type=authorization_code&code=2wgIzfqhvIgRtVIp2ZvqZ9X8R5u0QNaf&client_id=[subbed]&client_secret=[subbed]&redirect_uri=https://CloudBoxWP8
Return:
HTTP/1.1 400 Bad Request
Server: nginx
Date: Fri, 01 Mar 2013 07:50:31 GMT
Content-Type: application/json
Connection: keep-alive
Set-Cookie: box_visitor_id=51305dc751d7f5.67064854; expires=Sat, 01-Mar-2014 07:50:31 GMT; path=/; domain=.box.com
Set-Cookie: country_code=US; expires=Tue, 30-Apr-2013 07:50:31 GMT; path=/
Cache-Control: no-store
Content-Length: 99
{"error":"invalid_request","error_description":"Invalid grant_type parameter or parameter missing"}
It's not listed anywhere on the Box API documentation, but the request for retrieving the access token requires the header Content-Type: application/x-www-form-urlencoded
I was also stuck on this part for a while until I found the answer on StackOverflow. I forget the link to it though.
The request/response would be helpful. It looks like you are UrlEncoding the entire query string instead of just each value. Which would be submitted to us as:
grant_type%3Dauthorization_code%26code%3Dxyz%26client_id%3Dxyz%26client_secret%3Dxyz%26redirect_uri%3Dxyz
Instead of:
grant_type=authorization_code&code=xyz&client_id=xyz&client_secret=xyz&redirect_uri=xyz
I think that including the redirect_uri in your request body could be complicating things, particularly because it looks to be set to an invalid value (https://CloudBoxWP8) You might resolve this by setting your app to handle a custom protocol (cloudboxwp8://) and pre-configuring Box to redirect to that when the token is granted.
Register a custom protocol for your WP8 app. For example, cloudboxwp8.
Augment your WP8 app to handle a request for some endpoint on that protocol. For example, cloudboxwp8://tokengranted. Implement your token handling logic here.
Edit your Box application and browse to the OAuth2 paramters section (via Manage a Box Application => Edit Application)
In the redirect_uri field, set the value to the custom protocol and endpoint from step 2. Save your changes.
Remove the redirect_uri from your request body and try your request again.
in Windows phone 8.1 WinRT
Dictionary<string, string> contentList = new Dictionary<string, string>();
contentList.Add("code", code);
contentList.Add("client_id", client_id);
contentList.Add("client_secret", clientSecret);
contentList.Add("redirect_uri", redirectUri);
contentList.Add("grant_type", "authorization_code");
FormUrlEncodedContent content = new FormUrlEncodedContent(contentList);
var response = await client.PostAsync(baseURL, content);
YouTubeAutenticationResponse res = JsonConvert.DeserializeObject<YouTubeAutenticationResponse>(await response.Content.ReadAsStringAsync());
public class YouTubeAutenticationResponse
{
[JsonProperty("access_token")]
public string AccessToken { get; set; }
[JsonProperty("token_type")]
public string TokenType { get; set; }
[JsonProperty("expires_in")]
public string ExpiresIn { get; set; }
[JsonProperty("refresh_token")]
public string RefreshToken { get; set; }
}