28 Aug 2020

Design Automation and Azure Function as Service

Azure-Function-Design-Automation

There is a frequent request if it is possible to directly parse the results of Design Automation jobs to a JSON file, without ever downloading the output JSON file.

The general way is to pass an output URL with a PUT request, for which our DA service will upload the output file to a given URL.

Activity Parameter:

{
  "commandLine": [
    "$(engine.path)\\accoreconsole.exe /i $(args[HostDwg].path) /al $(appbundles[forgeExtractLength].path) /s $(settings[script].path)"
  ],
  "parameters": {
    "HostDwg": {
      "verb": "get",
      "required": true,
      "localName": "square.dwg"
    },
    "Result": {
      "verb": "put",
      "required": true,
      "localName": "result.json"
    }
  },
  "id": "mx.extractlengths+prod",
  "engine": "Autodesk.AutoCAD+24",
  "appbundles": [
    "mx.forgeExtractLength+prod"
  ],
  "settings": {
    "script": {
      "value": "ComputeLength\n"
    }
  },
  "version": 3
}

Sample Workitem

{
   "activityId":"mx.extractlengths+prod",
   "arguments":{
      "HostDwg":{
         "url":"https://fpd-uploads.s3.us-west-2.amazonaws.com/square.dwg",
         "headers":null,
         "verb":"get"
      },
      "Result":{
         "url":"https://developer.api.autodesk.com/oss/v2/buckets/results/objects/Result.json",
         "headers":{
            "Authorization":"Bearer {{ oAuthToken}}",
            "Content-type":"application/octet-stream"
         },
         "verb":"put"
      }
   }
}

It is possible to POST the result JSON to output URL, provided if the output URL is your server’s endpoint, you can parse the JSON from the endpoint’s request.

 

We can also leverage the concept of Serverless functionalities with Design Automation for listening to event triggers, to simulate the working of POST result JSON to the endpoint, we will use Azure Functions. Azure Functions is a serverless compute service that lets you run event-triggered code without having to explicitly provision or manage infrastructure.

 

New Activity Spec:

{
   "commandLine":[
       "$(engine.path)\\accoreconsole.exe /i $(args[HostDwg].path) /al $(appbundles[forgeExtractLength].path) /s $(settings[script].path)" 
  ],
   "parameters":{
       "HostDwg":{
           "verb":"get",
           "required":true,
           "localName":"square.dwg"   
    },
       "Result":{
           "verb":"post",
           "required":true,
           "localName":"result.json"   
    } 
  },
   "id":"mx.extractlengths+prod",
   "engine":"Autodesk.AutoCAD+24",
   "appbundles":[
       "mx.forgeExtractLength+prod" 
  ],
   "settings":{
       "script":{
           "value":"ComputeLength\n"   
    } 
  },
   "version":3
}

 

New Workitem Spec

{
	"activityId": "mx.extractlengths+prod",
	"arguments": {
		"HostDwg": {
			"url": "https://fpd-uploads.s3.us-west-2.amazonaws.com/square.dwg",
			"headers": null,
			"verb": "get"
		},
		"Result": {
			"url": "https://azfunc-da-oauth.azurewebsites.net/api/PutResultJson/$(workitem.id)",


			"verb": "post"
		}
	}
}

A Variable Expansion $(workitem.id) could be used in the payload, this will be resolved to the workitem id.

 

For example:

 

https://azfunc-da-oauth.azurewebsites.net/api/PutResultJson/$(workitem.id)

, will become

https://azfunc-da-oauth.azurewebsites.netapi/PutResultJson/d74527d72351488d9f6058f5ab5012bf

 

Azure Function to Post JSON from Design Automation.

 

 public class Extracted
    {
        public static  string Data { get; set; }
    }
    public static class PutJson
    {
        [FunctionName("PutResultJson")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "PutResultJson/{Id}")] HttpRequest req, string Id,
            ILogger log)
        {
            log.LogInformation($"C# HTTP trigger function processed a request.{Id}");        

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            HttpResponseMessage response = new HttpResponseMessage()
            {
               StatusCode = System.Net.HttpStatusCode.OK
            };
            log.LogInformation($"Read Json:\n\t:{data.ToString()}");
            Extracted.Data = data.ToString();
            return new OkObjectResult(response);
        }
    }

 

Azure Function to Fetch JSON

public static class FetchJson
    {
        [FunctionName("FetchJson")]
        public static IActionResult Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "FetchJson")] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            return new OkObjectResult(Extracted.Data);
        }
    }

Code

MadhukarMoogala/da-azfunc

Working Demo

Related Article