Reputation: 3247
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?
Upvotes: 42
Views: 3204
Reputation: 14974
I was able to create a working demo using a .NET 4.6.1 and following nuget package:
windowsazure.mediaservices v3.6.0.0
web.config
(if doesn't exists) https://social.msdn.microsoft.com/Forums/azure/en-US/eb05a115-36b2-47a5-b464-3220548a5de9/upgrade-to-media-services-sdk-20-error-with-microsoftpracticestransientfaulthandlingcore?forum=MediaServices[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.
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/
Upvotes: 1
Reputation: 1991
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.
Upvotes: 0
Reputation: 3222
I hope that "blobContainerName" is a mock you wrote when posting the question? Capital letters and blob containers do not mix :)
Upvotes: 0
Reputation: 5150
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.
Upvotes: 0