Google Login doesn't give me given_name and family_name - windows-runtime

I need to receive user firstname and lastname from Google login.
This is my code:
internal static string GoogleAppId = "XXXXXXXXXXXXX-scvpbtaoijuciinu1oneu7ijqtdvcpce.apps.googleusercontent.com";
internal static string GoogleAppSecret = "XXXXXXXXXXXUJuZNHhf6-8";
internal static Uri GoogleStartUri = new Uri("https://accounts.google.com/o/oauth2/auth?client_id=" + Uri.EscapeDataString(GoogleAppId) + "&redirect_uri=" + Uri.EscapeDataString("urn:ietf:wg:oauth:2.0:oob") + "&response_type=code&scope=" + Uri.EscapeDataString("profile openid https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/plus.me email"));
private string GoogleCallbackUrl = "urn:ietf:wg:oauth:2.0:oob";
internal static Uri GoogleEndUri = new Uri("https://accounts.google.com/o/oauth2/approval?");
public static void AuthenticateAndContinue()
{
StringBuilder googleUrl = new StringBuilder();
googleUrl.Append("https://accounts.google.com/o/oauth2/auth?client_id=");
googleUrl.Append(Uri.EscapeDataString(GoogleAppId));
googleUrl.Append("&scope=openid%20email%20profile");
googleUrl.Append("&redirect_uri=");
googleUrl.Append(Uri.EscapeDataString(GoogleCallbackUrl));
googleUrl.Append("&response_type=code");
Uri startUri = new Uri(googleUrl.ToString());
WebAuthenticationBroker.AuthenticateAndContinue(startUri, GoogleEndUri, null, WebAuthenticationOptions.UseTitle);
}
public static async Task<string> GetToken(string code)
{
var client = new HttpClient();
var auth = await client.PostAsync("https://accounts.google.com/o/oauth2/token", new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("client_id",GoogleAppId),
new KeyValuePair<string, string>("client_secret",GoogleAppSecret),
new KeyValuePair<string, string>("grant_type","authorization_code"),
new KeyValuePair<string, string>("redirect_uri","urn:ietf:wg:oauth:2.0:oob"),
//new KeyValuePair<string, string>("redirect_uri","http://localhost")
}));
var data = await auth.Content.ReadAsStringAsync();
var response = JsonConvert.DeserializeObject<TokenResponse>(data);
System.Diagnostics.Debug.WriteLine(response.id_token);
return response.id_token;
}
internal async void Continue(IContinuationActivatedEventArgs args)
        {
            if (args.Kind == ActivationKind.WebAuthenticationBrokerContinuation)
            {
                var data = ((WebAuthenticationBrokerContinuationEventArgs)args).WebAuthenticationResult.ResponseData.Split('&')[0];
                var code = data.Split('=')[1];
                System.Diagnostics.Debug.WriteLine($"code: {code}");
                var token = await GoogleManager.GetToken(code);
            }
        }
Then i put the token here:
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
I receive a JSON but family_name and given_name are missing:
{
"iss": "accounts.google.com",
"at_hash": "9Nxxxxxxxxxxxxxxx9uBNHA",
"aud": "99655070360-scvpbtaoijuXXXXXXXXXXXXXXXXvcpce.apps.googleusercontent.com",
"sub": "106XXXXXXXXXXXX86619603",
"email_verified": "true",
"azp": "996550XXXXXXXXXXXXXXXijqtdvcpce.apps.googleusercontent.com",
"email": "mymail#mail.it",
"iat": "1473XXXXXXXXXX",
"exp": "14738665XXX",
"alg": "RS256",
"kid": "96bffd2afXXXXXXXXXXXXXXXXXXXXXXXX"
}
What am I doing wrong?

Endpoint you are using is for getting information about token. You should use:
https://www.googleapis.com/oauth2/v3/userinfo?access_token={0}

Related

how to get a specfic value form httpClient response in Razorpages

return await request.Content.ReadAsStringAsync();
This line of code returns me a response from API which is fine but I want a specific object only, how can i do that
using (var _client = new HttpClient())
{
try
{
var gettokenasyn = await GetTokenAsync();
//_client.DefaultRequestHeaders.Clear();
//_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(gettokenasyn);
_client.DefaultRequestHeaders.Add("token", gettokenasyn);
var body = new StringContent(JsonConvert
.SerializeObject(payproModels), Encoding.UTF8, "application/json");
var request = await _client.PostAsync(endPointForOrder, body);
return await request.Content.ReadAsStringAsync();
}
catch (Exception exp)
{
return exp.Message;
}
}
You can parse the json string to a JsonDocument and then access the json properties.
Let's say you have this sample json response and you want to take the speed value:
{
"speed": 4,
"deg": 95,
"gust": 3.27
}
Then you can do:
var response = await _client.PostAsync(endPointForOrder, body);
var stream = await response.Content.ReadAsStreamAsync();
using (var jsonDocument = await JsonDocument.ParseAsync(stream))
{
JsonElement speed = jsonDocument.RootElement.GetProperty("speed");
return speed.GetDouble();
}
Alternative you can create a class and deserialize the json to an instance of that class:
public class Wind
{
public double Speed { get; set; }
public int Deg { get; set; }
public double Gust { get; set; }
}
.
var response = await _client.PostAsync(endPointForOrder, body);
var stream = await response.Content.ReadAsStreamAsync();
var wind = await JsonSerializer.DeserializeAsync<Wind>(stream);
return wind.Speed;
You also need to import System.Text.Json namespace:
using System.Text.Json;
https://learn.microsoft.com/en-us/dotnet/api/system.text.json?view=net-6.0

