c# - 从 blob 存储中获取资源文件并添加到 azure 批处理中的任务

标签 c# asp.net azure razor-pages

我是 Azure 和 Azure Batch 服务的新手。我创建了一个简单的 .NET 应用程序,它应该在某个输入文件上运行一些代码。这就是我开始创建作业、任务并添加随后应由我的应用程序包处理的资源文件的方式。

1.) 创建 BlobClient 等:

        // Create the blob client, for use in obtaining references to blob storage containers
        CloudBlobClient blobClient = CreateCloudBlobClient(StorageAccountName, StorageAccountKey);

        // Use the blob client to create the input container in Azure Storage 
        const string inputContainerName = "modelinput";

        CloudBlobContainer container = blobClient.GetContainerReference(inputContainerName);

        container.CreateIfNotExistsAsync().Wait();

2.) 这里上传了一个放置在应用程序目录中的文件,并将其添加到资源文件列表中:

         List<ResourceFile> inputFiles = new List<ResourceFile>();

//upload the file that should be processed and add to resourcefiles
inputFiles.Add(UploadFileToContainer(blobClient, inputContainerName, "myinputfile.xml"))

3.) 创建批处理作业和任务

    BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(BatchAccountUrl, BatchAccountName, BatchAccountKey);

        using (BatchClient batchClient = BatchClient.Open(cred))
        {

            Console.WriteLine("Creating job [{0}]...", JobId);


                CloudJob job = batchClient.JobOperations.CreateJob();
                job.Id = JobId;
                job.PoolInformation = new PoolInformation { PoolId = PoolId }; 

                job.Commit();

        List<CloudTask> tasks = new List<CloudTask>();

        string taskId = String.Format("Task{0}", 0);
        string inputFilename = inputFiles[0].FilePath;

        //set the commandline 
        string taskCommandLine = String.Format("cmd /c %AZ_BATCH_APP_PACKAGE_DEVBATCHAPP%\\batchapp.exe {0}", inputFilename);

        CloudTask task = new CloudTask(taskId, taskCommandLine)

         //add my resourcefiles to the task
        task.ResourceFiles = new List<ResourceFile> { inputFiles[0] }; 

        task.ApplicationPackageReferences = new List<ApplicationPackageReference>{new ApplicationPackageReference{ApplicationId = "devbatchapp",Version = "0.0.1"}};

        tasks.Add(task);
     }

如果我现在运行任务,一切都会完美运行。不过现在我开发了一个小的 ASP.NET Razor Pages 应用程序,用户可以通过它选择并上传文件。由于我现在只能使用文件流来上传我的文件,因此我必须将 2.) 更改为类似的内容,主要遵循文档 here :

            var filePath = Path.GetTempFileName();

            var file = Path.Combine(_environment.ContentRootPath, "uploads", filePath); 

        string containerSasToken = container.GetSharedAccessSignature(new SharedAccessBlobPolicy()
        {
            SharedAccessStartTime = DateTime.UtcNow,
            SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddDays(1),
            Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read
        });
        string containerSas = container.Uri.AbsoluteUri + containerSasToken; 

        using (var stream = new FileStream(file, FileMode.Create))
        {
            await Upload.CopyToAsync(stream);
            stream.Seek(0, SeekOrigin.Begin);
            var blobstore = container.GetBlockBlobReference("modelinput");
            await blobstore.UploadFromStreamAsync(stream);

            containerSas = blobstore.Uri.AbsoluteUri + containerSasToken;
            inputFiles = new List<ResourceFile> { 
            ResourceFile.FromStorageContainerUrl(containerSas, "myinput") };

        }

其余代码基本保持不变。但是现在当我尝试运行该任务时,我收到了 BlobDownloadMiscError 。在批处理资源管理器中对此进行分析时,我发现资源文件的 URL 显然是错误的,如果我手动将其添加到它可以工作的任务中。有人可以帮助我吗?如何获取资源文件的正确来源并将其添加到我的任务中?

最佳答案

根据我的测试,您可能没有使用正确的权限。更多详情请引用document 。此外,请确保您的存储帐户已链接到您的批量帐户。

For container access, you must have both Read and List permissions, whereas with blob access, you only need Read permission.

