Search code examples
azureazure-functionsazure-media-servicesazure-blob-storage

Azure Functions Method not found error


I'm trying to setup an azure function that imports a blob into azure media service. But when i try to run the function in debug mode some breakpoints are never hit and then i get this error

Microsoft.Azure.WebJobs.Host.FunctionInvocationException : Exception while executing function: Functions.EncodeJob ---> System.MissingMethodException : Method not found: 'System.Threading.Tasks.Task Microsoft.WindowsAzure.MediaServices.Client.CopyBlobHelpers.CopyBlobAsync(Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob, Microsoft.WindowsAzure.Storage.Blob.CloudBlockBlob, Microsoft.WindowsAzure.Storage.Blob.BlobRequestOptions, System.Threading.CancellationToken)'. at MyApp.WebTasks.EncodeJob.EncodeJobTrigger.CreateAssetFromBlob(CloudBlob sourceBlob,CloudStorageAccount destinationStorageAccount) at C:\Source\Quickflix\MyApp.webtasks\MyApp.WebTasks\EncodeJob\EncodeJobTrigger.cs : 164 at.....(truncated due to length)

It seems the cause is this block here

            // Call the CopyBlobHelpers.CopyBlobAsync extension method to copy blobs.
        using (var task =
            CopyBlobHelpers.CopyBlobAsync((CloudBlockBlob)sourceBlob,
                (CloudBlockBlob)destinationBlob,
                new BlobRequestOptions(),
                CancellationToken.None))
        {
            task.Wait();
        }

When i comment this block out i'm able to hit a breakpoint that i stuck in the method that this belongs to. When it is not commented out the breakpoint is never hit and i get this error. The exception seems to happen as soon as i step into CreateAssetFromBlob and not on the line that actually calls CopyBlobAsync. I've checked that all my nuget packages are up to date and that the version of Microsoft.WindowsAzure.MediaServices.Client.Extensions in the bin dir is the same version. The project builds fine so i'm not sure what i am missing. I'm scratching my head over why its behaving like this, am i missing something obvious?

So the project is setup as a Webapplication using this sample https://github.com/lindydonna/FunctionsAsWebProject which seems to work ok, i can debug locally and deploy to azure functions app using git.

For a more complete code snippet this is pretty much what i have

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Azure.WebJobs.Host;
using Microsoft.WindowsAzure.MediaServices.Client;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Blob;
using Newtonsoft.Json;
using MyApp.Integration.Services;
using MyApp.Logging;

namespace MyApp.WebTasks.EncodeJob
{
    public class EncodeJobTrigger
    {
        private static CloudMediaContext _context;
        private static MediaServicesCredentials _cachedCredentials;

        public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
        {
            var blob = Encode("vidcontainer", "vid.mp4");

            return req.CreateResponse(HttpStatusCode.OK, JsonConvert.SerializeObject(blob.Exists()));
        }

        public static CloudBlob Encode(string containerName, string blobPath)
        {
            var logger = new DebugLogger();
            var amsConnectionString = "connectionstring";
            var blobStorageService = new AzureBlobStorageService(amsConnectionString, logger);
            var destStorageAccount = CloudStorageAccount.Parse("connectionstring");

            string mediaServicesAccountName = "myaccountname";
            string mediaServicesAccountKey = "mykey";

            _cachedCredentials = new MediaServicesCredentials(
                mediaServicesAccountName,
                mediaServicesAccountKey);

            _context = new CloudMediaContext(_cachedCredentials);
            var blob = blobStorageService.FindBlobInContainer(containerName, blobPath);

            ImportBlobIntoAms(blob, destStorageAccount);

            return blob;

        }

        public static IAsset ImportBlobIntoAms(CloudBlob blob, CloudStorageAccount destStorageAccount)
        {

            var asset = CreateAssetFromBlob(blob, destStorageAccount);
            return asset;
        }