Signing the Header and Payload with json private key in C#

I have to generate a Client assertion string signing with the json private key.
I have the private key in the private.json file. How do I use the private key in the file to sign the Header and payload?
Except the signing part, I have managed to get the other things to work. Following is the code I use for getting the Signed Client assertion string
public string GetSignedClientAssertion()
{
var header = new Dictionary<string, string>()
{
{ "typ" , "JWT"},
{ "alg", "ES512"},
{ "kid", "TST_Staging" }
};
string token = Encode(Encoding.UTF8.GetBytes(JObject.FromObject(header).ToString())) + "." + Encode(Encoding.UTF8.GetBytes(JObject.FromObject(GetClaims()).ToString()));
var rsa = new RSACryptoServiceProvider();
var filename = System.Web.HttpContext.Current.Server.MapPath("Private.json");
string data = File.ReadAllText(filename);
string key = Encode(Encoding.UTF8.GetBytes(data));
byte[] databyte = File.ReadAllBytes(filename);
//-----I am stuck here on how to sign the token with the Private key from the private.key file
//---the method used for SignData does not work
string signature = SignData(token, data);
signature = Encode(Encoding.UTF8.GetBytes(signature));
return signedClientAssertion = string.Concat(token, ".", signature);
}
Private.json has something like the following
{
"kty": "EC",
"d": "AfJ_hlRFCP0g2PghjghjghjtryrtytyFpbALpoG0gqh9tyaSv8JIZuhKYOgvbAzkI6pi2gdCce3fvWb5csiL24PiS9Ke5CKlh3QyW-YOO",
"use": "sig",
"crv": "P-521",
"kid": "TST_Staging",
"x": "ADRSCG8Acsqj6SlShpEJYa9UhA7ojghjgjK4eUVHj9CDqbH4j2_F84j7qtK4fdH94xGzYqQwV0rLfJrAISknoudPQm743H",
"y": "AYnLkWp3Up69WQoc-kZ8ugvSiCNChMiBra3jLHmSotDdzSJ6MgMCokfRdHsfsF-z4VAGq3zam1Z604_rC5N9xrtyrtyufV",
"alg": "ES512"
}
Can someone point out how to sign the token with the Private key will be much helpful. Thanks.
I have managed to find the solution myself. I am using EC Json public and private keys. Previously I was using the Algorithm ES512 which had some issues while decrypting the JWE response from the server, so I had changed my JWT key algorithm to ES256 and with this encryption and decryption works perfectly with Jose.JWT.
I have been struggling for more than a month to find a solution for the EC Json Public and private key Encryption and Decryption. All the solution available out there was for PEM key method only and nothing much for the Json EC keys. It took me a lot of time find the necessary pieces and put them together and make it work. I am providing the entire code for the page where the encryption and decryption happens, so that someone might find it useful.
using System.Net;
using System.Text; // For class Encoding
using System.IO; // For StreamReader
using System;
using System.Collections.Generic;
using System.Configuration;
using Jose;
using System.Security.Cryptography;
using System.Web;
using Jose.keys;
using Stream = System.IO.Stream;
using System.Web.Script.Serialization;
using Newtonsoft.Json;
public partial class holding : System.Web.UI.Page
{
string ClientID = "mlDBKnXXXXXTYRTYRTYyYdmzFGD6HcBPsHZ2W";
string RemoteURL = "https://www.example.org";
string RemoteTokenAppend = "/token";
string RedirectURL = "https://www.exampleabc.com/holding.aspx";
//-----private key for Encrypting the token
string PrivateKey = #"
{
""x"": ""4kELRTR545GDGDGtvilOLrtr5luaQaWgaTlpqUf7o"",
""y"": ""iCyNdwX73FWKJTjn1Q19gdjEILKjEILK3Y_XwgY3Y_XwgY"",
""d"": ""wiYrwNa5SgBNgdqRtSMpaUvRmipaBJ6hfmL1CUMpwlQ"",
""kty"": ""EC"",
""crv"": ""P-256""
}";
Dictionary<string, object> PrivateKeyHeader = new Dictionary<string, object>
{
{ "typ", "JWT" },
{ "kid", "TST_SERVER" },
{ "alg", "ES256" }
};
//----Public Enc key for Decrypting the JWE token from the remote host
string PublicKey_Enc = #"
{
""x"": ""_ylhMfdVwaRrLx8HL8z7X1ixVkk2rbpwD9oU-uAqyhE"",
""y"": ""aCRo4kY2dTl7wZXjsp2NJyF9Tcmzk1XZN5ueJWNq7Lk"",
""d"": ""Jz9aEpbt_4aKL5FVdCLlux7U-Ubt_4aKL5VdCLLTR2Y"",
""kty"": ""EC"",
""crv"": ""P-256""
}";
public void Page_Load(object sender, EventArgs e)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(RemoteURL + RemoteTokenAppend);
ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
request.ProtocolVersion = HttpVersion.Version10;
var postData = "client_assertion_type=" + HttpUtility.UrlEncode("urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
postData += "&client_id=" + HttpUtility.UrlEncode(ClientID);
postData += "&grant_type=" + HttpUtility.UrlEncode("authorization_code");
postData += "&redirect_uri=" + HttpUtility.UrlEncode(RedirectURL);
postData += "&code=" + HttpUtility.UrlEncode(Request.QueryString["code"]);
postData += "&client_assertion=" + EncryptTokenJose();
var data = Encoding.ASCII.GetBytes(postData);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers.Add("Content-Encoding", "ISO-8859-1");
request.ContentLength = data.Length;
try
{
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var webResponse = (HttpWebResponse)request.GetResponse();
var webStream = webResponse.GetResponseStream();
var responseReader = new StreamReader(webStream);
var response = responseReader.ReadToEnd();
//---Decrypt the Response from Remote
string JoseRes = DecryptTokenJose(response.ToString());
//---close the response reader
responseReader.Close();
Response.Write("<br><br>Payload = " + JoseRes + "<br><br>");
//---Get the json string and values from the decrypted Token
JsonTextReader reader = new JsonTextReader(new StringReader(JoseRes));
var sData = JsonSerializer.CreateDefault().Deserialize<payload>(reader);
//----Sample Payload
//---- Payload = { "sub":"s=S775566X,u=c57acrtereb8-d102-455a-860a-ae7dretef4b8d","aud":"mlDBKnGyYfgdgdmzwx770mqXKb6HcBPsHZ2W","amr":["pwd","swk"],"iss":"https:\/\/www.exampleabc.com","exp":1637810980,"iat":1637810380,"nonce":"TJtv85f586sTgxjUlFm5"}
//----get the sub from Payload
string sub = sData.sub;
Response.Write("<br><br>Sub = " + sub + "<br><br>");
//---Get the list array of sub to extract the IC
string[] subList = sub.Split(',');
//---Get the first item of the array to get the IC
Response.Write("<br><br>NRIC = " + subList[0] + "<br><br>");
//---Retrieved IC value will be s=S775566X, so replace s= to "" to get the exact NRIC value and set the Session value
Session["NRIC"] = subList[0].Replace("s=", "");
//---if Session["RedirctPage"] is set then go to that page
if (Session["RedirctPage"] != null)
Response.Redirect(Session["RedirctPage"].ToString());
else
Response.Redirect("Register_uat.aspx");
}
catch (WebException ex)
{
using (WebResponse response = ex.Response)
{
string ErrorString = "Error from the Server:-----<br><br>";
HttpWebResponse httpResponse = (HttpWebResponse)response;
using (Stream data1 = response.GetResponseStream())
using (var reader = new StreamReader(data1))
{
ErrorString += reader.ReadToEnd();
Response.Write(ErrorString);
}
}
}
}
public string EncryptTokenJose()
{
const uint JwtToAadLifetimeInSeconds = 60 * 2;
DateTime validFrom = DateTime.UtcNow;
long exp = ConvertToTimeT(validFrom + TimeSpan.FromSeconds(JwtToAadLifetimeInSeconds));
long iat = ConvertToTimeT(validFrom);
//---Payload string
string payloadStr = "{\"aud\":\"" + RemoteURL + "\",\"exp\":" + exp.ToString() + ",\"iss\":\"" + ClientID + "\",\"iat\": " + iat.ToString() + ",\"sub\":\"" + ClientID + "\"}";
//---get the Private key to form the public key
JsonTextReader reader = new JsonTextReader(new StringReader(PrivateKey));
var jwk = JsonSerializer.CreateDefault().Deserialize<JWK>(reader);
var publicECCKey = EccKey.New(Base64Url.Decode(jwk.x), Base64Url.Decode(jwk.y), Base64Url.Decode(jwk.d), usage: CngKeyUsages.KeyAgreement);
string token = Jose.JWT.Encode(payloadStr, publicECCKey, JwsAlgorithm.ES256, extraHeaders: PrivateKeyHeader);
return token;
}
public string DecryptTokenJose(string Res)
{
var jss = new JavaScriptSerializer();
string json = Res;
Dictionary<string, string> sData = jss.Deserialize<Dictionary<string, string>>(json);
string AccessToken = sData["access_token"].ToString();
string TokenType = sData["token_type"].ToString();
string IdToken = sData["id_token"].ToString();
Response.Write("<br><br>" + IdToken + "<br><br>");
//---get the Public key Enc to decrypt the JWE token
JsonTextReader reader = new JsonTextReader(new StringReader(PublicKey_Enc));
var jwk = JsonSerializer.CreateDefault().Deserialize<JWK>(reader);
var publicECCKey = EccKey.New(Base64Url.Decode(jwk.x), Base64Url.Decode(jwk.y), Base64Url.Decode(jwk.d), usage: CngKeyUsages.KeyAgreement);
//---get the decrypted token
string token = Jose.JWT.Decode(IdToken, publicECCKey, JweAlgorithm.ECDH_ES_A128KW, JweEncryption.A256CBC_HS512);
//----todo: Verify the signature of the decoded JWS token
//----5 parts token with dot(.) as separator
string[] toklist = token.Split('.');
//----get the 2nd item of the list which will have the Payload with User IC details
string Payload = toklist[1];
//----decode the payload to bytes and from bytes to readable string
var base64EncodedBytes = Base64Url.Decode(Payload);
return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
}
public static long ConvertToTimeT(DateTime dt)
{
return (long)(dt - new DateTime(1970, 1, 1, 0, 0, 0, 0)).TotalSeconds;
}
public class payload
{
public string sub { get; set; }
public string aud { get; set; }
public string iss { get; set; }
public string exp { get; set; }
public string iat { get; set; }
}
public class JWK
{
public string x { get; set; }
public string y { get; set; }
public string d { get; set; }
}
}