我的代码如下

string containerSasToken = container.GetSharedAccessSignature(new SharedAccessBlobPolicy()
{
    SharedAccessStartTime = DateTime.UtcNow,
    SharedAccessExpiryTime = DateTimeOffset.UtcNow.AddDays(1),
    Permissions = SharedAccessBlobPermissions.Write | SharedAccessBlobPermissions.Read | SharedAccessBlobPermissions.List
});

string containerSasUrl = String.Format("{0}{1}", container.Uri, containerSasToken);
var inputFiles = new List<ResourceFile> { };
var file = ResourceFile.FromStorageContainerUrl(containerSasUrl,"test");
inputFiles.Add(file);
Console.WriteLine(inputFiles.Count);

// Get a Batch client using account creds

BatchSharedKeyCredentials cred = new BatchSharedKeyCredentials(BatchAccountUrl, BatchAccountName, BatchAccountKey);

using (BatchClient batchClient = BatchClient.Open(cred))
{
    Console.WriteLine("getting pool [{0}]...", PoolId);


    batchClient.PoolOperations.GetPool(PoolId);
    
    // Create a Batch job
    Console.WriteLine("Creating job [{0}]...", JobId);

    try
    {
        CloudJob job = batchClient.JobOperations.CreateJob();
        job.Id = JobId;
        job.PoolInformation = new PoolInformation { PoolId = PoolId };

        job.Commit();
    }
    catch (BatchException be)
    {
        // Accept the specific error code JobExists as that is expected if the job already exists
        if (be.RequestInformation?.BatchError?.Code == BatchErrorCodeStrings.JobExists)
        {
            Console.WriteLine("The job {0} already existed when we tried to create it", JobId);
        }
        else
        {
            throw; // Any other exception is unexpected
        }
    }

    // Create a collection to hold the tasks that we'll be adding to the job

    Console.WriteLine("Adding {0} tasks to job [{1}]...", inputFiles.Count, JobId);

    List<CloudTask> tasks = new List<CloudTask>();

    // Create each of the tasks to process one of the input files. 

    for (int i = 0; i < inputFiles.Count; i++)
    {
        string taskId = String.Format("Task{0}", i);
        string inputFilename = inputFiles[i].FilePath;
        string taskCommandLine = String.Format("cmd /c type {0}", inputFilename);

        CloudTask task = new CloudTask(taskId, taskCommandLine);
        task.ResourceFiles = new List<ResourceFile> { inputFiles[i] };
        tasks.Add(task);
    }

    // Add all tasks to the job.
    batchClient.JobOperations.AddTask(JobId, tasks);


    // Monitor task success/failure, specifying a maximum amount of time to wait for the tasks to complete.

    TimeSpan timeout = TimeSpan.FromMinutes(30);
    Console.WriteLine("Monitoring all tasks for 'Completed' state, timeout in {0}...", timeout);

    IEnumerable<CloudTask> addedTasks = batchClient.JobOperations.ListTasks(JobId);

    batchClient.Utilities.CreateTaskStateMonitor().WaitAll(addedTasks, TaskState.Completed, timeout);

    Console.WriteLine("All tasks reached state Completed.");

    // Print task output
    Console.WriteLine();
    Console.WriteLine("Printing task output...");
}

enter image description here

关于c# - 从 blob 存储中获取资源文件并添加到 azure 批处理中的任务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57443939/

相关文章:

c# - 使用c#显示pdf文件的特定页面

ASP.NET MVC 要求我重新验证 PNG 文件而不是 GIF 或 JPEG

c# - 传递参数以作为控制台或 GUI 应用程序启动?

c# - 创建对象泛型类

c# - 如何给partial类添加数据注解?

c# - 无法加载文件或程序集 'Microsoft.AI.Agent.Intercept' 或其依赖项之一

C# 绘图 : What is the best way to draw a polygon with a hole in the middle

javascript - 使用 Javascript 中的 App Insights TrackEvent 将自定义复杂属性发送到遥测到 Azure 门户?

rest - JSON 格式 不支持 Azure 存储 REST API 的异常

c# - 具有服务总线触发器的隔离 azure 功能 - 来自 azure 应用程序配置的连接字符串