2

What I am trying to achieve is that, I want to be able to create an Azure Function that would upload a video to YouTube using the YouTube API. example:https://developers.google.com/youtube/v3/docs/videos/insert . After creating the azure function, I then want to use that function inside my Azure logic app. Here is the code for the Azure function(uploded video):

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Upload;
using Google.Apis.Util.Store;
using Google.Apis.YouTube.v3;
using Google.Apis.YouTube.v3.Data;


namespace Google.Apis.YouTube.Samples
    {
        /// <summary>
        /// YouTube Data API v3 sample: upload a video.
        /// Relies on the Google APIs Client Library for .NET, v1.7.0 or higher.
        /// See https://developers.google.com/api-client-library/dotnet/get_started
        /// </summary>
        public class UploadVideo
        {
            [STAThread]
            static void Main(string[] args)
            {
                Console.WriteLine("YouTube Data API: Upload Video");
                Console.WriteLine("==============================");

                try
                {
                    new UploadVideo().Run().Wait();
                }
                catch (AggregateException ex)
                {
                    foreach (var e in ex.InnerExceptions)
                    {
                        Console.WriteLine("Error: " + e.Message);
                    }
                }

                Console.WriteLine("Press any key to continue...");
                Console.ReadKey();
            }

            private async Task Run()
            {
                UserCredential credential;
                using (var stream = new FileStream("client_secrets.json", FileMode.Open, FileAccess.Read))
                {
                    credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
                        GoogleClientSecrets.Load(stream).Secrets,
                        // This OAuth 2.0 access scope allows an application to upload files to the
                        // authenticated user's YouTube channel, but doesn't allow other types of access.
                        new[] { YouTubeService.Scope.YoutubeUpload },
                        "user",
                        CancellationToken.None
                    );
                }

                var youtubeService = new YouTubeService(new BaseClientService.Initializer()
                {
                    HttpClientInitializer = credential,
                    ApplicationName = Assembly.GetExecutingAssembly().GetName().Name
                });

                var video = new Video();
                video.Snippet = new VideoSnippet();
                video.Snippet.Title = "Default Video Title";
                video.Snippet.Description = "Default Video Description";
                video.Snippet.Tags = new string[] { "tag1", "tag2" };
                video.Snippet.CategoryId = "22"; // See https://developers.google.com/youtube/v3/docs/videoCategories/list
                video.Status = new VideoStatus();
                video.Status.PrivacyStatus = "unlisted"; // or "private" or "public"
                var filePath = @"/Users/sean/Desktop/audio/test1.mp4"; // Replace with path to actual movie file.

                using (var fileStream = new FileStream(filePath, FileMode.Open))
                {
                    var videosInsertRequest = youtubeService.Videos.Insert(video, "snippet,status", fileStream, "video/*");
                    videosInsertRequest.ProgressChanged += videosInsertRequest_ProgressChanged;
                    videosInsertRequest.ResponseReceived += videosInsertRequest_ResponseReceived;

                    await videosInsertRequest.UploadAsync();
                }
            }

            void videosInsertRequest_ProgressChanged(Google.Apis.Upload.IUploadProgress progress)
            {
                switch (progress.Status)
                {
                    case UploadStatus.Uploading:
                        Console.WriteLine("{0} bytes sent.", progress.BytesSent);
                        break;

                    case UploadStatus.Failed:
                        Console.WriteLine("An error prevented the upload from completing.\n{0}", progress.Exception);
                        break;
                }
            }

            void videosInsertRequest_ResponseReceived(Video video)
            {
                Console.WriteLine("Video id '{0}' was successfully uploaded.", video.Id);
            }
        }
    }

When I run this code, I am not seeing the expected outcome like this: https://developers.google.com/youtube/v3/docs/videos#resource . Instead, I am getting an error :

No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

