Skip to main content

.NET (C# / VBA.NET): arupcompute-connect-dotnet

tip

There is no project charging for use of ArupCompute, however project usage data is critical to justifying continued funding of ArupCompute - please provide a job number!

To contribute and / or submit bug reports go to the arupcompute-connect-dotnet github.

NOTE

You will require access to the Arup GitHub account to see the above link. If you are having trouble reach out on the ArupCompute teams.

You can join the teams using the code b53lq6l

Installation

You can reference the arupcompute-connect-dotnet library using NuGet, dotnet, or Visual Studio.

Dotnet

As arupcompute-connect-dotnet is hosted on a private feed you will need to install the Azure Artifacts Credential Provider.

Also ensure that you visit this webpage to ensure that you have access to the repository where the reference libraries are stored (enter Arup login details if prompted).

Project setup

Add a nuget.config file to your project, in the same folder as your .csproj or .sln file

<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<add key="arupcomputedevops@Release" value="https://pkgs.dev.azure.com/arupcomputedevops/_packaging/arupcomputedevops/nuget/v3/index.json" />
</packageSources>
</configuration>

Add references

Use the dotnet add package --interactive command (using the interactive flag, which allows the credential manager to prompt you for credentials):

dotnet add [<PROJECT>] package --interactive arupcompute-connect-dotnet

The three packages you will need to add to your solution are:

  • arupcompute-connect-dotnet
  • Arup.Compute.Models
  • Arup.Compute.DotNetSdk

Restore packages

If prompted to restore packages you may need to use the --interactive flag:

dotnet restore --interactive

Simple example

using Arup.Compute.Connect;
using Arup.Compute.Models;
using Arup.Compute.DotNetSdk;
using System.Threading.Tasks;
Connection connection = new Connection("00000-00"); // The job number will _not_ be charged
int calcId = 11416564; // Sample Library - Basic calculation

Dictionary<string, object> inputs = new Dictionary<string, object>()
{
{ "a", 1 },
{ "b", 2}
};

Task<CalcRecord> resultTask = Call.ExecuteCalculationAsync(connection, calcId, false, inputs);

CalcRecord calcRecord = resultTask.Result;

If you are interacting with a library that utilises the expanded features of ArupCompute (e.g. report writing, errors, warnings, remarks etc.) such as DesignCheck2 you will need the additional step below to interpret the .Result:

Task<CalcRecord> resultTask = Call.ExecuteCalculationAsync(connection, calcId, false, inputs, resultType: Arup.Compute.Connect.Call.ResultType.Simple); // Simple provides reports, errors etc. default is mini which just returns results
CalcRecord result = resultTask.Result;
ArupComputeResult acr = result.ParseOutput<Arup.Compute.DotNetSdk.ArupComputeResult>();

// For example if you want access to the plain-text report
string report = acr.ArupComputeReport;

If you are utilising the batch execution feature of ArupCompute and want access to reports etc. you will need to do the following:

///Call.ExecuteBatchCalculationAsync(...)
var lacr = result.ParseOutput<List<Arup.Compute.DotNetSdk.ArupComputeResult>>();

Connection object

The Connection class is one of the most important parts of the Dotnet ArupCompute client. It controls all authentication and most settings related to the client. It is a required input in most other functions related to ArupCompute.

This object also controls when to use AC Local.

Older authentication methods

The Connection object also replaces the old authentication methods. If you are working on an older Dotnet project that has not yet updated to use the Connection object then you should perform this upgrade as older authentication methods may stop working.

Constructor properties

NameDescriptionDefault
string jobNumberThe Job Number this call is associated with. This is for usage tracking purposes only and will not result in any charges to the jobN/A
Connect.ConfigMode ModeThe "Mode" that Connect will run in. This primarily affects how/why/when Connect will call AC Local or remote. Change to Connect.ConfigMode.PROXY to always use remote, recommended for instances where Connect is being used on a serverConfigMode.DEFAULT
Task<string> tokenTaskThe task object that contains the authentication method. In most cases this should be left to Connection to handle. Should only be used in scenarios where the auth to Arup systems are being handled outside of Connectnull

Connection modes

The Connection object can run in multiple different "modes". These modes control when/how Connect will try to connect to AC Local and when it will instead send requests directly to the remote server. This mode is changed through changing the Connect.ConfigMode Mode argument in the constructor.

Changing the mode

Most users should not change the mode that Connect is using. If you are using Connect inside a Compute function then you should not change the mode. The correct mode will be set automatically by ArupCompute.

NameDescriptionWhen to use
DEFAULTConnect will prefer AC Local over using the remote server. It will only use remote if AC Local cannot be foundThis is the default mode that should be used in the vast majority of programs. Specifically it should be used on any program that is running on user's machines
PROXYConnect will always use the remote server, it will not look for whether AC Local is runningThis should be used when a dotnet program is running on a server where AC Local will not be present
FUNC_SERVICEConnect will always use AC Local and will throw an error if AC Local cannot be found. It makes calls to AC Local through Unix Domain Sockets rather than HTTPThis mode should not be set directly by users. It is primarily used when Connect is being used inside an ArupCompute calc running on AC Local

Example use

string jobNumber = "00000000"

Connection connection = new Connection(jobNumber); // The job number will not be charged

Non-primitive inputs / outputs - JSON

The recommended library for working with JSON in C# is Newtonsoft.JSON. However, the arupcompute-connect-dotnet library uses this in the background and can deal with serialisation / deserialisation for you.

Parallel Mode

When making calls to AC Local you can use "parallel mode" to run a batch of calcs. This will make AC Local run the calculations in the batch in parallel, meaning that the batch will run faster. There is additional setup time required on AC Local when running calcs in parallel, so for small batches it is better to run the batch not in parallel mode. From testing we have found that if the batch is larger than 10 calcs then running in parallel will be faster than in regular batch mode.

To run a calc in parallel, set the parallel param in Call.ExecuteCalculationAsync to true.

Connection connection = new Connection("00000-00"); // The job number will _not_ be charged
int calcId = 11416564; // Sample Library - Basic calculation

Dictionary<string, object> inputs = new Dictionary<string, object>()
{
{ "a", new List<int>() { 1, 2, 3, 4, 5 } },
{ "b", new List<int>() { 2, 3, 4, 5, 6 } }
};

Task<CalcRecord> resultTask = Call.ExecuteCalculationAsync(connection, calcId, batch: true, inputs, parallel: true); // Note: parallel and batch are set to true

CalcRecord calcRecord = resultTask.Result;
useFanOut

parallel should not be set to True at the same time as useFanOut. Doing this would mean that parallel would have no effect

Optional Inputs

When you want to use the default value for an optional input you can either set the value of the input to be null, or leave out the input entirely from your inputs dictionary:

// for single invocation

Dictionary<string, object> inputs = new Dictionary<string, object>()
{
{ "a", 1 },
{ "b", 2 },
{ "optional-input", null } // or leave out this line
};

Task<CalcRecord> resultTask = Call.ExecuteCalculationAsync(connection, calcId, batch: false, inputs);

CalcRecord calcRecord = resultTask.Result;
// for batch call

Dictionary<string, object> inputs = new Dictionary<string, object>()
{
{ "a", new List<int>() { 1, 2, 3, 4, 5 } },
{ "b", new List<int>() { 2, 3, 4, 5, 6 } },
{ "optional-input", new List<object>() { null, 3, 4, 1 } } // NOTE: This list is not as long as the above two lists
};

Task<CalcRecord> resultTask = Call.ExecuteCalculationAsync(connection, calcId, batch: true, inputs);

CalcRecord calcRecord = resultTask.Result;