There are 3 steps to upload a feed via Amazon SP API, the first one is to get feed encryption info via createFeedDocument API. But I am getting Bad Request as response with following content:
{
"errors": [
{
"code": "InvalidInput",
"message": "Invalid Input",
"details": ""
}
]
}
C# code
private async Task<IRestResponse> CreateFeedDocument()
{
IRestRequest restRequest = new RestRequest("feeds/2020-09-04/documents", Method.POST);
restRequest.AddParameter("contentType", "application/xml; charset=UTF-8", ParameterType.RequestBody);
restRequest.AddQueryParameter("MarketplaceIds", "A21TJRUUN4KGV");
restClient = new RestClient(live_url_base);
restRequest = await signRequest(restRequest, restClient);
return restClient.Execute(restRequest);
}
private async Task<IRestRequest> signRequest(IRestRequest restRequest, RestClient restClient)
{
var roleAcccess = await GetAssumeRoleTokenDetail();
restRequest.AddHeader("x-amz-access-token", accessToken);
AWSAuthenticationCredentials AWSCredentials = new AWSAuthenticationCredentials();
AWSCredentials.AccessKeyId = roleAcccess.Credentials.AccessKeyId;
AWSCredentials.SecretKey = roleAcccess.Credentials.SecretAccessKey;
AWSCredentials.Region = region;
restRequest.AddHeader("X-Amz-Security-Token", roleAcccess.Credentials.SessionToken);
return new AWSSigV4Signer(AWSCredentials).Sign(restRequest, restClient.BaseUrl.Host);
}
I doubt that I am not using restRequest.AddParameter properly, but I am not sure.
I have been following below links:
https://github.com/amzn/selling-partner-api-docs/blob/main/references/feeds-api/feeds_2020-09-04.md#createfeeddocument
https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/use-case-guides/feeds-api-use-case-guide/feeds-api-use-case-guide-2020-09-04.md#step-1-create-a-feed-document
How to Encrypt and upload data using selling-partner-api in Amzon using .net
Update
I also tried replacing below line
restRequest.AddParameter("contentType", "application/xml; charset=UTF-8", ParameterType.RequestBody);
with
restRequest.AddJsonBody(new { contentType = "text/xml; charset=UTF-8" });
but then I was getting InvalidSignature error as below:
{
"errors": [
{
"message": "The request signature we calculated does not match the signature you provided. Check your AWS Secret Access Key and signing method. Consult the service documentation for details.
The Canonical String for this request should have been
'POST
/feeds/2020-09-04/documents
host:sellingpartnerapi-eu.amazon.com
x-amz-access-token:Atza|IwEBIA5KgrCsBbSXHmrXFS_FIgBTInh_xPAydLfi5q2P9xaFQf7p8Zl4NjqhHHxqRzUku__Q7GN1p2WQGRzuAoAa8oMkPLx57NJ05SqxEVXXG-fet3_XgKj8uBCU30HaGPsKltf4g2MD8Pqqt2OUrOXtkv4dAAjjCIxC-bFwVqOhvHktAur--NBv-bJaPZ608Av1GEu96GsNEV9eb0saVBwLaZD7NW3oOjzlCc8GPV9hdqHV5TUXY77QZgBLD1y94Vs1fSo54ShpyoMMOZebzbSr1K5gtf3wJZ.........................{ I hid it }...........................................
x-amz-date:20210524T175148Z
x-amz-security-token:FwoGZXIvYXdzEGsaDNUytY0xuP5/u61APiK2ARMZgv4IT+y2HLzdg5FjZOv6aL2bJ3baJPxBtCY2/7ASntTXfAF5s39P3/qspLLQfmqHPZiMGjweCE3Yf3aW5Q1mt+FLT2s2VUwuOawOQwDll51T2HB3wqyaDOSEpsWeR2Iym4TJXE2hbo7q5CQQBXissOo1Oruk5gcAp7uQHpnyuhCRCkfv/ErEpzdDA0JqfhMxdzmViVgsL1Kzalnbcy9lp+ACI4TL70iOl6j6xkyhFexe/aLXKLLPr4UGMi3Ver2CL6Q4kz.........................{ I hid it }...........................................
host;x-amz-access-token;x-amz-date;x-amz-security-token
4d719849acd655844ab5129f5e54a0ed16954c9580c7a9a737504faf42b309e2'
The String-to-Sign should have been
'AWS4-HMAC-SHA256
20210524T175148Z
20210524/eu-west-1/execute-api/aws4_request
a20e7ffe252dbf98d6a4b9213511ac1918f8bbad75ccbfd7ec46f5c9c1457b08'
",
"code": "InvalidSignature"
}
]
}
Note: I have removed some trailing chars of tokens and placed ......{ I hid it }..........
try this one
restRequest.AddJsonBody("{\"contentType\":\"text/tab-separated-values; charset=UTF-8\"}");
RestClient restClient = new RestClient("https://sandbox.sellingpartnerapi-eu.amazon.com/");
IRestRequest restRequest = new RestRequest("/feeds/2021-06-30/documents", Method.POST);
restRequest.AddJsonBody("{\"contentType\":\"text/tab-separated-values; charset=UTF-8\"}");
I do that in my open source library and its work without problem
https://github.com/abuzuhri/Amazon-SP-API-CSharp
Here sample to create and submit feed
ConstructFeedService createDocument = new ConstructFeedService("A3J37AJU4O9RHK", "1.02");
var list = new List<PriceMessage>();
list.Add(new PriceMessage()
{
SKU = "8201031206122...",
StandardPrice = new StandardPrice()
{
currency = BaseCurrencyCode.AED.ToString(),
Value = (201.0522M).ToString("0.00")
}
});
createDocument.AddPriceMessage(list);
var xml = createDocument.GetXML();
var feedID = amazonConnection.Feed.SubmitFeed(xml, FeedType.POST_PRODUCT_PRICING_DATA);
Thread.Sleep(1000*30);
var feedOutput=amazonConnection.Feed.GetFeed(feedID);
var outPut=amazonConnection.Feed.GetFeedDocument(feedOutput.ResultFeedDocumentId);
var reportOutpit = outPut.Url;
private async Task UploadFile(byte[] bytes, string url)
{
var contentType = "text/plain; charset=utf-8"; // this should be the same as what was used in Step #1 (in the CreateFeedDocument API request)
RestClient restClient = new RestClient(url);
IRestRequest restRequest = new RestRequest(Method.PUT);
restRequest.AddParameter(contentType, bytes, ParameterType.RequestBody);
var response = await restClient.ExecuteAsync(restRequest);
if (!response.IsSuccessful)
{
// your error logic
}
// success. Move to Step #3
}
IllegalLocationConstraintExceptionThe unspecified location constraint is incompatible for the region specific endpoint this request was sent to.5B8EGG143CSG45XCi7DqESeN8Q/1QfotMvQIiijcEj/76sr2T+gNh9Ubhq5aQZ7SbZMXCIS/8Mgw6iDod2mCwX/LX6Q=
Related
I'm trying to use Google's TTS to convert a text to speech and I want to use HttpWebRequest for this, as I want to avoid any third-party clients. (This is because I'm practicing calling Web API's.) So I have this code:
HttpWebRequest requestVoices = (HttpWebRequest)WebRequest.Create($"https://texttospeech.googleapis.com/v1/voices?key={bearerKey}");
using StreamReader streamReader = new(requestVoices.GetResponse().GetResponseStream());
var voiceList = GoogleVoices.LoadFromJson(streamReader.ReadToEnd()).Sort();
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Speaking.json"), voiceList.SaveAsJson());
This works fine. I get a list of all voices, ordered by gender, then name. So, being ambitious, I want to generate a sound file, using this configuration:
var sound = new SpeechConfig()
{
Input = new SpeechConfig.InputConfig(){Text = "Hello, World!"},
AudioConfig = new SpeechConfig.AudioSpeechConfig()
{
AudioEncoding = "MP3",
EffectsProfileId = new List<string>(){ "large-home-entertainment-class-device" },
Pitch = 0.0,
SpeakingRate = 1.0
},
Voice = new SpeechConfig.VoiceConfig()
{
Name = "en-IN",
LanguageCode = "en-IN-Wavenet-D"
}
};
File.WriteAllText(Path.Combine(Environment.CurrentDirectory, "Speak.json"), sound.SaveAsJson());
And to check if it generates proper JSON, this is what gets written to that file:
{
"AudioConfig": {
"AudioEncoding": "MP3",
"EffectsProfileId": [
"large-home-entertainment-class-device"
],
"Pitch": 0.0,
"SpeakingRate": 1.0
},
"Input": {
"Text": "Hello, World!"
},
"Voice": {
"LanguageCode": "en-IN-Wavenet-D",
"Name": "en-IN"
}
}
So, that looks good too. So now I need to call the TTS API, using this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://texttospeech.googleapis.com/v1/text:synthesize/");
request.Headers.Add("Authorization", $"Bearer {bearerKey}");
request.Headers.Add("Content-Type", "application/json; charset=utf-8");
request.Method = "POST";
request.ContentType = "application/json";
using (StreamWriter streamWriter = new(request.GetRequestStream()))
{
streamWriter.Write(sound.SaveAsJson());
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string soundFileName= Path.Combine(Environment.CurrentDirectory, "Sound.mp3");
var soundFile = File.Create(soundFileName);
response.GetResponseStream().CopyTo(soundFile);
soundFile.Close();
But nothing gets written and I get the error: Unhandled exception. System.Net.WebException: The remote server returned an error: (401) Unauthorized. at System.Net.HttpWebRequest.GetResponse() at Program.<Main>$(String[] args)...
Now, I know the bearer key is correct as I get a list of voices.
Using Google gives me way too many results, most of which use third-party libraries or talk about the "Translate" API. So that's not very useful. So I used OpenAI (ChatGPT) to give me an example, which wasn't much different, but used this as url: "https://texttospeech.googleapis.com/v1/text:synthesize?key=YOUR_API_KEY&input.text=" + textToSynthesize;
Well, that doesn't work either. So, I tried this as something suggested it:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add("Authorization", "Bearer $(gcloud auth print-access-token)");
request.Headers.Add("X-goog-api-key", $"{bearerKey}");
Still no luck. And there are no restrictions on this API key, except it's less than an hour old. Could it be that I just have to wait longer? Or am I doing something wrong? I must be doing something wrong, I think. I get the list of voices, but not the sound.
What am I doing wrong?
And I'm an idiot! :D This part:
"Voice": {
"LanguageCode": "en-IN-Wavenet-D",
"Name": "en-IN"
}
should be:
"Voice": {
"LanguageCode": "en-IN",
"Name": "en-IN-Wavenet-D"
}
Also, the JSON is case-sensitive...
Working code:
public async Task Speak(string filename, string bearerKey, string text)
{
string url = $"https://texttospeech.googleapis.com/v1/text:synthesize?key={bearerKey}";
var client = new HttpClient();
var context = new StringContent(Sound(text).SaveAsJson(), Encoding.UTF8, "application/json");
using HttpResponseMessage response = await client.PostAsync(url, context);
var result = AudioContent.LoadFromJson(await response.Content.ReadAsStringAsync());
File.WriteAllBytes(filename, System.Convert.FromBase64String(result.Content));
}
And yes, decided to use HttpClient() as it was easier. This method is part of a class that holds the voice data. Sound is created by:
public SpeechConfig Sound(string text) =>
new()
{
Input = new SpeechConfig.InputConfig()
{
Text = text
},
AudioConfig = new SpeechConfig.AudioSpeechConfig()
{
AudioEncoding = "MP3",
EffectsProfileId = new List<string>() { "large-home-entertainment-class-device" },
Pitch = Value.Pitch,
SpeakingRate = Value.SpeakingRate
},
Voice = new SpeechConfig.VoiceConfig()
{
Name = Value.Selection.Name,
LanguageCode = Value.Selection.LanguageCode
}
};
In the same class.
I've just updated my RestSharp application to 107.1.2 and are now unable to send post request.
To test the problem I've set up a small express.js webserver to receive the requests from my C# application. On every post request I made, there is always no body available.
RestClientOptions options = new RestClientOptions("http://127.0.0.1:3000");
RestClient client = new RestClient(options);
RestRequest request = new RestRequest("api/test");
request.AddParameter("test1", "test1");
request.AddParameter("test2", "test2");
request.AddParameter("test3", "test3");
TestResponse response = await client.PostAsync<TestResponse>(request);
The code is based on the QueryString documentation https://restsharp.dev/usage.html#query-string. And yes, the params from the request I receive on the webserver are also empty. To test plain post request, I even tried the following:
RestClientOptions options = new RestClientOptions("http://127.0.0.1:3000");
RestClient client = new RestClient(options);
RestRequest request = new RestRequest("api/test");
const string json = "{ data: { foo: \"bar\" } }";
request.AddStringBody(json, ContentType.Json);
TestResponse response = await client.PostAsync<TestResponse>(request);
I can't find the problem why the requests are sent without an actual post body. In the previous version I've updated from, everything works fine.
Hope you can help me.
Can you please Try this :
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(new { A = "foo", B = "bar" });
or
const string json = "{ data: { foo: \"bar\" } }";
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
RestClientOptions options = new RestClientOptions("http://127.0.0.1:3000");
var client = new RestSharp.RestClient(options);
var request = new RestSharp.RestRequest(RestSharp.Method.POST);
request.RequestFormat = RestSharp.DataFormat.Json;
request.AddHeader("Content-Type", "application/json");
const string json = "{ data: { foo: \"bar\" } }";
request.AddBody(JsonConvert.SerializeObject(json));
var response = client.Execute(request);
Try this please
RestClientOptions options = new RestClientOptions("http://127.0.0.1:3000");
var restClient = new RestClient(options);
var restRequest = new RestRequest(Method.POST)
{
RequestFormat = DataFormat.Json
};
const string json = "{ data: { foo: \"bar\" } }";
request.AddBody(JsonConvert.SerializeObject(json));
var result = restClient.Post<TResponse>(restRequest);
if (!result.IsSuccessful)
{
throw new HttpException($"Item not found: {result.ErrorMessage}");
}
return result.Data;
I am having trouble understanding why do you think the request is made without the body. I would expect that the express API gives you no body, but it doesn't mean the request has no body.
I traced your requests, and you can see them here.
The first snippet produces the following request:
As you can see it has the correct content type and the body is correctly formed as form URL encoded body content.
Your second snippet also produces the correct request with JSON body:
It is impossible to say why your server doesn't understand these requests, as you haven't specified what the server needs, but I don't see any issues with those requests per se.
If you you want to add parameters in the request use below way:
RestClient client = new("http://127.0.0.1:3000");
RestRequest restRequest = new("api/test");
restRequest.AddParameter("test1", "test1");
request.AddParameter("test2", "test2");
request.AddParameter("test3", "test3");
RestResponse response = client.ExecuteAsync(restRequest,Method.Post).Result;
Assert.AreEqual(HttpStatusCode.OK, response);
If you you want to add json body in the request use the below way:
RestClient client = new("http://127.0.0.1:3000");
RestRequest restRequest = new("api/test");
string requestBody= "{\"data\":{\"foo\":\"bar\"}}"
restRequest.AddStringBody(requestBody, DataFormat.Json);
RestResponse response = client.ExecuteAsync(restRequest, Method.Post).Result;
Assert.AreEqual(HttpStatusCode.OK, response);
I'm trying to post an order to PayU payment gateway, using Rest Client tools like post man also I got the same issue.
I'm trying to post using C#, the order created successfully but the response is not as expected, it should be a json object contains the inserted order id and the redirect url , but the current is html response!
C# Code response :
My C# Code using restsharp library :
public IRestResponse<CreateOrderResponseDTO> CreateOrder(CreateOrderDTO orderToCreate)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var actionUrl = "/api/v2_1/orders/";
var client = new RestClient(_baseUrl);
var request = new RestRequest(actionUrl, Method.POST)
{
RequestFormat = DataFormat.Json
};
request.AddJsonBody(orderToCreate);
request.AddHeader("authorization", $"Bearer {_accessToken}");
request.AddHeader("Content-Type", "application/json");
var response = client.Execute<CreateOrderResponseDTO>(request);
if (response.StatusCode == HttpStatusCode.OK)
{
return response;
}
throw new Exception("order not inserted check the data.");
}
My C# Code using built in WebRequest also returns same html :
public string Test(string url, CreateOrderDTO order)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Accept = "application/json";
httpWebRequest.Method = "POST";
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "Bearer " + _accessToken);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
streamWriter.Write(new JavaScriptSerializer().Serialize(order));
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}
Can anyone advise what I missed here ?
In postman, the solution is turning off redirects, like on the image below:
After some tries I found that PayU rest api returns 302 (found) also ResponseUri not OK 200 as expected.
by default rest client automatically redirect to this url so I received the html content of the payment page.
The solution is :
client.FollowRedirects = false;
Hope this useful to anyone.
Also, I would like to add that the above answer by Mohammad is correct as to get the response URL we need to set AllowAutoRedirect to false. I have been trying to implement PayU LatAM WebCheckout in a console app and I was facing similar issue. I got some inspiration from the answer given here: How to get Location header with WebClient after POST request
Based on the answer, I wrote a sample code:
public class NoRedirectWebClient : WebClient
{
protected override WebRequest GetWebRequest(Uri address)
{
var temp = base.GetWebRequest(address) as HttpWebRequest;
temp.AllowAutoRedirect = false;
return temp;
}
}
After creating the above class, I wrote the following code in my Main method:
var request = MakeRequestLocation(new NoRedirectWebClient());
var psi = new ProcessStartInfo("chrome.exe");
psi.Arguments = request.ResponseHeaders["Location"];
Process.Start(psi);
I am now calling the function MakeRequestLocation inside the same class.
private static WebClient MakeRequestLocation(WebClient webClient)
{
var loginUrl = #"https://sandbox.checkout.payulatam.com/ppp-web-gateway-payu/";
NameValueCollection formData = new NameValueCollection
{
{"ApiKey", "4Vj8eK4rloUd272L48hsrarnUA" },
{"merchantId", "508029" },
{"accountId", "512321" },
{"description", "Test PAYU" },
{"referenceCode", "SomeRandomReferenceCode" },
{"amount", "2" },
{"tax", "0" },
{"taxReturnBase", "0" },
{"currency", "USD" },
{"signature", "Signature generated via MD5 sum" },
{"buyerFullName", "test" },
{"buyerEmail", "test#test.com" },
{"responseUrl", #"http://www.test.com/response" },
{"confirmationUrl", #"http://www.test.com/confirmation" }
};
webClient.UploadValues(loginUrl, "POST", formData);
return webClient;
}
The object that is returned by the above function contains a header called location. The value of the location is your required URL for webcheckout.
I am trying to upload an image to the Microsoft custom vision API prediction endpoint using Restsharp, I am trying to use the AddFile method but I am getting a BadRequest as the result, here is the code I am using
public IRestResponse<PredictionResponse> Predict(string imageFileName)
{
var file = new FileInfo(imageFileName);
var serviceUrl = ConfigurationManager.AppSettings["api.custom-vision.prediction.url.file"];
var serviceKey = ConfigurationManager.AppSettings["api.custom-vision.key"];
var client = new RestClient(serviceUrl);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("Prediction-Key", serviceKey);
request.AddFile(file.Name, file.FullName);
var response = client.Execute<PredictionResponse>(request);
return response;
}
When I execute the method I am getting the following response back from the service
{
"code": "BadRequestImageFormat",
"message": "Bad Request Image Format, Uri: 1062fe0480714281abe2daf17beb3ac5"
}
After looking for ways in the restsharp documentation to properly upload a file, I came to the solution that it needs to be passed as parameter with an array of bytes with the parameter type of ParameterType.RequestBody
Here is the example of the method that actually works
public IRestResponse<PredictionResponse> Predict(string imageFileName)
{
var file = new FileInfo(imageFileName);
var serviceUrl = ConfigurationManager.AppSettings["api.custom-vision.prediction.url.file"];
var serviceKey = ConfigurationManager.AppSettings["api.custom-vision.key"];
var client = new RestClient(serviceUrl);
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/octet-stream");
request.AddHeader("Prediction-Key", serviceKey);
request.AddParameter("content", File.ReadAllBytes(file.FullName), ParameterType.RequestBody);
var response = client.Execute<PredictionResponse>(request);
return response;
}
I am having trouble with creating POST JOB (new name for registration of file in OSS for translation). I have already uploaded ZIP file to the bucket (containing 2 revit files, first is root, second is a revitlink) using segment upload, have its URN and now I want to trigger translation to SVF. For this purpose I am using this piece of code (used Restharp, Newtonsoft.Json):
public void CreatePostJOB(string serviceUrl, string urn, string rootFile, string token)
{
try
{
RestClient client = new RestClient(serviceUrl);
RestRequest request = new RestRequest();
request.Method = Method.POST;
request.Resource = "modelderivative/v2/designdata/job";
request.RequestFormat = DataFormat.Json;
request.AddParameter("Authorization", "Bearer " + token, ParameterType.HttpHeader);
request.AddParameter("x-ads-force", true);
request.AddParameter("Content-Type", "application/json");
JObject jsonbody = new JObject
(
new JProperty("input", new JObject
(
new JProperty("urn", urn),
new JProperty("compressedUrn", true),
new JProperty("rootFileName", rootFile)
)),
new JProperty("output", new JObject
(
new JProperty("formats", new JArray
(
new JObject
(
new JProperty("type", "svf"),
new JProperty("views", new JArray("3d", "2d"))
)
))
))
);
string post = jsonbody.ToString(Formatting.Indented);
request.AddParameter("application/json", post, ParameterType.RequestBody);
IRestResponse resp = client.Execute(request);
if (resp.StatusCode == HttpStatusCode.OK)
{
//TODO
}
}
catch (Exception ex)
{
//TODO
}
}
Code above will produce following JSON into post variable:
{
"input": {
"urn": "/*urn base64 string with no padding*/",
"compressedUrn": true,
"rootFileName": "MainModel_A.rvt"
},
"output": {
"formats": [
{
"type": "svf",
"views": [
"3d",
"2d"
]
}
]
}
No matter how I change this code result is always the same:
{"diagnostic":"Request body is not a valid json"}
I also tried to use ordinary C# WebRequest with same result. Maybe there is a bug, because other calls from the same API works with restsharp like a charm. Please how do I create a valid post job in C#?
As mentioned by #XiaodongLiang, use the rootFilename (exactly like this), otherwise will not recognize.
Now your C# code should be (worked on my end):
RestClient client = new RestClient(serviceUrl);
RestRequest request = new RestRequest();
request.Method = Method.POST;
request.Resource = "modelderivative/v2/designdata/job";
request.AddHeader("Accept", "application/json");
request.AddParameter("Authorization", "Bearer " + token, ParameterType.HttpHeader);
request.AddParameter("application/json", jsonbody.ToString(Formatting.None), ParameterType.RequestBody);
IRestResponse resp = client.Execute(request);
if (resp.StatusCode == HttpStatusCode.OK)
{
//TODO
}
And I would suggest you change your app.config with this parameters, which should help you debug your requests (in this case, the headers).
I am not sure if it is case sensitive, but it looks you wrote as 'rootFileName' while the help says 'rootFilename'
I happened to write a blog on such topic yesterday. I also provided a test harness which works well with demo Revit file (with linked file) . If your files are not large, could you give it a check with my test harness (Node.js) in that blog? I have not added resumable uploading, so it is better to test the relatively small files.
http://adndevblog.typepad.com/cloud_and_mobile/2016/07/translate-referenced-files-by-derivative-api.html
If this does not work, could you send me the URN (you can mail me at xiaodong.liang#autodesk.com). I can consult with our team at back-end.
Regards,
Xiaodong Liang
Forge Adovater
Developer Technical Services
Autodesk