다음을 통해 공유


백그라운드 전송

백그라운드 전송 API를 사용하여 네트워크를 통해 파일을 안정적으로 복사합니다. 백그라운드 전송 API는 앱이 일시 중단된 동안 백그라운드에서 실행되고 앱이 종료된 후에도 지속되는 고급 업로드 및 다운로드 기능을 제공합니다. API는 네트워크 상태를 모니터링하고 연결이 끊어지면 전송을 자동으로 일시 중지하고 다시 시작하며, 전송은 데이터 감지 및 배터리 감지도 인식합니다. 즉, 다운로드 작업은 현재 연결 및 디바이스 배터리 상태에 따라 조정됩니다. API는 HTTP(S)를 사용하여 대용량 파일을 업로드하고 다운로드하는 데 이상적입니다. FTP도 지원되지만 다운로드에만 해당됩니다.

백그라운드 전송은 호출 앱과 별도로 실행되며 주로 동영상, 음악, 대형 이미지와 같은 리소스에 대한 장기 전송 작업을 위해 설계되었습니다. 이러한 시나리오에서는 앱이 일시 중단된 경우에도 다운로드가 계속 진행되므로 백그라운드 전송을 사용하는 것이 필수적입니다.

빠르게 완료될 수 있는 작은 리소스를 다운로드하는 경우 백그라운드 전송 대신 HttpClient API를 사용해야 합니다.

Windows.Networking.BackgroundTransfer 사용

백그라운드 전송 기능은 어떻게 작동하나요?

앱이 백그라운드 전송을 사용하여 전송을 시작하면 요청은 BackgroundDownloader 또는 BackgroundUploader 클래스 개체를 사용하여 구성되고 초기화됩니다. 각 전송 작업은 시스템에 의해 개별적으로 처리되며 호출 앱과는 별도로 처리됩니다. 앱 UI에서 사용자에게 상태를 제공하려는 경우 진행 정보를 사용할 수 있으며, 앱은 전송이 진행되는 동안 데이터를 일시 중지, 다시 시작, 취소하거나 읽을 수도 있습니다. 시스템에서 전송을 처리하는 방식은 스마트 전원 사용을 촉진하고 연결된 앱에서 앱 일시 중지, 종료 또는 갑작스러운 네트워크 상태 변경과 같은 이벤트에서 발생할 수 있는 문제를 방지합니다.

참고 항목

앱당 리소스 제한 때문에, 특정 주어진 시간 동안 앱의 전송이 200을 초과할 수 없습니다(DownloadOperations + UploadOperations). 이런 제한 기준을 초과하면 앱의 전송 큐가 복구할 수 없는 상태가 됩니다.

애플리케이션을 시작할 때 기존의 모든 DownloadOperationUploadOperation 개체에 대해 AttachAsync를 호출해야 합니다. 이렇게 하지 않으면 이미 완료된 전송이 누출되고, 결과적으로 백그라운드 전송 기능을 사용하는 것이 의미 없어집니다.

백그라운드 전송으로 인증된 파일 요청 수행

백그라운드 전송은 각 전송 작업에 대해 기본 서버 및 프록시 사용자 인증 정보, 쿠키, 사용자 지정 HTTP 헤더(SetRequestHeader 사용)을 지원하는 메서드를 제공합니다.

이 기능은 네트워크 상태 변경이나 예기치 못한 종료에 어떻게 적응하나요?

백그라운드 전송 기능은 연결 기능에서 제공하는 연결 및 통신사 데이터 요금제 상태 정보를 지능적으로 활용하여 네트워크 상태가 변경될 때 각 전송 작업에 대한 일관된 환경을 유지합니다. 다양한 네트워크 시나리오에 대한 동작을 정의하기 위해 앱은 BackgroundTransferCostPolicy에 정의된 값을 사용하여 각 작업에 대한 비용 정책을 설정합니다.

예를 들어, 작업에 대해 정의된 비용 정책은 디바이스가 데이터 통신 연결 네트워크를 사용할 때 작업이 자동으로 일시 중지되어야 함을 나타낼 수 있습니다. 그런 다음 "제한되지 않은" 네트워크에 대한 연결이 설정되면 전송이 자동으로 다시 시작(또는 다시 시작)됩니다. 네트워크를 비용으로 정의하는 방법에 대한 자세한 내용은 NetworkCostType을 참조하세요.

백그라운드 전송 기능에는 네트워크 상태 변경을 처리하기 위한 자체 메커니즘이 있지만 네트워크에 연결된 앱에 대한 다른 일반적인 연결 고려 사항이 있습니다. 자세한 내용은 사용 가능한 네트워크 연결 정보 활용을 참조하세요.

참고 모바일 디바이스에서 실행되는 앱에는 연결 형식, 로밍 상태 및 사용자의 데이터 요금제에 따라 전송되는 데이터 양을 사용자가 모니터링하고 제한할 수 있는 기능이 있습니다. 이로 인해 BackgroundTransferCostPolicy가 전송을 진행해야 함을 나타내는 경우에도 휴대폰에서 백그라운드 전송이 일시 중지될 수 있습니다.

다음 표는 휴대폰의 현재 상태를 고려하여 각 BackgroundTransferCostPolicy 값에 대해 휴대폰에서 백그라운드 전송이 허용되는 시기를 나타냅니다. ConnectionCost 클래스를 사용하여 휴대폰의 현재 상태를 확인할 수 있습니다.

디바이스 상태 UnrestrictedOnly 기본 항상 표시
Wi-Fi에 연결됨 허용 허용 허용
데이터 통신 연결, 로밍 아님, 데이터 제한 미만, 제한 미만 유지 예정 거부 허용 허용
데이터 통신 연결, 로밍 아님, 데이터 제한 미만, 제한 초과 예정 거부 거부 허용
데이터 통신 연결, 로밍, 데이터 제한 미만 거부 거부 허용
데이터 통신 연결, 데이터 제한 초과 이 상태는 사용자가 Data Sense UI에서 "백그라운드 데이터 제한"을 사용하도록 설정한 경우에만 발생합니다. 거부 거부 거부

파일 업로드

백그라운드 전송을 사용할 때 업로드는 작업을 다시 시작하거나 취소하는 데 사용되는 다양한 제어 방법을 노출하는 UploadOperation으로 존재합니다. 앱 이벤트(예: 일시 중단 또는 종료) 및 연결 변경은 UploadOperation에 따라 시스템에서 자동으로 처리합니다. 업로드는 앱 일시 중단 기간 또는 일시 중지 중에도 계속되며, 앱 종료 후에도 유지됩니다. 또한 CostPolicy 속성을 설정하면 인터넷 연결에 데이터 통신 연결 네트워크가 사용되는 동안 앱 업로드를 시작할지 여부가 표시됩니다.

다음 예에서는 기본 업로드 만들기 및 초기화와 이전 앱 세션에서 지속된 작업을 열거하고 다시 도입하는 방법을 안내합니다.

단일 파일 업로드

업로드 만들기는 BackgroundUploader로 시작됩니다. 이 클래스는 결과 UploadOperation을 만들기 전에 앱이 업로드를 구성할 수 있도록 하는 메서드를 제공하는 데 사용됩니다. 다음 예에서는 필수 UriStorageFile 개체를 사용하여 이 작업을 수행하는 방법을 보여 줍니다.

파일 및 업로드 대상 식별

UploadOperation 만들기를 시작하기 전에 먼저 업로드할 위치의 URI와 업로드할 파일을 식별해야 합니다. 다음 예에서는 uriString 값이 UI 입력의 문자열을 사용하여 채워지고 StorageFile 개체를 사용하는 file 값이 PickSingleFileAsync 작업에 의해 반환됩니다.

function uploadFile() {
    var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
    filePicker.fileTypeFilter.replaceAll(["*"]);

    filePicker.pickSingleFileAsync().then(function (file) {
        if (!file) {
            printLog("No file selected");
            return;
        }

        var upload = new UploadOp();
        var uriString = document.getElementById("serverAddressField").value;
        upload.start(uriString, file);

        // Store the upload operation in the uploadOps array.
        uploadOperations.push(upload);
    });
}

업로드 작업 만들기 및 초기화

이전 단계에서는 uriStringfile 값이 다음 예인 UploadOp의 인스턴스로 전달되어 새 업로드 작업을 구성하고 시작하는 데 사용됩니다. 먼저, uriString이 구문 분석되어 필수 Uri 개체를 만듭니다.

다음으로, 제공된 StorageFile(파일)의 속성은 요청 헤더를 채우고 StorageFile 개체로 SourceFile 속성을 설정하기 위해 BackgroundUploader에서 사용됩니다. 그런 다음 SetRequestHeader 메서드가 호출되어 문자열로 제공된 파일 이름과 StorageFile.Name 속성을 삽입합니다.

마지막으로, BackgroundUploaderUploadOperation(업로드)을 만듭니다.

function UploadOp() {
    var upload = null;
    var promise = null;

    this.start = function (uriString, file) {
        try {
        
            var uri = new Windows.Foundation.Uri(uriString);
            var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();

            // Set a header, so the server can save the file (this is specific to the sample server).
            uploader.setRequestHeader("Filename", file.name);

            // Create a new upload operation.
            upload = uploader.createUpload(uri, file);

            // Start the upload and persist the promise to be able to cancel the upload.
            promise = upload.startAsync().then(complete, error, progress);
        } catch (err) {
            displayError(err);
        }
    };
    // On application activation, reassign callbacks for a upload
    // operation persisted from previous application state.
    this.load = function (loadedUpload) {
        try {
            upload = loadedUpload;
            promise = upload.attachAsync().then(complete, error, progress);
        } catch (err) {
            displayError(err);
        }
    };
}

JavaScript 프라미스를 사용하여 정의된 비동기 메서드 호출에 유의합니다. 마지막 예의 한 줄을 보면 다음과 같습니다.

promise = upload.startAsync().then(complete, error, progress);

비동기 메서드 호출 다음에는 비동기 메서드 호출의 결과가 반환될 때 호출되는 앱에서 정의한 메서드를 나타내는 then 문이 옵니다. 이 프로그래밍 패턴에 대한 자세한 내용은 프라미스를 사용한 JavaScript의 비동기 프로그래밍을 참조하세요.

여러 파일 업로드

파일 및 업로드 대상 식별

단일 UploadOperation으로 전송된 여러 파일이 포함된 시나리오에서 프로세스는 일반적으로 필요한 대상 URI와 로컬 파일 정보를 먼저 제공하여 시작됩니다. 이전 섹션의 예와 유사하게 URI는 최종 사용자가 문자열로 제공하며 FileOpenPicker를 사용하면 사용자 인터페이스를 통해 파일을 표시하는 기능도 제공할 수 있습니다. 그러나 이 시나리오에서는 앱이 대신 PickMultipleFilesAsync 메서드를 호출하여 UI를 통해 여러 파일을 선택할 수 있도록 해야 합니다.

function uploadFiles() {
       var filePicker = new Windows.Storage.Pickers.FileOpenPicker();
       filePicker.fileTypeFilter.replaceAll(["*"]);

       filePicker.pickMultipleFilesAsync().then(function (files) {
          if (files === 0) {
             printLog("No file selected");
                return;
          }

          var upload = new UploadOperation();
          var uriString = document.getElementById("serverAddressField").value;
          upload.startMultipart(uriString, files);

          // Persist the upload operation in the global array.
          uploadOperations.push(upload);
       });
    }

제공된 매개 변수에 대한 개체 만들기

다음 두 예에서는 마지막 단계가 끝날 때 호출된 단일 메서드 예인 startMultipart에 포함된 코드를 사용합니다. 교육의 목적으로 BackgroundTransferContentPart 개체 배열을 만드는 메서드의 코드는 결과 UploadOperation을 만드는 코드에서 분할되었습니다.

먼저, 사용자가 제공한 URI 문자열이 Uri로 초기화됩니다. 다음으로, 이 메서드에 전송된 IStorageFile 개체(파일)의 배열이 반복되고, 각 개체는 새 BackgroundTransferContentPart 개체는 contentParts 배열에 배치됩니다.

    upload.startMultipart = function (uriString, files) {
        try {
            var uri = new Windows.Foundation.Uri(uriString);
            var uploader = new Windows.Networking.BackgroundTransfer.BackgroundUploader();

            var contentParts = [];
            files.forEach(function (file, index) {
                var part = new Windows.Networking.BackgroundTransfer.BackgroundTransferContentPart("File" + index, file.name);
                part.setFile(file);
                contentParts.push(part);
            });

다중 파트 업로드 작업 만들기 및 초기화

업로드할 각 IStorageFile을 나타내는 모든 BackgroundTransferContentPart 개체로 contentParts 배열을 채우면 요청이 전송될 위치를 표시하는 Uri를 사용하여 CreateUploadAsync를 호출할 준비가 된 것입니다.

        // Create a new upload operation.
            uploader.createUploadAsync(uri, contentParts).then(function (uploadOperation) {

               // Start the upload and persist the promise to be able to cancel the upload.
               upload = uploadOperation;
               promise = uploadOperation.startAsync().then(complete, error, progress);
            });

         } catch (err) {
             displayError(err);
         }
     };

중단된 업로드 작업 다시 시작

