public static async Task <object> Run([HttpTrigger(WebHookType = "genericJson")] HttpRequestMessage req, TraceWriter log)
        {
            Guid requestId = Guid.NewGuid();

            log.Info($"Notification webhook started, request {requestId} RequestUri={req.RequestUri}");
            try
            {
                Task <byte[]> taskForRequestBody = req.Content.ReadAsByteArrayAsync();
                byte[]        requestBody        = await taskForRequestBody;

                string jsonContent = await req.Content.ReadAsStringAsync();

                log.Info($"Notification webhook request {requestId} Request Body = {jsonContent}");
                IEnumerable <string> values = null;
                if (req.Headers.TryGetValues("ms-signature", out values))
                {
                    byte[] signingKey          = Convert.FromBase64String(FaceHelper.SigningKey);
                    string signatureFromHeader = values.FirstOrDefault();

                    if (VerifyWebHookRequestSignature(requestBody, signatureFromHeader, signingKey))
                    {
                        string requestMessageContents = Encoding.UTF8.GetString(requestBody);

                        NotificationMessage msg = JsonConvert.DeserializeObject <NotificationMessage>(requestMessageContents);

                        if (VerifyHeaders(req, msg, log))
                        {
                            string newJobStateStr = (string)msg.Properties.Where(j => j.Key == "NewState").FirstOrDefault().Value;
                            if (newJobStateStr == "Finished")
                            {
                                log.Info($"Notification webhook finished for request Id:{requestId}");
                                IJob job = FaceHelper.MediaContext.Jobs.Where(j => j.Id == msg.Properties["JobId"]).FirstOrDefault();
                                if (job != null)
                                {
                                    if (job.OutputMediaAssets.Count > 0)
                                    {
                                        IAsset asset     = job.OutputMediaAssets[job.OutputMediaAssets.Count - 1]; //always we want to take the last output
                                        string strStep   = asset.Name.Substring(asset.Name.LastIndexOf('_') + 1);
                                        string jobName   = asset.Name.Substring(0, asset.Name.LastIndexOf('_'));
                                        string videoname = jobName.Substring(0, jobName.LastIndexOf('_')) + ".mp4"; //TODO fix
                                        string requestid = jobName.Substring(jobName.LastIndexOf('_') + 1);
                                        log.Info($"Notification webhook finished duration: {job.RunningDuration} for request Id:{requestId} details: {strStep} {jobName} {videoname}");
                                        VideoAnalysisSteps step;
                                        if (Enum.TryParse(strStep, out step))
                                        {
                                            HttpClient         client        = FaceHelper.GetHttpClientForVideo(log);
                                            VideoAnalysisSteps nextStep      = VideoAnalysisSteps.Unknown;
                                            string             containerName = string.Empty;
                                            switch (step)
                                            {
                                            case VideoAnalysisSteps.Encode:
                                                nextStep = VideoAnalysisSteps.Redactor;
                                                break;

                                            case VideoAnalysisSteps.Redactor:
                                                containerName = ConfigurationManager.AppSettings["videoresultcontainername"];
                                                nextStep      = VideoAnalysisSteps.Copy;
                                                break;

                                            case VideoAnalysisSteps.LiveRedactor:
                                                containerName = ConfigurationManager.AppSettings["streamresultcontainername"];
                                                nextStep      = VideoAnalysisSteps.Copy;
                                                break;
                                            }
                                            if (nextStep != VideoAnalysisSteps.Unknown)
                                            {
                                                await new SendToEventGrid(log, client).SendVideoData(new VideoAssetData()
                                                {
                                                    RequestId     = requestid,
                                                    AssetName     = asset.Name,
                                                    JobName       = jobName,
                                                    VideoName     = videoname,
                                                    ContainerName = containerName,
                                                    Step          = nextStep,
                                                    PrevStep      = step,
                                                    TimeStamp     = DateTime.UtcNow
                                                });

                                                //copy the subclip video to stream container in case it was set in the setting
                                                if ((step == VideoAnalysisSteps.LiveRedactor) && (ConfigurationManager.AppSettings["copysubclip"] == "1") &&
                                                    (job.OutputMediaAssets.Count > 1))
                                                {
                                                    await new SendToEventGrid(log, client).SendVideoData(new VideoAssetData()
                                                    {
                                                        RequestId     = requestid,
                                                        AssetName     = job.OutputMediaAssets[job.OutputMediaAssets.Count - 2].Name, //assume that the second from the last item is the subclip output
                                                        JobName       = jobName,
                                                        VideoName     = videoname,
                                                        ContainerName = ConfigurationManager.AppSettings["streamsourcecontainername"],
                                                        Step          = VideoAnalysisSteps.Copy,
                                                        PrevStep      = VideoAnalysisSteps.Subclip,
                                                        TimeStamp     = DateTime.UtcNow
                                                    });
                                                }
                                            }
                                            else
                                            {
                                                log.Info($"Notification webhookfor request Id:{requestId} didn't find next step: {nextStep}");
                                            }
                                        }
                                        else
                                        {
                                            log.Info($"Notification webhookfor request Id:{requestId} didn't cast step: {strStep}");
                                        }
                                    }
                                    else
                                    {
                                        log.Info($"Notification webhookfor request Id:{requestId} didn't find output asset for job: {job.Name}");
                                    }
                                }
                                else
                                {
                                    log.Info($"Notification webhookfor request Id:{requestId} didn't find jobid: {msg.Properties["JobId"]}");
                                }
                            }

                            return(req.CreateResponse(HttpStatusCode.OK, string.Empty));
                        }
                        else
                        {
                            log.Info($"Notification webhook for VerifyHeaders request {requestId} failed.");
                            return(req.CreateResponse(HttpStatusCode.BadRequest, "VerifyHeaders failed."));
                        }
                    }
                    else
                    {
                        log.Info($"Notification webhook for VerifyWebHookRequestSignature request {requestId} failed.");
                        return(req.CreateResponse(HttpStatusCode.BadRequest, "VerifyWebHookRequestSignature failed."));
                    }
                }
            }
            catch (Exception ex)
            {
                log.Info($"Notification webhook for request Id:{requestId} failed with exception {ex.Message}");
                return(req.CreateResponse(HttpStatusCode.BadRequest, "Exception Error " + ex.Message));
            }
            log.Info($"Notification webhook for request Id:{requestId} failed");
            return(req.CreateResponse(HttpStatusCode.BadRequest, "Generic Error"));
        }
        public static async Task Run([EventGridTrigger] JObject eventGridEvent,
                                     [Blob("{data.url}", FileAccess.Read, Connection = "myblobconn")] Stream incomingVideo,
                                     TraceWriter log)
        {
            Guid requestID = Guid.NewGuid();

            log.Info($"Start TriggerByVideoUploadFunc request id: {requestID} ticks: {DateTime.Now.Ticks}");
            string eventdetails = eventGridEvent.ToString();
            bool   result       = true;

            try
            {
                string   url  = eventGridEvent["data"]["url"].ToString();
                string   name = url.Substring(url.LastIndexOf('/') + 1);
                string   nameWithoutExtension = name.Substring(0, name.IndexOf('.'));
                string[] splittedfilename     = name.Split('-');
                if (splittedfilename.Length == 2)
                {
                    string jobName   = nameWithoutExtension + "_" + requestID;
                    string assetName = nameWithoutExtension + "_" + requestID + "_" + VideoAnalysisSteps.Upload;
                    log.Info($"started uploaded new asset for {requestID} ticks: {DateTime.Now.Ticks}");
                    IAsset asset = FaceHelper.CreateAssetAndUploadSingleFile(incomingVideo, assetName, AssetCreationOptions.None);
                    log.Info($"completed uploaded asset for {requestID} send event grid to start encode process ticks: {DateTime.Now.Ticks}");
                    HttpClient client = FaceHelper.GetHttpClientForVideo(log);

                    await new SendToEventGrid(log, client).SendVideoData(new VideoAssetData()
                    {
                        RequestId     = requestID.ToString(),
                        ContainerName = string.Empty,
                        AssetName     = asset.Name,
                        JobName       = jobName,
                        VideoName     = name,
                        Step          = VideoAnalysisSteps.Encode,
                        PrevStep      = VideoAnalysisSteps.Upload,
                        TimeStamp     = DateTime.UtcNow
                    });

                    /* API V3 Not working for now  */
                    //ConfigWrapper config = new ConfigWrapper();
                    //IAzureMediaServicesClient client = FaceHelper.CreateMediaServicesClient(config);
                    //client.LongRunningOperationRetryTimeout = 2;
                    //string uniqueness = Guid.NewGuid().ToString().Substring(0, 13);
                    //string jobName = FaceHelper.GenerateJobNameByUnique(nameWithoutExtension, uniqueness);
                    //string jobName = "job-" + uniqueness;
                    //string outputAssetName = "output-" + uniqueness;
                    //string inputAssetName = "input-" + uniqueness;
                    //string adaptiveStreamingTransformName = ConfigurationManager.AppSettings["AdaptiveStreamingTransformName"];
                    //EncoderNamedPreset encodePreset = ConfigurationManager.AppSettings["EncoderPreset"];

                    //log.Info($"init job encode process {requestID} jobName: {jobName} input: {inputAssetName} output: {outputAssetName}  ticks: {DateTime.Now.Ticks}");
                    //Transform transform = FaceHelper.EnsureEncoderTransformExists(client,
                    //    config.ResourceGroup, config.AccountName, adaptiveStreamingTransformName, encodePreset, log);
                    //log.Info($"after get transform for encode process {requestID} jobName: {jobName} ticks: {DateTime.Now.Ticks}");

                    //FaceHelper.CreateInputAsset(client, config.ResourceGroup, config.AccountName, inputAssetName, name, incomingVideo);
                    //log.Info($"after create input asset for encode process {requestID} jobName: {jobName} ticks: {DateTime.Now.Ticks}");
                    //JobInput jobInput = new JobInputAsset(assetName: inputAssetName);
                    //log.Info($"before create output asset for encode process {requestID} jobName: {jobName} ticks: {DateTime.Now.Ticks}");
                    //Asset outputAsset = FaceHelper.CreateOutputAsset(client, config.ResourceGroup, config.AccountName, outputAssetName);
                    //log.Info($"after create output asset for encode process {requestID} jobName: {jobName} input: {inputAssetName} output: {outputAssetName}");
                    //FaceHelper.SubmitJob(client, config.ResourceGroup, config.AccountName,
                    //    adaptiveStreamingTransformName, jobName, jobInput, outputAssetName);
                    //log.Info($"after submit job encode process {requestID} jobName: {jobName} input: {inputAssetName} output: {outputAssetName} ticks: {DateTime.Now.Ticks}");
                }
                else
                {
                    throw new IncorrectFileName(name);
                }
            }
            catch (Exception ex)
            {
                log.Error($"Exception Message: {ex.Message}, requestId: {requestID}, details: {eventdetails}, ticks: {DateTime.Now.Ticks}", ex);
                result = false;
            }
            string succeed = result ? "" : "unsuccessful";

            log.Info($"Finished {succeed} TriggerByVideoUploadFunc requestId: {requestID} ticks: {DateTime.Now.Ticks}");
        }