http://localhost:3000/api/forge/designautomation/workitems 500 (Internal Server Error) jquery.min.js:2 POST

I am trying out the step by step tutorial of design-automation in Revit, to modify-your-models from learn.autodesk.io . This code worked perfectly fine even a few days back but today I am suddenly facing this error. I tried recreating the entire project sample once again as per the tutorial but this error is not going away. Can anyone explain what is causing it?
The error log:
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HM7HP2HS8PF1", Request id "0HM7HP2HS8PF1:00000002": An unhandled exception was thrown by the application.
Autodesk.Forge.Client.ApiException: Error calling UploadObject: Error while copying content to a stream. Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host..
at Autodesk.Forge.ObjectsApi.UploadObjectAsyncWithHttpInfo(String bucketKey, String objectName, Nullable`1 contentLength, Stream body, String contentDisposition, String ifMatch, String contentType)
at Autodesk.Forge.ObjectsApi.UploadObjectAsync(String bucketKey, String objectName, Nullable`1 contentLength, Stream body, String contentDisposition, String ifMatch, String contentType)
at forgeSample.Controllers.DesignAutomationController.StartWorkitem(StartWorkitemInput input) in E:\Test-2nd_Attempt\forgeSample\Controllers\DesignAutomationController.cs:line 275
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Builder.RouterMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
DesignAutomationController.cs
using Autodesk.Forge;
using Autodesk.Forge.DesignAutomation;
using Autodesk.Forge.DesignAutomation.Model;
using Autodesk.Forge.Model;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RestSharp;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Activity = Autodesk.Forge.DesignAutomation.Model.Activity;
using Alias = Autodesk.Forge.DesignAutomation.Model.Alias;
using AppBundle = Autodesk.Forge.DesignAutomation.Model.AppBundle;
using Parameter = Autodesk.Forge.DesignAutomation.Model.Parameter;
using WorkItem = Autodesk.Forge.DesignAutomation.Model.WorkItem;
using WorkItemStatus = Autodesk.Forge.DesignAutomation.Model.WorkItemStatus;
namespace forgeSample.Controllers {
[ApiController]
public class DesignAutomationController: ControllerBase {
// Used to access the application folder (temp location for files & bundles)
private IWebHostEnvironment _env;
// used to access the SignalR Hub
private IHubContext < DesignAutomationHub > _hubContext;
// Local folder for bundles
public string LocalBundlesFolder {
get {
return Path.Combine(_env.WebRootPath, "bundles");
}
}
/// Prefix for AppBundles and Activities
public static string NickName {
get {
return OAuthController.GetAppSetting("FORGE_CLIENT_ID");
}
}
/// Alias for the app (e.g. DEV, STG, PROD). This value may come from an environment variable
public static string Alias {
get {
return "dev";
}
}
// Design Automation v3 API
DesignAutomationClient _designAutomation;
// Constructor, where env and hubContext are specified
public DesignAutomationController(IWebHostEnvironment env, IHubContext < DesignAutomationHub > hubContext, DesignAutomationClient api) {
_designAutomation = api;
_env = env;
_hubContext = hubContext;
}
// **********************************
//
/// <summary>
/// Names of app bundles on this project
/// </summary>
[HttpGet]
[Route("api/appbundles")]
public string[] GetLocalBundles() {
// this folder is placed under the public folder, which may expose the bundles
// but it was defined this way so it be published on most hosts easily
return Directory.GetFiles(LocalBundlesFolder, "*.zip").Select(Path.GetFileNameWithoutExtension).ToArray();
}
/// <summary>
/// Return a list of available engines
/// </summary>
[HttpGet]
[Route("api/forge/designautomation/engines")]
public async Task < List < string >> GetAvailableEngines() {
dynamic oauth = await OAuthController.GetInternalAsync();
// define Engines API
Page < string > engines = await _designAutomation.GetEnginesAsync();
engines.Data.Sort();
return engines.Data; // return list of engines
}
/// <summary>
/// Define a new appbundle
/// </summary>
[HttpPost]
[Route("api/forge/designautomation/appbundles")]
public async Task < IActionResult > CreateAppBundle([FromBody] JObject appBundleSpecs) {
// basic input validation
string zipFileName = appBundleSpecs["zipFileName"].Value < string > ();
string engineName = appBundleSpecs["engine"].Value < string > ();
// standard name for this sample
string appBundleName = zipFileName + "AppBundle";
// check if ZIP with bundle is here
string packageZipPath = Path.Combine(LocalBundlesFolder, zipFileName + ".zip");
if (!System.IO.File.Exists(packageZipPath)) throw new Exception("Appbundle not found at " + packageZipPath);
// get defined app bundles
Page < string > appBundles = await _designAutomation.GetAppBundlesAsync();
// check if app bundle is already define
dynamic newAppVersion;
string qualifiedAppBundleId = string.Format("{0}.{1}+{2}", NickName, appBundleName, Alias);
if (!appBundles.Data.Contains(qualifiedAppBundleId)) {
// create an appbundle (version 1)
AppBundle appBundleSpec = new AppBundle() {
Package = appBundleName,
Engine = engineName,
Id = appBundleName,
Description = string.Format("Description for {0}", appBundleName),
};
newAppVersion = await _designAutomation.CreateAppBundleAsync(appBundleSpec);
if (newAppVersion == null) throw new Exception("Cannot create new app");
// create alias pointing to v1
Alias aliasSpec = new Alias() {
Id = Alias, Version = 1
};
Alias newAlias = await _designAutomation.CreateAppBundleAliasAsync(appBundleName, aliasSpec);
} else {
// create new version
AppBundle appBundleSpec = new AppBundle() {
Engine = engineName,
Description = appBundleName
};
newAppVersion = await _designAutomation.CreateAppBundleVersionAsync(appBundleName, appBundleSpec);
if (newAppVersion == null) throw new Exception("Cannot create new version");
// update alias pointing to v+1
AliasPatch aliasSpec = new AliasPatch() {
Version = newAppVersion.Version
};
Alias newAlias = await _designAutomation.ModifyAppBundleAliasAsync(appBundleName, Alias, aliasSpec);
}
// upload the zip with .bundle
RestClient uploadClient = new RestClient(newAppVersion.UploadParameters.EndpointURL);
RestRequest request = new RestRequest(string.Empty, Method.POST);
request.AlwaysMultipartFormData = true;
foreach(KeyValuePair < string, string > x in newAppVersion.UploadParameters.FormData) request.AddParameter(x.Key, x.Value);
request.AddFile("file", packageZipPath);
request.AddHeader("Cache-Control", "no-cache");
await uploadClient.ExecuteAsync(request);
return Ok(new {
AppBundle = qualifiedAppBundleId, Version = newAppVersion.Version
});
}
/// <summary>
/// Helps identify the engine
/// </summary>
private dynamic EngineAttributes(string engine) {
if (engine.Contains("3dsMax")) return new {
commandLine = "$(engine.path)\\3dsmaxbatch.exe -sceneFile \"$(args[inputFile].path)\" $(settings[script].path)", extension = "max", script = "da = dotNetClass(\"Autodesk.Forge.Sample.DesignAutomation.Max.RuntimeExecute\")\nda.ModifyWindowWidthHeight()\n"
};
if (engine.Contains("AutoCAD")) return new {
commandLine = "$(engine.path)\\accoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\" /s $(settings[script].path)", extension = "dwg", script = "UpdateParam\n"
};
if (engine.Contains("Inventor")) return new {
commandLine = "$(engine.path)\\inventorcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "ipt", script = string.Empty
};
if (engine.Contains("Revit")) return new {
commandLine = "$(engine.path)\\revitcoreconsole.exe /i \"$(args[inputFile].path)\" /al \"$(appbundles[{0}].path)\"", extension = "rvt", script = string.Empty
};
throw new Exception("Invalid engine");
}
/// <summary>
/// Define a new activity
/// </summary>
[HttpPost]
[Route("api/forge/designautomation/activities")]
public async Task < IActionResult > CreateActivity([FromBody] JObject activitySpecs) {
// basic input validation
string zipFileName = activitySpecs["zipFileName"].Value < string > ();
string engineName = activitySpecs["engine"].Value < string > ();
// standard name for this sample
string appBundleName = zipFileName + "AppBundle";
string activityName = zipFileName + "Activity";
//
Page < string > activities = await _designAutomation.GetActivitiesAsync();
string qualifiedActivityId = string.Format("{0}.{1}+{2}", NickName, activityName, Alias);
if (!activities.Data.Contains(qualifiedActivityId)) {
// define the activity
// ToDo: parametrize for different engines...
dynamic engineAttributes = EngineAttributes(engineName);
string commandLine = string.Format(engineAttributes.commandLine, appBundleName);
Activity activitySpec = new Activity() {
Id = activityName,
Appbundles = new List < string > () {
string.Format("{0}.{1}+{2}", NickName, appBundleName, Alias)
},
CommandLine = new List < string > () {
commandLine
},
Engine = engineName,
Parameters = new Dictionary < string, Parameter > () {
{
"inputFile",
new Parameter() {
Description = "input file", LocalName = "$(inputFile)", Ondemand = false, Required = true, Verb = Verb.Get, Zip = false
}
}, {
"inputJson",
new Parameter() {
Description = "input json", LocalName = "params.json", Ondemand = false, Required = false, Verb = Verb.Get, Zip = false
}
}, {
"outputFile",
new Parameter() {
Description = "output file", LocalName = "outputFile." + engineAttributes.extension, Ondemand = false, Required = true, Verb = Verb.Put, Zip = false
}
}
},
Settings = new Dictionary < string, ISetting > () {
{
"script",
new StringSetting() {
Value = engineAttributes.script
}
}
}
};
Activity newActivity = await _designAutomation.CreateActivityAsync(activitySpec);
// specify the alias for this Activity
Alias aliasSpec = new Alias() {
Id = Alias, Version = 1
};
Alias newAlias = await _designAutomation.CreateActivityAliasAsync(activityName, aliasSpec);
return Ok(new {
Activity = qualifiedActivityId
});
}
// as this activity points to a AppBundle "dev" alias (which points to the last version of the bundle),
// there is no need to update it (for this sample), but this may be extended for different contexts
return Ok(new {
Activity = "Activity already defined"
});
}
/// <summary>
/// Get all Activities defined for this account
/// </summary>
[HttpGet]
[Route("api/forge/designautomation/activities")]
public async Task < List < string >> GetDefinedActivities() {
// filter list of
Page < string > activities = await _designAutomation.GetActivitiesAsync();
List < string > definedActivities = new List < string > ();
foreach(string activity in activities.Data)
if (activity.StartsWith(NickName) && activity.IndexOf("$LATEST") == -1)
definedActivities.Add(activity.Replace(NickName + ".", String.Empty));
return definedActivities;
}
/// <summary>
/// Start a new workitem
/// </summary>
[HttpPost]
[Route("api/forge/designautomation/workitems")]
public async Task < IActionResult > StartWorkitem([FromForm] StartWorkitemInput input) {
// basic input validation
JObject workItemData = JObject.Parse(input.data);
string widthParam = workItemData["width"].Value < string > ();
string heigthParam = workItemData["height"].Value < string > ();
string activityName = string.Format("{0}.{1}", NickName, workItemData["activityName"].Value < string > ());
string browerConnectionId = workItemData["browerConnectionId"].Value < string > ();
// save the file on the server
var fileSavePath = Path.Combine(_env.ContentRootPath, Path.GetFileName(input.inputFile.FileName));
using(var stream = new FileStream(fileSavePath, FileMode.Create)) await input.inputFile.CopyToAsync(stream);
// OAuth token
dynamic oauth = await OAuthController.GetInternalAsync();
// upload file to OSS Bucket
// 1. ensure bucket existis
string bucketKey = NickName.ToLower() + "-designautomation";
BucketsApi buckets = new BucketsApi();
buckets.Configuration.AccessToken = oauth.access_token;
try {
PostBucketsPayload bucketPayload = new PostBucketsPayload(bucketKey, null, PostBucketsPayload.PolicyKeyEnum.Transient);
await buckets.CreateBucketAsync(bucketPayload, "US");
} catch {}; // in case bucket already exists
// 2. upload inputFile
string inputFileNameOSS = string.Format("{0}_input_{1}", DateTime.Now.ToString("yyyyMMddhhmmss"), Path.GetFileName(input.inputFile.FileName)); // avoid overriding
ObjectsApi objects = new ObjectsApi();
objects.Configuration.AccessToken = oauth.access_token;
using(StreamReader streamReader = new StreamReader(fileSavePath))
await objects.UploadObjectAsync(bucketKey, inputFileNameOSS, (int) streamReader.BaseStream.Length, streamReader.BaseStream, "application/octet-stream");
System.IO.File.Delete(fileSavePath); // delete server copy
// prepare workitem arguments
// 1. input file
XrefTreeArgument inputFileArgument = new XrefTreeArgument() {
Url = string.Format("https://developer.api.autodesk.com/oss/v2/buckets/{0}/objects/{1}", bucketKey, inputFileNameOSS),
Headers = new Dictionary < string, string > () {
{
"Authorization",
"Bearer " + oauth.access_token
}
}
};
// 2. input json
dynamic inputJson = new JObject();
inputJson.Width = widthParam;
inputJson.Height = heigthParam;
XrefTreeArgument inputJsonArgument = new XrefTreeArgument() {
Url = "data:application/json, " + ((JObject) inputJson).ToString(Formatting.None).Replace("\"", "'")
};
// 3. output file
string outputFileNameOSS = string.Format("{0}_output_{1}", DateTime.Now.ToString("yyyyMMddhhmmss"), Path.GetFileName(input.inputFile.FileName)); // avoid overriding
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}&outputFileName={2}", OAuthController.GetAppSetting("FORGE_WEBHOOK_URL"), browerConnectionId, outputFileNameOSS);
WorkItem workItemSpec = new WorkItem() {
ActivityId = activityName,
Arguments = new Dictionary < string, IArgument > () {
{
"inputFile",
inputFileArgument
}, {
"inputJson",
inputJsonArgument
}, {
"outputFile",
outputFileArgument
}, {
"onComplete",
new XrefTreeArgument {
Verb = Verb.Post, Url = callbackUrl
}
}
}
};
WorkItemStatus workItemStatus = await _designAutomation.CreateWorkItemAsync(workItemSpec);
return Ok(new {
WorkItemId = workItemStatus.Id
});
}
/// <summary>
/// Input for StartWorkitem
/// </summary>
public class StartWorkitemInput {
public IFormFile inputFile {
get;
set;
}
public string data {
get;
set;
}
}
/// <summary>
/// Callback from Design Automation Workitem (onProgress or onComplete)
/// </summary>
[HttpPost]
[Route("/api/forge/callback/designautomation")]
public async Task < IActionResult > OnCallback(string id, string outputFileName, [FromBody] dynamic body) {
try {
// your webhook should return immediately! we can use Hangfire to schedule a job
JObject bodyJson = JObject.Parse((string) body.ToString());
await _hubContext.Clients.Client(id).SendAsync("onComplete", bodyJson.ToString());
var client = new RestClient(bodyJson["reportUrl"].Value < string > ());
var request = new RestRequest(string.Empty);
// send the result output log to the client
byte[] bs = client.DownloadData(request);
string report = System.Text.Encoding.Default.GetString(bs);
await _hubContext.Clients.Client(id).SendAsync("onComplete", report);
// generate a signed URL to download the result file and send to the client
ObjectsApi objectsApi = new ObjectsApi();
dynamic signedUrl = await objectsApi.CreateSignedResourceAsyncWithHttpInfo(NickName.ToLower() + "-designautomation", outputFileName, new PostBucketsSigned(10), "read");
await _hubContext.Clients.Client(id).SendAsync("downloadResult", (string)(signedUrl.Data.signedUrl));
} catch {}
// ALWAYS return ok (200)
return Ok();
}
/// <summary>
/// Clear the accounts (for debugging purpouses)
/// </summary>
[HttpDelete]
[Route("api/forge/designautomation/account")]
public async Task < IActionResult > ClearAccount() {
// clear account
await _designAutomation.DeleteForgeAppAsync("me");
return Ok();
}
}
/// <summary>
/// Class uses for SignalR
/// </summary>
public class DesignAutomationHub: Microsoft.AspNetCore.SignalR.Hub {
public string GetConnectionId() {
return Context.ConnectionId;
}
}
}
This error is from a [Storage API][1]. I can imagine that it may had a temporary issue. Can you retry to see if it works now?