I have made all my methods public. I am not sure what I am missing.

Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • Can you [edit] your question and provide the code you're trying to run? – MindSwipe Feb 14 '20 at 06:12
  • @MindSwipe I have updated it. –  Feb 14 '20 at 06:13
  • Why is your `UploadVideo` class `internal`? Shouldn't it be `public`? – Gaurav Mantri Feb 14 '20 at 06:17
  • @GauravMantri Yes, I have tried both public as well, but the error is same. –  Feb 14 '20 at 06:22
  • The you have posted is fine for a console application. You need to convert the logic to a Azure Functions method. I would use a storage binding, so when ever someone uploads a video to the storage would trigger the function. The function grabs the file and calls the youtube apis. To add addition META data requires a bit more work. – Zsolt Bendes Feb 14 '20 at 07:00
  • Hi @ZsoltBendes, if it is fine, then how come I am seeing the error? I have created this azure function using Visual Studio. I then want to be able to take this azure function and insert in a Azure Logic App designer. Is this feasible? –  Feb 14 '20 at 07:05
  • it is fine for a CONSOLE APPLICATION. – Zsolt Bendes Feb 14 '20 at 07:07
  • Does this answer your question? [No job functions found. Try making your job classes and methods public](https://stackoverflow.com/questions/47682760/no-job-functions-found-try-making-your-job-classes-and-methods-public) – Linda Lawton - DaImTo Feb 14 '20 at 07:08
  • 1
    @ZsoltBendes, can you point me to some tutorials on how to covert it to a Azure function? –  Feb 14 '20 at 07:13
  • https://learn.microsoft.com/en-us/azure/azure-functions/ I think MS does a great job to keep the docs up to date and useful. I would start there. I would suggest to focus on bindings. Try out different triggers and pick the one that one that is most suited for the task. – Zsolt Bendes Feb 14 '20 at 07:20

3 Answers3

3

It looks like the wrong template was used when you tried to create an Azure Function, so it created a Console App instead. Right now you're missing Azure Functions specific Nuget packages and I think your project also lacks some Azure Function specific files such as the host.json.

Can you try following these instructions when using Visual Studio: https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-your-first-function-visual-studio

Or these instructions when using VS Code: https://learn.microsoft.com/en-us/azure/azure-functions/functions-create-first-function-vs-code?pivots=programming-language-csharp

This way you'll end up with a proper structure of a Function App, including the correct dependencies.

Marc
  • 1,798
  • 8
  • 15
  • Hi @Marc thanks for that info. other than me choosing Wrong temple do you find anything else missing with code right now?thanks. –  Feb 14 '20 at 08:05
  • I see some references to file paths which are a bad practice when developing serverless functions. You could look into Azure Functions bindings for blob storage in order to use files in your function: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-storage-blob. And remove the calls to Console.Writeline. – Marc Feb 14 '20 at 13:32
2

You are missing out the FunctionName attribute

[FunctionName("Function1")]
        public static async Task<IActionResult> Run(
                [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)] HttpRequest req,
                ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");
             //UploadVideoToYoutube() method call here;
            return new OkResult();
        }

Getting started docs

HariHaran
  • 3,642
  • 2
  • 16
  • 33
  • where exactly would I place this part of code in my code? I am getting an error when I add this attribute to my code. Thanks. –  Feb 14 '20 at 07:23
  • @Peter you should clean out everything and start fresh from the docs – HariHaran Feb 14 '20 at 10:41
  • In Azure Functions with .NET 5 you need to use the `Function` attribute instead of `FunctionName`, otherwise this won't work. – Thom Jun 16 '21 at 09:03
  • @Thom What package is the Function attribute in? I can't find it at all and it was there in the default code. – Napoleon Ike Jones Jul 01 '21 at 16:21
  • @NapoleonIkeJones in the `Microsoft.Azure.Functions.Worker` nuget package. This is the package that adds the out-of-proces execution model for .NET 5. – Thom Jul 02 '21 at 07:54
0

After trying a few things that didn't work, exiting and restarting Visual Studio fixed it for me. I'm not sure why that fixes so many things.

TheTall
  • 298
  • 3
  • 7