C# 如何传递Forge bucket下载*绕过*web应用,而不是通过*web应用?

C# 如何传递Forge bucket下载*绕过*web应用,而不是通过*web应用?,c#,download,autodesk-forge,asp.net-apicontroller,autodesk-data-management,C#,Download,Autodesk Forge,Asp.net Apicontroller,Autodesk Data Management,我有一个基于此示例的Azure托管web应用程序: 此示例演示了一个桌面应用程序,其中显示了BIM 360团队、BIM 360文档和Fusion团队中心,它们分别包含项目、文件夹、项目和版本。对于每个版本,都可以使用查看器进行查看 (出于安全目的,托管应用程序用作中介。) 我扩展了这个示例,以便可以将项目和版本对象下载到桌面。这很有效 要下载的对象/文件将作为HttpResponseMessage从Autodesk服务器检索 using System; using System.Net; usi

我有一个基于此示例的Azure托管web应用程序:

此示例演示了一个桌面应用程序,其中显示了BIM 360团队、BIM 360文档和Fusion团队中心,它们分别包含项目、文件夹、项目和版本。对于每个版本,都可以使用查看器进行查看

(出于安全目的,托管应用程序用作中介。)

我扩展了这个示例,以便可以将项目和版本对象下载到桌面。这很有效

要下载的对象/文件将作为
HttpResponseMessage
从Autodesk服务器检索

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using Autodesk.Forge;

namespace FPD.Sample.Cloud.Controllers
{
    public class DownloadController : ApiController
    {
        private const string FORGE_BASE_URL = "https://developer.api.autodesk.com";
        private const string PROXY_ROUTE = "api/forge/download/";

        // HttpClient has been designed to be re-used for multiple calls. 
        // Even across multiple threads. 
        // https://stackoverflow.com/a/22561368/4838205
        private static HttpClient _httpClient;

        [HttpGet]
        [Route("api/forge/download/{bucketKey}/{objectName}/bucket")]
        public async Task<HttpResponseMessage> Get(string bucketKey, string objectName)
        {
            string sessionId, localId;
            if (!HeaderUtils.GetSessionLocalIDs(out sessionId, out localId)) return null;
            if (!await OAuthDB.IsSessionIdValid(sessionId, localId)) return null;
            string userAccessToken =  await OAuthDB.GetAccessToken(sessionId, localId);


            if (_httpClient == null)
            {
                _httpClient = new HttpClient(
                  // this should avoid HttpClient searching for proxy settings
                  new HttpClientHandler()
                  {
                      UseProxy = false,
                      Proxy = null
                  }, true);
                _httpClient.BaseAddress = new Uri(FORGE_BASE_URL);
                ServicePointManager.DefaultConnectionLimit = int.MaxValue;
            }

            string resourceUrl = $"/oss/v2/buckets/{bucketKey}/objects/{objectName}";
            try
            {
                HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, resourceUrl);

                // add our Access Token
                request.Headers.Add("Authorization", "Bearer " + userAccessToken);

                HttpResponseMessage response = await _httpClient.SendAsync(request,
                  // this ResponseHeadersRead force the SendAsync to return
                  // as soon as the header is ready, faster
                HttpCompletionOption.ResponseHeadersRead);

                return response;
            }
            catch
            {
                return new HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);
            }
        }
    }
}


是否可以在Azure应用程序周围传递大部分有效负载,以便对象/文件完好无损地到达,安全性得到维护,但是应用程序的数据余量没有被破坏?

您可以为对象创建一个
签名URL
,并将其传递到后端,基本上,签名URL是指向对象的链接,允许临时匿名访问-有关详细信息,请参阅


或者,您可以将对象下载到一个临时位置(请参阅和),并传递路径信息,以便在再次下载时保存代码的其他部分。

您可以尝试从rest API返回一个元组(bucketUri、userAccessToken),而不是从bucket下载的内容。然后使用RESTAPI中的相同代码在桌面客户机上下载bucket,以便download@dvitel这需要将accessToken传递给桌面客户端,不是吗?我正试图避免这种情况。谢谢你,布莱恩。我尝试了签名URL方法,但得到了403禁止响应。(我更改了范围以包括数据:写入、使用POST方法和使用签名端点。)可能是因为:“成功调用此端点需要bucket owner访问权限。”我正在尝试下载模型、衍生工具等。您提到的备选方案与我当前的工作流程没有太大区别;它仍然需要将数据带到内存或虚拟磁盘中的临时位置。确保使用客户端id/secret的Forge应用程序在为对象创建签名URL时拥有目标存储桶-只需在我存储桶中的对象上进行了尝试,就成功了:
{“signedUrl”:"https://developer.api.autodesk.com/oss/v2/signedresources/7012e598-dc2b-4aee-b8df-8ed968021170?region=US,“过期”:156860960947,“单一使用”:false}
我想将其用于BIM360模型和衍生产品,因此我绝对不是桶的所有者。还有其他想法吗?还有其他想法吗?让我与工程部谈谈,看看是否有办法解决许可问题。
        public async static Task<byte[]> GetDownload(string  bucketKey, string objectName)
        {
            byte[] bytes = await RestAPI<byte[]>.RequestAsyncBytes("api/forge/download/" + bucketKey + "/" + objectName +  "/bucket", true);
            return bytes;
        }
        public static async Task<byte[]> RequestAsyncBytes(string endpoint, IDictionary<string, string> headers, bool includeIdHeaders)
        {
            var client = new RestClient(EndPoints.BaseURL);
            var request = new RestRequest(endpoint, Method.GET);

            if (includeIdHeaders)
            {
                if (headers == null) headers = new Dictionary<string, string>();
                headers.Add("FPDSampleSessionId", SessionManager.SessionId);
                headers.Add("FPDSampleLocalId", SessionManager.MachineId);
            }

            if (headers != null)
                foreach (KeyValuePair<string, string> header in headers)
                    request.AddHeader(header.Key, header.Value);

            IRestResponse response = await client.ExecuteTaskAsync(request);
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                return response.RawBytes; 
            }
            else if (response.StatusCode == System.Net.HttpStatusCode.NoContent)
            {
                throw new Exception("No Content: " + endpoint);

            }
            else if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
            {
                throw new Exception("Not found: " + endpoint);

            }
            else
            {
                throw new Exception($"Error {response.StatusCode}. Cannot call {endpoint}");
            }

        }
byte [] bytes = await Forge.DataManagement.GetDownload(bucketKey, objectName);
System.IO.File.WriteAllBytes(pathAndFilename, bytes);