UploadOperation이 완료되거나 취소되면 관련 시스템 리소스가 모두 해제됩니다. 그러나 이러한 일이 발생하기 전에 앱이 종료되면 모든 활성 작업이 일시 중지되고 각 작업과 관련된 리소스는 계속 사용됩니다. 이러한 작업이 열거되지 않고 다음 앱 세션에 다시 도입되면 작업이 완료되지 않고 계속해서 디바이스 리소스를 차지하게 됩니다.

  1. 지속형 작업을 열거하는 함수를 정의하기 전에 반환할 UploadOperation 개체를 포함하는 배열을 만들어야 합니다.

    var uploadOperations = [];
    
  2. 다음으로 지속되는 작업을 열거하고 이를 배열에 저장하는 함수를 정의합니다. 앱 종료 후에도 지속되어야 하는 UploadOperation에 콜백을 다시 할당하기 위해 호출되는 load 메서드는 이 섹션의 뒷부분에서 정의하는 UploadOp 클래스에 있습니다.

    function Windows.Networking.BackgroundTransfer.BackgroundUploader.getCurrentUploadsAsync() {
        .then(function (uploads) {
            for (var i = 0; i < uploads.size; i++) {
                var upload = new UploadOp();
                upload.load(uploads[i]);
                uploadOperations.push(upload);
            }
        }
    };
    

파일 다운로드

백그라운드 전송을 사용할 때 각 다운로드는 작업을 일시 중지, 다시 시작, 재시작 및 취소하는 데 사용되는 다양한 제어 방법을 노출하는 DownloadOperation으로 존재합니다. 앱 이벤트(예: 일시 중단 또는 종료) 및 연결 변경은 DownloadOperation에 따라 시스템에서 자동으로 처리합니다. 다운로드는 앱 일시 중단 기간 또는 일시 중지 중에도 계속되며, 앱 종료 후에도 유지됩니다. 모바일 네트워크 시나리오의 경우 CostPolicy 속성을 설정하면 데이터 통신 연결 네트워크가 인터넷 연결에 사용되는 동안 앱이 다운로드를 시작하거나 계속할지 여부가 표시됩니다.

빠르게 완료될 수 있는 작은 리소스를 다운로드하는 경우 백그라운드 전송 대신 HttpClient API를 사용해야 합니다.

다음 예에서는 기본 다운로드의 만들기 및 초기화와 이전 앱 세션에서 지속된 작업을 열거하고 다시 도입하는 방법을 안내합니다.

백그라운드 전송 파일 다운로드 구성 및 시작

다음 예에서는 URI와 파일 이름을 나타내는 문자열을 사용하여 요청된 파일을 포함할 Uri 개체와 StorageFile을 만드는 방법을 보여줍니다. 이 예에서는 새 파일이 미리 정의된 위치에 자동으로 배치됩니다. 또는 FileSavePicker를 사용하여 사용자가 디바이스에서 파일을 저장할 위치를 지정할 수 있습니다. 콜백을 DownloadOperation에 재할당하기 위해 호출된 load 메서드는 앱 종료 후에도 지속되어야 하며, 이 섹션 뒷부분에서 정의된 DownloadOp 클래스에 있습니다.

function DownloadOp() {
    var download = null;
    var promise = null;
    var imageStream = null;

    this.start = function (uriString, fileName) {
        try {
            // Asynchronously create the file in the pictures folder.
            Windows.Storage.KnownFolders.picturesLibrary.createFileAsync(fileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (newFile) {
                var uri = Windows.Foundation.Uri(uriString);
                var downloader = new Windows.Networking.BackgroundTransfer.BackgroundDownloader();

                // Create a new download operation.
                download = downloader.createDownload(uri, newFile);

                // Start the download and persist the promise to be able to cancel the download.
                promise = download.startAsync().then(complete, error, progress);
            }, error);
        } catch (err) {
            displayException(err);
        }
    };
    // On application activation, reassign callbacks for a download
    // operation persisted from previous application state.
    this.load = function (loadedDownload) {
        try {
            download = loadedDownload;
            printLog("Found download: " + download.guid + " from previous application run.<br\>");
            promise = download.attachAsync().then(complete, error, progress);
        } catch (err) {
            displayException(err);
        }
    };
}

JavaScript 프라미스를 사용하여 정의된 비동기 메서드 호출에 유의합니다. 이전 코드 예의 17행을 보면 다음과 같습니다.

promise = download.startAsync().then(complete, error, progress);

비동기 메서드 호출 다음에는 비동기 메서드 호출의 결과가 반환될 때 호출되는 앱에서 정의한 메서드를 나타내는 then 문이 옵니다. 이 프로그래밍 패턴에 대한 자세한 내용은 프라미스를 사용한 JavaScript의 비동기 프로그래밍을 참조하세요.

추가 작업 제어 방법 추가

추가 DownloadOperation 메서드를 구현하여 제어 수준을 높일 수 있습니다. 예를 들어, 위 예에 다음 코드를 추가하면 다운로드를 취소하는 기능이 도입됩니다.

// Cancel download.
this.cancel = function () {
    try {
        if (promise) {
            promise.cancel();
            promise = null;
            printLog("Canceling download: " + download.guid + "<br\>");
            if (imageStream) {
                imageStream.close();
            }
        }
        else {
            printLog("Download " + download.guid + " already canceled.<br\>");
        }
    } catch (err) {
        displayException(err);
    }
};

시작 시 지속되는 작업 열거

DownloadOperation이 완료되거나 취소되면 관련 시스템 리소스가 모두 해제됩니다. 그러나 이러한 이벤트가 발생하기 전에 앱이 종료되면 다운로드가 일시 중지되고 백그라운드에서 지속됩니다. 다음 예에서는 지속형 다운로드를 새 앱 세션에서 다시 수행하는 방법을 보여 줍니다.

  1. 지속형 작업을 열거하는 함수를 정의하기 전에 반환할 DownloadOperation 개체를 포함할 배열을 만들어야 합니다.

    var downloadOps = [];
    
  2. 다음으로 지속되는 작업을 열거하고 이를 배열에 저장하는 함수를 정의합니다. 지속형 DownloadOperation에 대한 콜백을 재할당하기 위해 호출된 load 메서드는 이 섹션 뒷부분에서 정의하는 DownloadOp 예에 있습니다.

    // Enumerate outstanding downloads.
    Windows.Networking.BackgroundTransfer.BackgroundDownloader.getCurrentDownloadsAsync().done(function (downloads) {
    
        for (var i = 0; i < downloads.size; i++) {
            var download = new DownloadOp();
            download.load(downloads[i]);
            downloadOps.push(download);
        }
    });
    
  3. 이제 채워진 목록을 사용하여 보류 중인 작업을 다시 시작할 수 있습니다.

후처리

Windows 10의 한 가지 새로운 기능은 앱이 실행되지 않는 경우에도 백그라운드 전송 완료 시 애플리케이션 코드를 실행하는 기능입니다. 예를 들어, 앱이 시작할 때마다 새 영화를 검사하도록 하지 않고 영화 다운로드가 완료된 후 사용 가능한 영화 목록을 업데이트하려고 할 수 있습니다. 또는 앱이 다른 서버나 포트를 사용하여 다시 시도하여 실패한 파일 전송을 처리하려고 할 수도 있습니다. 전송 성공 및 실패 모두에 대해 사후 처리가 호출되므로 이를 사용하여 사용자 지정 오류 처리 및 다시 시도 논리를 구현할 수 있습니다.

사후 처리는 기존 백그라운드 작업 인프라를 사용합니다. 전송을 시작하기 전에 백그라운드 작업을 만들고 이를 전송과 연결합니다. 그런 다음 전송은 백그라운드에서 실행되고, 완료되면 사후 처리를 수행하기 위해 백그라운드 작업이 호출됩니다.

사후 처리에서는 새로운 클래스인 BackgroundTransferCompletionGroup을 사용합니다. 이 클래스는 백그라운드 전송을 그룹화할 수 있다는 점에서 기존 BackgroundTransferGroup과 유사하지만, BackgroundTransferCompletionGroup은 전송이 완료되면 실행할 백그라운드 작업을 지정하는 기능을 추가합니다.

다음과 같이 사후 처리를 통해 백그라운드 전송을 시작합니다.

  1. BackgroundTransferCompletionGroup 개체를 만듭니다. 그런 다음 BackgroundTaskBuilder 개체를 만듭니다. 작성기 개체의 Trigger 속성을 완료 그룹 개체로 설정하고, 작성기의 TaskEntryPoint 속성을 전송 완료 시 실행해야 하는 백그라운드 작업의 진입점으로 설정합니다. 마지막으로 BackgroundTaskBuilder.Register 메서드를 호출하여 백그라운드 작업을 등록합니다. 많은 완료 그룹이 하나의 백그라운드 작업 진입점을 공유할 수 있지만 백그라운드 작업 등록당 하나의 완료 그룹만 가질 수 있습니다.
var completionGroup = new BackgroundTransferCompletionGroup();
BackgroundTaskBuilder builder = new BackgroundTaskBuilder();

builder.Name = "MyDownloadProcessingTask";
builder.SetTrigger(completionGroup.Trigger);
builder.TaskEntryPoint = "Tasks.BackgroundDownloadProcessingTask";

BackgroundTaskRegistration downloadProcessingTask = builder.Register();
  1. 다음으로 백그라운드 전송을 완료 그룹과 연결합니다. 모든 전송이 만들어지면 완료 그룹을 사용하도록 설정합니다.
BackgroundDownloader downloader = new BackgroundDownloader(completionGroup);
DownloadOperation download = downloader.CreateDownload(uri, file);
Task<DownloadOperation> startTask = download.StartAsync().AsTask();

// App still sees the normal completion path
startTask.ContinueWith(ForegroundCompletionHandler);

// Do not enable the CompletionGroup until after all downloads are created.
downloader.CompletionGroup.Enable();
  1. 백그라운드 작업의 코드는 트리거 세부 정보에서 작업 목록을 추출합니다. 그러면 코드는 각 작업에 대한 세부 정보를 검사하고 각 작업에 대해 적절한 사후 처리를 수행할 수 있습니다.
public class BackgroundDownloadProcessingTask : IBackgroundTask
{
    public async void Run(IBackgroundTaskInstance taskInstance)
    {
    var details = (BackgroundTransferCompletionGroupTriggerDetails)taskInstance.TriggerDetails;
    IReadOnlyList<DownloadOperation> downloads = details.Downloads;

    // Do post-processing on each finished operation in the list of downloads
    }
}

사후 처리 작업은 일반적인 백그라운드 작업입니다. 이는 모든 백그라운드 작업 풀의 일부이며 모든 백그라운드 작업과 동일한 리소스 관리 정책이 적용됩니다.

또한 사후 처리는 포그라운드 완료 처리기를 바꾸지 않는다는 점에 유의합니다. 앱이 포그라운드 완료 처리기를 정의하고 파일 전송이 완료될 때 앱이 실행 중인 경우 포그라운드 완료 처리기와 백그라운드 완료 처리기가 모두 호출됩니다. 포그라운드 및 백그라운드 작업이 호출되는 순서는 보장되지 않습니다. 둘 다 정의하는 경우 두 작업이 제대로 작동하고 동시에 실행되는 경우 서로 방해하지 않는지 확인해야 합니다.

요청 시간 초과

기본 연결 시간을 제한하는 두 가지 시나리오를 고려해야 합니다.

  • 전송을 위해 새로운 연결을 설정할 때 5분 이내에 연결이 설정되지 않으면 연결 요청이 중단됩니다.

  • 연결이 설정된 후 2분 이내에 응답을 받지 못한 HTTP 요청 메시지는 중단됩니다.

참고 두 경우 모두 인터넷에 연결되어 있다고 가정하면 백그라운드 전송에서 요청을 최대 세 번까지 자동으로 다시 시도합니다. 인터넷 연결이 검색되지 않는 경우 연결이 검색될 때까지 추가 요청이 대기됩니다.

디버깅 지침

Microsoft Visual Studio에서 디버깅 세션을 중지하는 것은 앱을 닫는 것과 비슷합니다. PUT 업로드가 일시 중지되고 POST 업로드가 종료됩니다. 디버깅하는 동안에도 앱은 지속적인 업로드를 열거한 다음 다시 시작하거나 취소해야 합니다. 예를 들어, 해당 디버그 세션의 이전 작업에 관심이 없는 경우 앱 시작 시 열거된 지속 업로드 작업을 앱에서 취소하도록 할 수 있습니다.

디버그 세션 중 앱 시작 시 다운로드/업로드를 열거하는 동안 해당 디버그 세션의 이전 작업에 관심이 없으면 앱에서 이를 취소하도록 할 수 있습니다. 앱 매니페스트 변경과 같은 Visual Studio 프로젝트 업데이트가 있고 앱이 제거되었다가 다시 배포되는 경우 GetCurrentUploadsAsync는 이전 앱 배포를 사용하여 만들어진 작업을 열거할 수 없습니다.

개발 중에 백그라운드 전송을 사용하면 활성 및 완료된 전송 작업의 내부 캐시가 동기화되지 않는 상황이 발생할 수 있습니다. 이로 인해 새로운 전송 작업을 시작하지 못하거나 기존 작업 및 BackgroundTransferGroup 개체와 상호 작용하지 못할 수 있습니다. 경우에 따라 기존 작업과 상호 작용을 시도하면 크래시가 발생할 수 있습니다. 이 결과는 TransferBehavior 속성이 Parallel로 설정된 경우 발생할 수 있습니다. 이 문제는 개발 중 특정 시나리오에서만 발생하며 앱의 최종 사용자에게는 적용되지 않습니다.

Visual Studio를 사용하는 네 가지 시나리오에서 이 문제가 발생할 수 있습니다.

  • 기존 프로젝트와 동일한 앱 이름을 사용하지만 언어는 다른(예: C++에서 C#으로) 새 프로젝트를 만듭니다.
  • 기존 프로젝트에서 대상 아키텍처(예: x86에서 x64로)를 변경합니다.
  • 기존 프로젝트에서 문화권을 변경합니다(예: neutral에서 en-US로).
  • 기존 프로젝트의 패키지 매니페스트에서 기능을 추가하거나 제거합니다(예: 엔터프라이즈 인증 추가).

기능을 추가하거나 제거하는 매니페스트 업데이트를 포함한 정기적인 앱 서비스는 앱의 최종 사용자 배포에서 이 문제를 트리거하지 않습니다. 이 문제를 해결하려면 모든 버전의 앱을 완전히 제거하고 새로운 언어, 아키텍처, 문화권 또는 기능을 사용하여 다시 배포합니다. 이 작업은 시작 화면을 통해 수행하거나 PowerShell 및 Remove-AppxPackage cmdlet을 사용하여 수행할 수 있습니다.

Windows.Networking.BackgroundTransfer의 예외

URI(Uniform Resource Identifier)에 대한 잘못된 문자열이 Windows.Foundation.Uri 객체 생성자로 전달되면 예외가 발생합니다.

.NET: Windows.Foundation.Uri 형식은 C# 및 VB에서 System.Uri로 표시됩니다.

C# 및 Visual Basic에서는 .NET 4.5의 System.Uri 클래스와 System.Uri.TryCreate 메서드 중 하나를 통해 URI가 만들어지기 전에 앱 사용자로부터 받은 문자열을 테스트하여 이 오류를 방지할 수 있습니다.

C++에는 문자열을 URI로 구문 분석하는 방법이 없습니다. 앱이 Windows.Foundation.Uri에 대해 사용자 입력을 가져오면 생성자는 try/catch 블록에 있게 됩니다. 예외가 발생하면 앱은 사용자에게 알리고 새 호스트 이름을 요청할 수 있습니다.

Windows.Networking.BackgroundTransfer 네임스페이스에는 편리한 도우미 메서드가 있으며 오류 처리를 위해 Windows.Networking.Sockets 네임스페이스의 열거형을 사용합니다. 이는 앱에서 특정 네트워크 예외를 다르게 처리하는 데 유용할 수 있습니다.

Windows.Networking.BackgroundTransfer 네임스페이스의 비동기 메서드에서 발생한 오류는 HRESULT 값으로 반환됩니다. BackgroundTransferError.GetStatus 메서드는 백그라운드 전송 작업의 네트워크 오류를 WebErrorStatus 열거형 값으로 변환하는 데 사용됩니다. 대부분의 WebErrorStatus 열거형 값은 네이티브 HTTP 또는 FTP 클라이언트 작업에서 반환된 오류에 해당합니다. 앱은 특정 WebErrorStatus 열거형 값을 필터링하여 예외 원인에 따라 앱 동작을 수정할 수 있습니다.

매개 변수 유효성 검사 오류의 경우 앱은 또한 예외에서 HRESULT를 사용하여 예외의 원인이 된 오류에 대한 더 자세히 알아보기를 알 수 있습니다. 가능한 HRESULT 값은 Winerror.h 헤더 파일에 나열되어 있습니다. 대부분의 매개 변수 유효성 검사 오류에서 반환되는 HRESULTE_INVALIDARG입니다.

중요 API