Creating SharePoint Framework Client Web Part and solving the challenges with _RequestDigest Token value using React
Recently I decided to add React and Angular to my portfolio for developing solutions for SharePoint. I'm starting with React and it has been an interesting journey so far. I started with React because Angular 2.x/4.x which is a major leap from Angular 1.x seems to have a few challenges integrating with SharePoint framework as Andrew Connell explains here. Though these challenges are being addressed with the roll out of Angluar 5 as seen in another of Andrew Connell post: Solve the SharePoint Framework + Angular Challenge with Angular 5.0 Elements. But as for me, I have decided to wait until Angular 5 is stable for SharePoint framework so that my learning can be seamless.
In this post I will be sharing what I have learnt in my few days of using React in SharePoint framework to build client web part. If you are considering learning React to work with SharePoint framework, these are some of the key concepts you will first need to understand to get started:
State- generally, state is like variable, you can declare its datatype and you can initialize it. You declare its datatype in an interface and initialize it in the constructor. Note: In React, you don't have to write a separate interface to declare the datatype but in SharePoint framework you have to. Getting confused? Don't worry, I will explain this better with an example later.
Props- props simply stands for properties. In React, they are used to pass data down to child components and they are fixed unlike state that can be updated. We will see an example later.
setState- This is like a method or function that is called to set the state of an object. So if you need to update your variables, you do that with setState. Updates can come from input elements on the page or from any datasource.
Constructor- as stated above, constructor is where you initialize your state. The constructor is also often used to bind event handlers to the class instance.
Event handlers- These are triggers like onChange, OnSubmit etc
componentDidMount- This method gets executed after a component has been rendered or mounted. This is a good place to call a remote endpoint e.g making a Resful call via ajax request. It is also a good place to implement subscription. Our example will give show each of these in action. Note that there are also other methods like componentWillMount(), componentWillUnmount() etc. that we can work with.
Another thing you may want to learn is stylesheet development with sass/scss to style your react forms. As a developer, that may not be your interest. The good news is you can use regular CSS to style your form. If you are interested in converting it to scss format, you can use this online generator to do that.
Enough stories! Let us go straight to our example. In this example, we want to create a simple contact Us form to demonstrate how React can be used to address the challenges posed by _RequestDigest to retrieve request digest token.
The number one challenge I faced while developing the web part was trying to use $('#_REQUESTDIGEST).val() to retrieve the token value, but this threw my entire lines of code into red underlines, document.getElementById('_REQUESTDIGEST).value that has worked for me in the past did not work either.
The second problem is that the request digest token that is issued is valid for 30 minutes by default. 30 minutes should be enough to complete most forms. But what if you have a longer form or let's say your users may want to leave the form open and do some other things, that means if they don't get to complete the form within 30 minutes they will get error 403 forbidden because the token would have expired, and they will loose all the information they have entered. This will generate a lot of complaints from your users and you don't want that. So in this example, I will use React to solve these two problems. Note: This second challenge has been addressed in SharePoint framework with SPHttpClient as explained here. But the article does not provide enough explanation on how to use it. If you know how to or if there is an article with examples on the usage kindly share it in the comment section.
Let's start by creating a working folder called spfx in the root of our C drive
1. Open command line and change directory to your C drive i.e. c:\>
2. Type md spfx and change directory to the folder using cd spfx
3. At the prompt, type yo @microsoft/sharepoint
4. Follow the screenshot below to complete scaffolding your solution files
5. When the scaffolding completes you will see a successful congratulations message like this
6. On the command prompt, type npm install jquery --save and npm install @types/jquery --save one after the other. This installs jquery library and its typings in our solution
7. Type code . to open your solution in Visual studio code
8. Lets un-bundle our jquery library by externalizing it. Go to config and open config.json
9. Modify the external section as follows
10. Go to src > webparts > reactTester > components and open ReactTester.tsx
11. In the import section at the top of the page, type import * as jQuery from 'jquery'
Now all is set for our contact us form. Firstly, lets define an interface for our state. We will call this IRequestState. Add the code below just above ReactTester class i.e. export default class ReactTester extends React.Component...
Here we declared five variables in this interface, namely: name, email, subject, message and formDigestValue. FormDigestvalue is the variable that will store our request digest token. Note: you could create a separate file for the interface and import it into the ReactTester.tsx file.
The next thing is to create a constructor and initialize our state. Add the constructor just below export default class ReactTester extends React.Component and modify the class as follows
Notice how I have added IRequestState as parameter to the class - see the red arrow. If you don't do that you will see red underline in the constructor. Also note that I did not pass props as parameter to my constructor or super, this is because I don't require props to access any data in my constructor at this point.
Before creating event handlers, lets design our Contact Us form. We will call it Contact IT Department
Copy the code below and modify public render method in ReactTester.tsx as follows
Then open ReactTester.module.scss. Replace its content with the styles below
Lets view the form. Save your changes and go to view on visual studio code, click Integrated terminal. In the Integrated terminal widow, type gulp build to build your solution. Then gulp serve to launch local workbench and add your web part. If all is fine your form should look like this
Before we go further in our code, lets create the custom list where the form will submit data to. In your SharePoint online, create a custom list and call it ContactList. Create the following fields-- type is single line of text for Full Name, Email and Subject and multiple line of text for Message. Note: I renamed the Title field to Full Name.
Now that we have created our list, lets go back to the code. Lets first create a method to get request digest token.
Copy the code below and paste just below the constructor
Explanation: I made a POST ajax request to _api/contextinfo, set the header and then pass the result data into the FormDigestValue variable using setState i.e setState({FormDigestvalue: resultData.d.GetContextWebInformation.FormDigestValue}). Request digest token is generated by and stored on FormDigestValue field. You can also retrieve other fields such as FormDigestTimeoutseconds, field storing the timeout session in case you want to manipulate timeout session in your code. But I will use a different approach for this. If you have fiddler, you can see more when you make a request to _api/contextinfo. You will see something like this
Hint: notice the JSON result...it cascades from d > GetContextWebInformation >FormDigestValue. This is the reason why the result data is set as resultData.d.GetContextWebInformation.FormDigestValue. If you want to retrieve FormDigestTimeoutseconds for instance, it will be resultData.d.GetContextWebInformation.FormDigestTimeoutseconds.
Next, lets create our event handlers, handleChange and handleSubmit and bind them in the constructor. Copy the code below and paste it below getAccessToken method:
Explanation: In this code block, I created a reusable handler (i.e. handleChange) to handle changes to the form input elements using target value. In the handleSubmit handler, I made an ajax POST request to our contact list (ContactList) that we created earlier, set X-RequestDigest in the header to FormDigestValue to retrieve the request digest token. Note: If you try to use ('#_REQUESTDIGEST).val() here it won't work. I then reset the form fields back to empty strings using setState.
Now update the constructor by adding the following lines after this.state={....}; code block but before the closing brace for the constructor:
this.handleSubmit=this.handleSubmit.bind(this);
this.handleChange=this.handleChange.bind(this);
We do this to bind our handlers to their respective class instance.
Still in Reacttester.tsx file, update the form element in the public render with onSubmit attribute as follows
With this you are done. If you deploy the web part, it will work fine. But there is a challenge; as mentioned earlier, the request digest token expires after 30 minutes, and what if this is a long form and users may need to do some other things in between while filling the form. A scenario like this can elongate the filling process. The challenge is that the form will timeout while users are still completing the form; and when they try to submit they get error 403 forbidden. To address this challenge, we will use componentDidMount() method to subscribe to our getAccessToken method.
Lets create a variable called timerID i.e. var timerID. Put this just above export default class ReactTester....
Then copy and paste the lines of code below under handleSubmit method
Explanation: In the componentDidMount method, I first called getAccessToken method to generate the initial request digest token which expires in 30 minutes. I then used setInterval to subscribe to getAccessToken method again, but delay the execution for about 29 minutes (i.e. 1770000 milliseconds) , this ensures that I get a new token before the initial value expires. This repeats every 29 minutes and the result is stored in timerID variable.
Lastly I implemented conmponentWillUnmount() method to clear the timer. This is necessary to avoid performance issue. This simply says, clear the timer when component unmounts i.e. when you navigate away from the component.
With this you are good to go. Your entire code should look like this:
To test your solution, save all your changes. This should automatically refresh your workbench if you still have gulp serve running. Otherwise, run gulp serve again from the Integrated terminal.
Now go your SharePoint developer site, and navigate to workbench by appending _layouts/15/workbench.aspx to you site name. click the plus + sign to add your web part. Your web part should automatically retrieve your name and email. See the screenshot below:
Complete the rest of the form and hit the submit button. If everything works fine, you should get an alert message that your form was submitted successfully.
Note: You can change the timer to test how componentDidMount helps to refresh the token. Try changing it to 5 minutes i.e. 3000 milliseconds and use fiddler to monitor the changes.
I hope you will find information contained in this post useful. Please do leave me a comment if you see anything you want me to correct or explain better. Thanks for reading.
Useful Links:
https://reactjs.org/docs/components-and-props.html
https://reactjs.org/docs/react-component.html
https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/basics/working-with-requestdigest
In this post I will be sharing what I have learnt in my few days of using React in SharePoint framework to build client web part. If you are considering learning React to work with SharePoint framework, these are some of the key concepts you will first need to understand to get started:
- State
- Props (Properties)
- setState
- Constructor
- Event hanlers
- componentDidMount
State- generally, state is like variable, you can declare its datatype and you can initialize it. You declare its datatype in an interface and initialize it in the constructor. Note: In React, you don't have to write a separate interface to declare the datatype but in SharePoint framework you have to. Getting confused? Don't worry, I will explain this better with an example later.
Props- props simply stands for properties. In React, they are used to pass data down to child components and they are fixed unlike state that can be updated. We will see an example later.
setState- This is like a method or function that is called to set the state of an object. So if you need to update your variables, you do that with setState. Updates can come from input elements on the page or from any datasource.
Constructor- as stated above, constructor is where you initialize your state. The constructor is also often used to bind event handlers to the class instance.
Event handlers- These are triggers like onChange, OnSubmit etc
componentDidMount- This method gets executed after a component has been rendered or mounted. This is a good place to call a remote endpoint e.g making a Resful call via ajax request. It is also a good place to implement subscription. Our example will give show each of these in action. Note that there are also other methods like componentWillMount(), componentWillUnmount() etc. that we can work with.
Another thing you may want to learn is stylesheet development with sass/scss to style your react forms. As a developer, that may not be your interest. The good news is you can use regular CSS to style your form. If you are interested in converting it to scss format, you can use this online generator to do that.
Enough stories! Let us go straight to our example. In this example, we want to create a simple contact Us form to demonstrate how React can be used to address the challenges posed by _RequestDigest to retrieve request digest token.
The number one challenge I faced while developing the web part was trying to use $('#_REQUESTDIGEST).val() to retrieve the token value, but this threw my entire lines of code into red underlines, document.getElementById('_REQUESTDIGEST).value that has worked for me in the past did not work either.
The second problem is that the request digest token that is issued is valid for 30 minutes by default. 30 minutes should be enough to complete most forms. But what if you have a longer form or let's say your users may want to leave the form open and do some other things, that means if they don't get to complete the form within 30 minutes they will get error 403 forbidden because the token would have expired, and they will loose all the information they have entered. This will generate a lot of complaints from your users and you don't want that. So in this example, I will use React to solve these two problems. Note: This second challenge has been addressed in SharePoint framework with SPHttpClient as explained here. But the article does not provide enough explanation on how to use it. If you know how to or if there is an article with examples on the usage kindly share it in the comment section.
Let's start by creating a working folder called spfx in the root of our C drive
1. Open command line and change directory to your C drive i.e. c:\>
2. Type md spfx and change directory to the folder using cd spfx
3. At the prompt, type yo @microsoft/sharepoint
4. Follow the screenshot below to complete scaffolding your solution files
5. When the scaffolding completes you will see a successful congratulations message like this
6. On the command prompt, type npm install jquery --save and npm install @types/jquery --save one after the other. This installs jquery library and its typings in our solution
7. Type code . to open your solution in Visual studio code
8. Lets un-bundle our jquery library by externalizing it. Go to config and open config.json
9. Modify the external section as follows
10. Go to src > webparts > reactTester > components and open ReactTester.tsx
11. In the import section at the top of the page, type import * as jQuery from 'jquery'
Now all is set for our contact us form. Firstly, lets define an interface for our state. We will call this IRequestState. Add the code below just above ReactTester class i.e. export default class ReactTester extends React.Component...
Here we declared five variables in this interface, namely: name, email, subject, message and formDigestValue. FormDigestvalue is the variable that will store our request digest token. Note: you could create a separate file for the interface and import it into the ReactTester.tsx file.
The next thing is to create a constructor and initialize our state. Add the constructor just below export default class ReactTester extends React.Component
Before creating event handlers, lets design our Contact Us form. We will call it Contact IT Department
Copy the code below and modify public render method in ReactTester.tsx as follows
Then open ReactTester.module.scss. Replace its content with the styles below
Lets view the form. Save your changes and go to view on visual studio code, click Integrated terminal. In the Integrated terminal widow, type gulp build to build your solution. Then gulp serve to launch local workbench and add your web part. If all is fine your form should look like this
One thing you might want to do is fetching the current user details, full name and email so they don't have to type them in. Let's try to do that.
Open IReactTesterProps.ts and update as thus:
Then go to ReactTesterWebPart.ts and modify the public render() method as follows
To be able to access these properties from our ReactTester.tsx file, we will need to update our constructor by setting default values for name and email variables in the state initialization. Modify the constructor as follows
Note that I have now passed props as parameter to my constructor and super. This is because I now require props in my constructor. If you remember from my explanation above, I explained that props is used to pass data down to child components. This is an example of such. If don't add props as a parameter in your constructor, your web part will disappear and you will get the following similar error when you inspect your page in the browser. You can test it by removing props and try to load the web part. Note: As already mentioned, you don't have to add props if you won't need it in the constructor.
To test this, save your changes, this will automatically refresh your workbench. You should now see your form with user details
Now that we have created our list, lets go back to the code. Lets first create a method to get request digest token.
Copy the code below and paste just below the constructor
Explanation: I made a POST ajax request to _api/contextinfo, set the header and then pass the result data into the FormDigestValue variable using setState i.e setState({FormDigestvalue: resultData.d.GetContextWebInformation.FormDigestValue}). Request digest token is generated by and stored on FormDigestValue field. You can also retrieve other fields such as FormDigestTimeoutseconds, field storing the timeout session in case you want to manipulate timeout session in your code. But I will use a different approach for this. If you have fiddler, you can see more when you make a request to _api/contextinfo. You will see something like this
Hint: notice the JSON result...it cascades from d > GetContextWebInformation >FormDigestValue. This is the reason why the result data is set as resultData.d.GetContextWebInformation.FormDigestValue. If you want to retrieve FormDigestTimeoutseconds for instance, it will be resultData.d.GetContextWebInformation.FormDigestTimeoutseconds.
Next, lets create our event handlers, handleChange and handleSubmit and bind them in the constructor. Copy the code below and paste it below getAccessToken method:
Explanation: In this code block, I created a reusable handler (i.e. handleChange) to handle changes to the form input elements using target value. In the handleSubmit handler, I made an ajax POST request to our contact list (ContactList) that we created earlier, set X-RequestDigest in the header to FormDigestValue to retrieve the request digest token. Note: If you try to use ('#_REQUESTDIGEST).val() here it won't work. I then reset the form fields back to empty strings using setState.
Now update the constructor by adding the following lines after this.state={....}; code block but before the closing brace for the constructor:
this.handleSubmit=this.handleSubmit.bind(this);
this.handleChange=this.handleChange.bind(this);
We do this to bind our handlers to their respective class instance.
Still in Reacttester.tsx file, update the form element in the public render with onSubmit attribute as follows
With this you are done. If you deploy the web part, it will work fine. But there is a challenge; as mentioned earlier, the request digest token expires after 30 minutes, and what if this is a long form and users may need to do some other things in between while filling the form. A scenario like this can elongate the filling process. The challenge is that the form will timeout while users are still completing the form; and when they try to submit they get error 403 forbidden. To address this challenge, we will use componentDidMount() method to subscribe to our getAccessToken method.
Lets create a variable called timerID i.e. var timerID. Put this just above export default class ReactTester....
Then copy and paste the lines of code below under handleSubmit method
Explanation: In the componentDidMount method, I first called getAccessToken method to generate the initial request digest token which expires in 30 minutes. I then used setInterval to subscribe to getAccessToken method again, but delay the execution for about 29 minutes (i.e. 1770000 milliseconds) , this ensures that I get a new token before the initial value expires. This repeats every 29 minutes and the result is stored in timerID variable.
Lastly I implemented conmponentWillUnmount() method to clear the timer. This is necessary to avoid performance issue. This simply says, clear the timer when component unmounts i.e. when you navigate away from the component.
With this you are good to go. Your entire code should look like this:
To test your solution, save all your changes. This should automatically refresh your workbench if you still have gulp serve running. Otherwise, run gulp serve again from the Integrated terminal.
Now go your SharePoint developer site, and navigate to workbench by appending _layouts/15/workbench.aspx to you site name. click the plus + sign to add your web part. Your web part should automatically retrieve your name and email. See the screenshot below:
Complete the rest of the form and hit the submit button. If everything works fine, you should get an alert message that your form was submitted successfully.
Note: You can change the timer to test how componentDidMount helps to refresh the token. Try changing it to 5 minutes i.e. 3000 milliseconds and use fiddler to monitor the changes.
I hope you will find information contained in this post useful. Please do leave me a comment if you see anything you want me to correct or explain better. Thanks for reading.
Useful Links:
https://reactjs.org/docs/components-and-props.html
https://reactjs.org/docs/react-component.html
https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/basics/working-with-requestdigest
Very nice explanation !
ReplyDeleteThe blog you shared is very good. I expect more information from you like this. Thankyou.
ReplyDeleteLoadRunner Training in Chennai
Loadrunner Training
best loadrunner training in chennai
Loadrunner Training in OMR
QTP Training in Chennai
qtp training institutes in chennai
DOT NET Training in Chennai
Html5 Training in Chennai
Amazing blog with the latest information. Your blog helps me to improve myself in many ways. Looking forward for more like this.
ReplyDeleteRPA Training in Chennai
RPA course in Chennai
Blue Prism Training in Chennai
Blue Prism course in Chennai
Blue Prism Training in Anna Nagar
UiPath Training in Chennai
RPA Training in Velachery
RPA Training in Anna Nagar
Outstanding blog with lots of information. Keep posting more like this.
ReplyDeleteAngularJS Training in Chennai
AngularJS course in Chennai
Angular 6 Training in Chennai
ReactJS Training in Chennai
Web Designing course in Chennai
Salesforce Training in Chennai
ccna course in Chennai
Ethical Hacking course in Chennai
AngularJS Training in Velachery
This comment has been removed by the author.
ReplyDelete"Nice article Instagram and Facebook have provided an amazing place for new brands to grow and flourish.
ReplyDeleteDigital Marketing Training Course in Chennai | Digital Marketing Training Course in Anna Nagar | Digital Marketing Training Course in OMR | Digital Marketing Training Course in Porur | Digital Marketing Training Course in Tambaram | Digital Marketing Training Course in Velachery
"
I feel very grateful that I read this. It is very helpful and very informative and I really learned a lot from it.could u plz share me some more details.
ReplyDeleteAngularJS training in chennai | AngularJS training in anna nagar | AngularJS training in omr | AngularJS training in porur | AngularJS training in tambaram | AngularJS training in velachery
It's very easy and simple task to build basic applications and do simple customizations, but if one is into this business, then it becomes inevitable to design complex applications with intricate application logic. Salesforce training in Chennai
ReplyDeleteIt is a very helpful data. It will help to improve my knowledge about this topic. Thank you for this awesome post.
ReplyDeletePega Training in Chennai
Pega Course in Chennai
Primavera Training in Chennai
Full Stack Developer Course in Chennai
Corporate Training in Chennai
Đại lý vé máy bay Aivivu, tham khảo
ReplyDeletevé máy bay đi Mỹ bao nhiêu tiền
gia ve may bay tet 2021
giá vé máy bay đi canada bao nhiêu
kinh nghiệm mua vé máy bay giá rẻ đi Pháp
lịch trình bay từ việt nam sang Anh
giá vé máy bay đi Los Angesles
combo đà nẵng 4 ngày 3 đêm 2021
combo đi đà lạt giá rẻ
xin visa trung quốc
dịch vụ cách ly tại khách sạn
Mua vé máy bay tại đại lý Aivivu, tham khảo
ReplyDeletekinh nghiệm mua vé máy bay đi Mỹ giá rẻ
vé máy bay từ mỹ về việt nam hãng ana
vé máy bay khứ hồi từ đức về việt nam
dịch vụ vé máy bay tại nga
I'm going to share with you the exact ten-step process I take companies through when developing their staff to think and act like business owners who make customers want to buy, buy again, and then go on to tell their friends and family to buy! Salesforce interview questions
ReplyDeleteIt’s really amazing to see this blog and its related to what I expected.
ReplyDeleteRobotics Process Automation Training in Chennai
App Development Course in Chennai
Angular 4 Training in Chennai
.Net training in chennai
Ethical Hacking Training in Chennai
Digital Marketing Training Institute in Chennai
Best Car Mechanic in Canning Vale today
ReplyDeleteyoutube abone satın al
ReplyDeletecami avizesi
cami avizeleri
avize cami
no deposit bonus forex 2021
takipçi satın al
takipçi satın al
takipçi satın al
takipcialdim.com/tiktok-takipci-satin-al/
instagram beğeni satın al
instagram beğeni satın al
btcturk
tiktok izlenme satın al
sms onay
youtube izlenme satın al
no deposit bonus forex 2021
tiktok jeton hilesi
tiktok beğeni satın al
binance
takipçi satın al
uc satın al
sms onay
sms onay
tiktok takipçi satın al
tiktok beğeni satın al
twitter takipçi satın al
trend topic satın al
youtube abone satın al
instagram beğeni satın al
tiktok beğeni satın al
twitter takipçi satın al
trend topic satın al
youtube abone satın al
takipcialdim.com/instagram-begeni-satin-al/
perde modelleri
instagram takipçi satın al
instagram takipçi satın al
takipçi satın al
instagram takipçi satın al
betboo
marsbahis
sultanbet
You shared an excellent article with us. This article gives some unique knowledge to us. Keep sharing more posts.
ReplyDeleteBest UPVC Windows and Doors Manufacturer in Chennai | Latest Upvc Doors in Chennai
| Best UPVC Windows in Chennai
You can use this program to evaluate, treat, and measure results. You can visually see how different words and phrases are spoken RoseMedical icSpeech Professional Crack
ReplyDeleteSynthesia Full Version lets you learn and play piano directly from your computer. The program can teach you to play piano with ease. Synthesia Full Version
ReplyDeleteMerry Christmas To The Love Of My Life! Sending special wishes of Christmas cheer to the one I love so dear. I hope your day is as wonderful .Merry Christmas To The Love Of My Life
ReplyDeletebayrampaşa
ReplyDeletegüngören
hakkari
izmit
kumluca
OPTK
yurtdışı kargo
ReplyDeleteresimli magnet
instagram takipçi satın al
yurtdışı kargo
sms onay
dijital kartvizit
dijital kartvizit
https://nobetci-eczane.org/
T7FWN
urfa evden eve nakliyat
ReplyDeletemalatya evden eve nakliyat
burdur evden eve nakliyat
kırıkkale evden eve nakliyat
kars evden eve nakliyat
6M84
düzce evden eve nakliyat
ReplyDeletedenizli evden eve nakliyat
kırşehir evden eve nakliyat
çorum evden eve nakliyat
afyon evden eve nakliyat
TFR
B0232
ReplyDeleteSakarya Şehirler Arası Nakliyat
Bybit Güvenilir mi
Erzurum Lojistik
Antep Lojistik
Rize Parça Eşya Taşıma
Kars Şehir İçi Nakliyat
Bibox Güvenilir mi
Shibanomi Coin Hangi Borsada
Denizli Şehir İçi Nakliyat
92B31
ReplyDeleteÇankaya Parke Ustası
Nevşehir Şehir İçi Nakliyat
Qlc Coin Hangi Borsada
Mersin Evden Eve Nakliyat
Ünye Marangoz
Bee Coin Hangi Borsada
Tekirdağ Lojistik
Btcst Coin Hangi Borsada
Bingöl Şehir İçi Nakliyat
3943C
ReplyDeleteAmasya Lojistik
Ünye Boya Ustası
Ordu Evden Eve Nakliyat
Trabzon Şehir İçi Nakliyat
Referans Kimliği Nedir
Mersin Evden Eve Nakliyat
Gümüşhane Evden Eve Nakliyat
İzmir Lojistik
Bingöl Parça Eşya Taşıma
5060D
ReplyDeleteArtvin Şehirler Arası Nakliyat
order testosterone enanthate
Batman Lojistik
masteron
Poloniex Güvenilir mi
Bursa Lojistik
Ünye Marangoz
Siirt Şehir İçi Nakliyat
Kilis Şehirler Arası Nakliyat
1D691
ReplyDeleteBursa Şehir İçi Nakliyat
Kırklareli Şehirler Arası Nakliyat
Antep Parça Eşya Taşıma
Uşak Lojistik
Ankara Lojistik
Ünye Evden Eve Nakliyat
Muğla Şehir İçi Nakliyat
Bartın Lojistik
Erzincan Evden Eve Nakliyat
970D9
ReplyDeleteresimli magnet
binance referans kodu
referans kimliği nedir
referans kimliği nedir
binance referans kodu
resimli magnet
resimli magnet
binance referans kodu
binance referans kodu
18010
ReplyDeletebinance
bybit
btcturk
kucoin
btcturk
huobi
toptan sabun
referans kodu
bitexen