简体   繁体   中英

System.NotSupportedException when trying to create an asset

I am trying to use the Azure MediaService API along with the Azure Storage API in an API Service hosted in Azure .

The user sends the video stream to the service as an HttpPost , the service saves the video as a blob in my Storage account, the media service encodes the video and when the link to the video is ready it is returned to the user.

But when I am trying to create an Asset a System.NotSupportedException is thrown with the message:

Exception thrown: 'System.NotSupportedException' in Microsoft.Data.Services.Client.dll Exception thrown: 'System.NotSupportedException' in mscorlib.dll iisexpress.exe Error: 0 : Exception=System.NotSupportedException: This target framework does not enable you to directly enumerate over a data service query. This is because enumeration automatically sends a synchronous request to the data service. Because this framework only supports asynchronous operations, you must instead call the BeginExecute and EndExecute methods to obtain a query result that supports enumeration.

I am using the following versions of the required dependencies:

Microsoft.Data.Services.Client - 5.6.2.0
Microsoft.WindowsAzure.MediaServices.Client - 3.0.0.8
Microsoft.WindowsAzure.Storage - 3.1.0.1

Here is my code:

CloudMediaContext _context;
IAsset asset;
using (MemoryStream Ms = new MemoryStream(data.Data))
{
    _context = new CloudMediaContext("accountName", "accountKey");
    asset = await _context.Assets.CreateAsync("blobContainerName",
        AssetCreationOptions.None,CancellationToken.None);
    ...
    ...
}

The data.Data contains the byte[] of the video. The exception is thrown when CreateAsync is called. I tried _context.Assets.Create with no luck.

IMPORTANT EDIT

I created a new console application, used the code I am using in the API Service and it was executed successfully. So the problem is in the API Service.

Here is my class and method definitions

public class UploadController : ApiController
{

    [HttpPost]
    public async Task<string> PostUpload(VideoData data)
    {
        ...
        ...
    }

Any alternative to that maybe?

I was able to create a working demo using a .NET 4.6.1 and following nuget package:

[HttpPost]
public async Task<string> PostUpload()
{
    var bytes = System.Text.Encoding.UTF8.GetBytes("Test");
    var data = new VideoData { Data = bytes };
    CloudMediaContext _context;
    using (MemoryStream ms = new MemoryStream(data.Data))
    {
        var accountName = "accountName";
        var accountKey = @"primaryaccessKey";
        _context = new CloudMediaContext(accountName, accountKey);
        var asset = await _context.Assets.CreateAsync("myjblobassets", AssetCreationOptions.None, CancellationToken.None);
        //... do something with asset and ms ...
    }
    return "http://my-link";
}

* Note: any bytes is fine here since we are not demonstrating the upload part, we are making sure creating a Media Service Asset works.

  1. Add a HTML form and submit button in the index view pointing to this post action, run it and works!!!

在此输入图像描述

Note: In NAME, enter the name of the new account. A Media Services account name is all lower-case numbers or letters with no spaces, and is 3 - 24 characters in length. https://azure.microsoft.com/en-us/documentation/articles/media-services-dotnet-get-started/

I can't tell you why it's not working exactly. But i think the problem is more likely to find in the construction of your function than in the Azure API.

It should be done like this:

    // Important is the return value of the function: 
    public async Task<IAsset> CreateAssetBlobAsync(CancellationToken token)
    {            
        var asset = await _context.Assets.CreateAsync("blobContainerName", AssetCreationOptions.None, CancellationToken.None); // or your 'token'

        return asset;
    }

And this async function should be called like this:

public static async Task ProcessNewBlobAsync()
{
     // ...

     var asset = await CreateAssetBlobAsync(token);

     // ...
}

I think the problem will be your using Statement .

Fact is the Read/Write Async methods of MemoryStream don't actually provide any kind of true asynchronous implementation. Which means they always will be synchronously.

(But you didn't call any of them. I fear maybe it will be a synchronous wrapper for the async method. And so it will call the API synchronous instead of asynchronous. This is only a thought.)

I recommend to avoid using-Statements with async for preventing a deadlock .


Can you try to call method

Task<IAsset> CreateAsync(string assetName, string storageAccountName, AssetCreationOptions options, CancellationToken cancellationToken)

and pass your default storage account name associated with media service. In your example you are calling method which querying default storage account name. Querying of storage account has been done not asynchronously and it is a bug. This storage account query happens once per context not to generate load on server. It will be good if you can query during app initialization and use it within your create asset calls later.

I hope that "blobContainerName" is a mock you wrote when posting the question? Capital letters and blob containers do not mix :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM