예제 #1
0
        /// <summary>
        /// Writes the specified stream which contains the device request to the file storage.
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="data"></param>
        /// <exception cref="InvalidOperationException">
        /// Write operation failed due to a conflict while creating the destination blob
        /// -or- The uploaded blob has been deleted prior to generate the SAS token enabled URL to access the blob.
        /// </exception>
        /// <returns></returns>
        public async Task <string> WriteFileAsync(string deviceId, BlobStreamDecorator data)
        {
            var filePath = $"/{m_FileStorageOptions.Value.ServerFileUploadFolder}/{deviceId}/{m_FileStorageOptions.Value.ServerFileUploadSubFolder}/{Guid.NewGuid()}";

            try
            {
                await m_BlobRepository.WriteBlobAsync(filePath, data);

                return(await m_BlobRepository.GetDelegatedReadAccessAsync(filePath, ReadAccessExpiryDelay));
            }
            catch (ApiException ex)
            {
                //re-throw the exception as a non ApiException which will cause the error to be properly logged
                string error;
                switch (ex)
                {
                case ConflictException _:
                    //we are the less fortunate people on earth and got a Guid conflict
                    error = $"File '{filePath}' cannot be written";
                    break;

                case IdNotFoundException _:
                    //there is a concurrency issue somewhere and someone deleted the blob we just created
                    error = $"File '{filePath}' cannot be found";
                    break;

                default:
                    //some case we did not think about yet but we might actually need to handle...
                    throw;
                }

                //InvalidOperationException as all those errors are transient and should not happen, retrying should be fine
                throw new InvalidOperationException(error, ex);
            }
        }
예제 #2
0
        /// <summary>
        /// Creates a device request based on the incoming HTTP request.
        /// </summary>
        /// <param name="deviceId"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task <DeviceRequest> CreateRequestAsync(string deviceId, HttpRequest request)
        {
            // discard any body that could have been provided when doing GET or DELETE requests
            if (HttpMethods.IsGet(request.Method) || HttpMethods.IsDelete(request.Method))
            {
                return(new DeviceInlineRequest(request));
            }

            // determine whether the request body needs to be written to file storage or sent inline to the device.
            // a more accurate check could be done against the serialized DeviceRequest instead of the current request.ContentLength since additional info is added to the payload later on.
            // that would still not be perfectly accurate since the SDK adds its own data to the final payload.
            if (request.HasFormContentType || request.ContentLength.GetValueOrDefault() > m_DeviceCommunicationAdapter.GetMaximumMessageSize())
            {
                var fileData = new BlobStreamDecorator(request.Body)
                {
                    ContentType = request.ContentType
                };
                var blobSasUrl = string.Empty;

                await m_TelemetryService.IncrementCounterAsync("blob_upload", new string[] { });

                blobSasUrl = await m_TelemetryService.StartTimerAsync(() => m_FileService.WriteFileAsync(deviceId, fileData), "blob_upload", new string[] { });

                m_TelemetryService.Dispose();
                return(new DeviceFileRequest(request)
                {
                    BlobUrl = blobSasUrl
                });
            }
            else
            {
                var inlineRequest = new DeviceInlineRequest(request);

                using (StreamReader reader = new StreamReader(request.Body, inlineRequest.Headers.GetEncoding()))
                {
                    inlineRequest.Body = await reader.ReadToEndAsync();
                }

                return(inlineRequest);
            }
        }