Correct JSON structure using RestSharp

What is the Correct format for sending JSON using RestSharp:
Example PUT JSON:
{
"properties": [
{
"name": "description",
"value": "A far better description than before"
}
]
}
In C# how to correctly send, I'm attempting with:
request.AddJsonBody(new
{
properties = new[]
{
new{property="name",value="about_us"},
new{property="value",value="My description"}
}
});
Below is the full code:
private void UpdateCompanyProperty(string companyId)
{
var hapikey = "{YOUR_HAPI_KEY_HERE}";
var client = new RestClient("https://api.hubapi.com/");
var request = new RestRequest("companies/v2/companies/{companyId}", Method.PUT);
request.AddUrlSegment("companyId", companyId);
request.AddQueryParameter("hapikey", hapikey);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(new
{
properties = new[]
{
new{property="name",value="about_us"},
new{property="value",value="My description"}
}
});
IRestResponse response = client.Execute(request);
JObject jObject = JObject.Parse(response.Content);
JToken jvid = jObject["portalId"];
Debug.WriteLine(jvid);
}
No errors but not updating or returning values.
Try my answer here:
https://stackoverflow.com/a/57281157/5478655
request.RequestFormat = DataFormat.Json; // Important
var input = new Dictionary<string, object>();
// props could be an array or real objects too of course
var props = new[]
{
new{property="name",value="about_us"},
new{property="value",value="My description"}
};
input.Add("properties", props);
request.AddBody(input);
Create a class and give it any name
class MyClass
{
public string property {get;set;}
private string value {get;set;}
}
Define your class as an object
List<MyClass> list = new List<MyClass>
{
new MyClass() { property = "name", value = "about_us"},
new MyClass() { property = "value", value = "My Description"},
};
Now using Newtonsoft.Json serialize your object
string result = JsonConvert.SerializeObject(list);
Now add it to an array
var resArray = new object[] { result };
Find your modified code below
class MyClass
{
public string property {get;set;}
private string value {get;set;}
}
using Newtonsoft.Json;
using RestSharp;
private void UpdateCompanyProperty(string companyId)
{
List<MyClass> list = new List<MyClass>
{
new MyClass() { property = "name", value = "about_us"},
new MyClass() { property = "value", value = "My Description"},
};
string result = JsonConvert.SerializeObject(list);
var hapikey = "{YOUR_HAPI_KEY_HERE}";
var client = new RestClient("https://api.hubapi.com/");
var request = new RestRequest("companies/v2/companies/{companyId}", Method.PUT);
request.AddUrlSegment("companyId", companyId);
request.AddQueryParameter("hapikey", hapikey);
request.RequestFormat = DataFormat.Json;
request.AddJsonBody(new
{
properties =result
});
IRestResponse response = client.Execute(request);
JObject jObject = JObject.Parse(response.Content);
JToken jvid = jObject["portalId"];
Debug.WriteLine(jvid);
}