        public static IAsset CreateAssetFromBlob(CloudBlob sourceBlob, CloudStorageAccount destinationStorageAccount)
        {

            CloudBlobClient destBlobStorage = destinationStorageAccount.CreateCloudBlobClient();

            // Create a new asset. 
            IAsset asset = _context.Assets.Create("NewAsset_" + Guid.NewGuid(), AssetCreationOptions.None);

            IAccessPolicy writePolicy = _context.AccessPolicies.Create("writePolicy",
                TimeSpan.FromHours(24), AccessPermissions.Write);

            ILocator destinationLocator =
                _context.Locators.CreateLocator(LocatorType.Sas, asset, writePolicy);

            // Get the asset container URI and Blob copy from mediaContainer to assetContainer. 
            CloudBlobContainer destAssetContainer =
                destBlobStorage.GetContainerReference((new Uri(destinationLocator.Path)).Segments[1]);

            if (destAssetContainer.CreateIfNotExists())
            {
                destAssetContainer.SetPermissions(new BlobContainerPermissions
                {
                    PublicAccess = BlobContainerPublicAccessType.Blob
                });
            }

            var assetFile = asset.AssetFiles.Create(sourceBlob.Name);

            ICloudBlob destinationBlob = destAssetContainer.GetBlockBlobReference(assetFile.Name);

            // Call the CopyBlobHelpers.CopyBlobAsync extension method to copy blobs.
            using (var task =
                CopyBlobHelpers.CopyBlobAsync((CloudBlockBlob)sourceBlob,
                    (CloudBlockBlob)destinationBlob,
                    new BlobRequestOptions(),
                    CancellationToken.None))
            {
                task.Wait();
            }

            assetFile.ContentFileSize = (sourceBlob as ICloudBlob).Properties.Length;
            assetFile.Update();
            Console.WriteLine("File {0} is of {1} size", assetFile.Name, assetFile.ContentFileSize);
            //            }

            asset.Update();

            destinationLocator.Delete();
            writePolicy.Delete();

            // Set the primary asset file.
            // If, for example, we copied a set of Smooth Streaming files, 
            // set the .ism file to be the primary file. 
            // If we, for example, copied an .mp4, then the mp4 would be the primary file. 
            var ismAssetFiles = asset.AssetFiles.ToList().FirstOrDefault(f => f.Name.Equals(sourceBlob.Name, StringComparison.OrdinalIgnoreCase));

            // The following code assigns the first .ism file as the primary file in the asset.
            // An asset should have one .ism file.  
            ismAssetFiles.IsPrimary = true;
            ismAssetFiles.Update();

            return asset;
        }
    }
}

Update 1 So i updated this block/function to be async and not wait on the task but i still get the same error. Updated code looks like this.

            await CopyBlobHelpers.CopyBlobAsync((CloudBlockBlob) sourceBlob,
            (CloudBlockBlob) destinationBlob,
            new BlobRequestOptions(),
            CancellationToken.None);

Also her is nugets packages.config

<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net45" />
  <package id="Microsoft.Azure.KeyVault.Core" version="2.0.4" targetFramework="net45" />
  <package id="Microsoft.Azure.WebJobs" version="2.0.0" targetFramework="net45" />
  <package id="Microsoft.Azure.WebJobs.Core" version="2.0.0" targetFramework="net45" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.0" targetFramework="net45" />
  <package id="Microsoft.Data.Edm" version="5.8.2" targetFramework="net45" />
  <package id="Microsoft.Data.OData" version="5.8.2" targetFramework="net45" />
  <package id="Microsoft.Data.Services.Client" version="5.8.2" targetFramework="net45" />
  <package id="Microsoft.Net.Compilers" version="1.0.0" targetFramework="net45" developmentDependency="true" />
  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net45" />
  <package id="System.ComponentModel.EventBasedAsync" version="4.0.11" targetFramework="net45" />
  <package id="System.Dynamic.Runtime" version="4.0.0" targetFramework="net45" />
  <package id="System.IdentityModel.Tokens.Jwt" version="4.0.2.206221351" targetFramework="net45" />
  <package id="System.Linq.Queryable" version="4.0.0" targetFramework="net45" />
  <package id="System.Net.Requests" version="4.0.11" targetFramework="net45" />
  <package id="System.Spatial" version="5.8.2" targetFramework="net45" />
  <package id="TransientFaultHandling.Core" version="5.1.1209.1" targetFramework="net45" />
  <package id="windowsazure.mediaservices" version="3.8.0.5" targetFramework="net45" />
  <package id="windowsazure.mediaservices.extensions" version="3.8.0.3" targetFramework="net45" />
  <package id="WindowsAzure.Storage" version="8.1.1" targetFramework="net45" />
</packages>

Solution

  • This is likely caused by a mismatch on the version of the Storage SDK you're using. Can you please downgrade to 7.2.1 and retry?