protected override async Task DoExecuteAsync(GenerateIoTSecurityTokenContext context)
        {
            var deviceTags = await _deviceStoreServiceAgent.GetDeviceTwinTagsByIdAsync(context.Id);

            // check the passed mac address matches what we have in the device twin.
            if (deviceTags.MacAddress != context.MacAddress)
            {
                throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest)
                {
                    Content      = new StringContent($"MacAddress in device twin does not match the MacAddress of {context.MacAddress} passed"),
                    ReasonPhrase = "Critical Exception"
                });
            }

            // now generate SAS token.
            var builder = IotHubConnectionStringBuilder.Create(_iotHubConnectionString);

            int tokenExpiry = 8;

            if (context.TokenExpiryInHours != 0)
            {
                tokenExpiry = context.TokenExpiryInHours;
            }

            var device = await _deviceStoreServiceAgent.GetDeviceByIdAsync(context.Id);

            SharedAccessSignatureBuilder sasBuilder;

            if (context.SignUsingPrimaryKey)
            {
                sasBuilder = new SharedAccessSignatureBuilder()
                {
                    Key        = device.Authentication.SymmetricKey.PrimaryKey,
                    Target     = $"{builder.HostName}/devices/{WebUtility.UrlEncode(context.Id)}",
                    TimeToLive = TimeSpan.FromHours(Convert.ToDouble(tokenExpiry))
                };
            }
            else
            {
                // then use secondary key.
                sasBuilder = new SharedAccessSignatureBuilder()
                {
                    Key        = device.Authentication.SymmetricKey.SecondaryKey,
                    Target     = $"{builder.HostName}/devices/{WebUtility.UrlEncode(context.Id)}",
                    TimeToLive = TimeSpan.FromHours(Convert.ToDouble(tokenExpiry))
                };
            }

            context.SasToken = $"HostName={builder.HostName};DeviceId={context.Id};SharedAccessSignature={sasBuilder.ToSignature()}";
        }
        public async Task PublishAsync(SensorDto payload)
        {
            // publish the telemetry on the blockchain. Firstly check if we have a reference to the contract.
            if (_contract == null)
            {
                // get the latest smart contract version to invoke.
                _deviceMovementSmartContract = _smartContractServiceAgent.GetLatestVersionSmartContractByName(SmartContractName.DeviceMovement).Result;

                // if it's been removed since we bootstrapped the application, redeploy it.
                if (!_deviceMovementSmartContract.IsDeployed)
                {
                    await _blockchainServiceAgent.DeploySmartContractAsync(_deviceMovementSmartContract);
                }

                // now load the contract using the contract address

                _contract = _web3.Eth.GetContract(_deviceMovementSmartContract.Abi,
                                                  _deviceMovementSmartContract.Address);

                _storeMovementFunction = _contract.GetFunction("StoreTelemetry");
            }

            DeviceTwinTagsDto deviceTwin = null;

            if (!_deviceTwinFuncs.ContainsKey(payload.DeviceId))
            {
                deviceTwin = await _deviceStoreServiceAgent.GetDeviceTwinTagsByIdAsync(payload.DeviceId);

                _deviceTwinFuncs.Add(payload.DeviceId, () => deviceTwin);
            }
            else
            {
                deviceTwin = _deviceTwinFuncs[payload.DeviceId]();
            }

            // now to get the account and key for this blockchain user if we don't have it already.

            // unlock the account.
            var unlockResult = await _web3.Personal.UnlockAccount.SendRequestAsync(deviceTwin.BlockchainAccount, "Monday01", 1000);

            if (!unlockResult)
            {
                throw new Exception($"Unable to unlock account {deviceTwin.BlockchainAccount}");
            }

            var transactionsHash =
                await
                _storeMovementFunction.SendTransactionAsync(deviceTwin.BlockchainAccount, new HexBigInteger(900000), null,
                                                            payload.TransactionId, // this is the index for the record
                                                            payload.GpsLat,
                                                            payload.GpsLong,
                                                            payload.TemperatureInCelcius,
                                                            payload.DeviceId,
                                                            Convert.ToInt64(payload.Timestamp.Ticks));

            // check it has been mined.
            var receipt = await _web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(transactionsHash);

            while (receipt == null)
            {
                Thread.Sleep(5000);
                receipt = await _web3.Eth.Transactions.GetTransactionReceipt.SendRequestAsync(transactionsHash);
            }

            // now pass the transaction hash and id of the record so we can find it within blockchain or the smart contract to the tracking service, no need to await this process.
            await _trackerStoreServiceAgent.PublishAsync(
                new TrackerHashDto(payload.TransactionId, receipt.TransactionHash, payload.DeviceId, payload.Timestamp, receipt.BlockNumber.HexValue, receipt.BlockHash, receipt.TransactionIndex.HexValue, _deviceMovementSmartContract.Address));
        }