How to perform POST operation on Windows Phone 8.1

I am struggling to successfully implement a POST operation within Windows Phone 8.1.
PostMessage method executes without any exceptions being caught.
However, the POST method within MessagesController never gets invoked.
How do I perform a POST for Windows Phone 8.1?
The code is below:
internal async Task PostMessage(string text)
{
Globals.MemberId = 1;
int memberId = 2;
// server to POST to
string url = #"http://localhost:17634/api/messages";
try
{
// HTTP web request
var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
httpWebRequest.ContentType = "text/plain; charset=utf-8";
httpWebRequest.Method = "POST";
// Write the request Asynchronously
using (var stream = await Task.Factory.FromAsync<Stream>(httpWebRequest.BeginGetRequestStream,
httpWebRequest.EndGetRequestStream, null))
{
//create some json string
var message = new Message() { FromId = Globals.MemberId, ToId = memberId, Content = text, Timestamp = DateTime.Now };
var json = string.Format("{0}{1}", "action=", JsonConvert.SerializeObject(message));
// convert json to byte array
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(json);
// Write the bytes to the stream
await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
}
catch(Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
public class MessagesController : ApiController
{
public HttpResponseMessage Post(Message message)
{
throw new NotImplementedException();
}
}
public class Message
{
public int MessageId { get; set; }
public int FromId { get; set; }
public int ToId { get; set; }
public DateTime Timestamp { get; set; }
public string Content { get; set; }
}
The following link resolved my issue.
The updated client is as follows:
using (var client = new System.Net.Http.HttpClient())
{
// New code:
client.BaseAddress = new Uri(Globals.URL_PREFIX);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var message = new Message() { MessageId = 0, FromId = Globals.MemberId, ToId = memberId, Content = text, Timestamp = DateTime.Now };
var json_object = JsonConvert.SerializeObject(message);
var response = await client.PostAsync("api/messages", new StringContent(json_object.ToString(), Encoding.UTF8, "application/json"));
Debug.Assert(response.StatusCode == System.Net.HttpStatusCode.Accepted);
}
This works fine for me. The function accepts an payload of type T. The server accepts a JSON object and returns a JSON response.
public async static Task SendRequestPacket<T>(object payload)
{
Uri theUri = new Uri("the_uri");
//Create an Http client and set the headers we want
HttpClient aClient = new HttpClient();
aClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
aClient.DefaultRequestHeaders.Host = theUri.Host;
//Create a Json Serializer for our type
DataContractJsonSerializer jsonSer = new DataContractJsonSerializer(typeof(T));
// use the serializer to write the object to a MemoryStream
MemoryStream ms = new MemoryStream();
jsonSer.WriteObject(ms, payload);
ms.Position = 0;
//use a Stream reader to construct the StringContent (Json)
StreamReader sr = new StreamReader(ms);
StringContent theContent = new StringContent(sr.ReadToEnd(), Encoding.UTF8, "application/json");
//Post the data
HttpResponseMessage aResponse = await aClient.PostAsync(theUri, theContent);
if (aResponse.IsSuccessStatusCode)
{
string content = await aResponse.Content.ReadAsStringAsync();
System.Diagnostics.Debug.WriteLine(content);
}
else
{
// show the response status code
}
}
Just dont use HttpWebRequest if you are not forced to in any way.
This example is using HttpClient() and it is good to always have the client created once and not every time you make a request.
So in your class add:
private static HttpClient _client;
public static Uri ServerBaseUri
{
get { return new Uri("http://localhost:17634/api"); }
}
public ClassConstructor()
{
_client = new HttpClient();
}
internal async Task<ResponseType> PostMessage(string text)
{
Globals.MemberId = 1;
int memberId = 2;
try
{
var js = "{ JSON_OBJECT }";
var json = new StringContent(js);
json.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var response = await Client.PostAsync(new Uri(ServerBaseUri, "/messages"), json);
var reply = await response.Content.ReadAsStringAsync();
} catch (Exception)
{
return null;
}
}
More on HttpClient.