Azure Mobile Apps에 관리되는 클라이언트를 사용하는 방법How to use the managed client for Azure Mobile Apps

참고

Visual Studio App Center는 모바일 앱 개발의 중심인 엔드투엔드 통합 서비스를 지원합니다.Visual Studio App Center supports end to end and integrated services central to mobile app development. 개발자는 빌드, 테스트배포 서비스를 사용하여 지속적인 통합 및 업데이트 파이프라인을 설정할 수 있습니다.Developers can use Build, Test and Distribute services to set up Continuous Integration and Delivery pipeline. 앱이 배포되면 개발자는 분석진단 서비스를 사용하여 앱의 상태와 사용 현황을 모니터링하고, 푸시 서비스를 사용하여 사용자와 소통할 수 있습니다.Once the app is deployed, developers can monitor the status and usage of their app using the Analytics and Diagnostics services, and engage with users using the Push service. 또한 개발자는 인증 서비스를 사용하여 사용자를 인증하고, 데이터 서비스를 사용하여 클라우드에서 애플리케이션 데이터를 유지하고 동기화할 수도 있습니다.Developers can also leverage Auth to authenticate their users and Data service to persist and sync app data in the cloud.

모바일 애플리케이션에서 클라우드 서비스를 통합하려면 지금 App Center에 등록하세요.If you are looking to integrate cloud services in your mobile application, sign up with App Center today.

개요Overview

이 가이드에서는 Windows 및 Xamarin 앱용 Azure App Service Mobile Apps에 관리되는 클라이언트 라이브러리를 사용하는 일반적인 시나리오를 수행하는 방법을 보여 줍니다.This guide shows you how to perform common scenarios using the managed client library for Azure App Service Mobile Apps for Windows and Xamarin apps. Mobile Apps를 처음 접하는 경우 먼저 Azure Mobile Apps 빠른 시작 자습서를 완료하는 것이 좋습니다.If you are new to Mobile Apps, you should consider first completing the Azure Mobile Apps quickstart tutorial. 이 가이드에서는 클라이언트 쪽 관리되는 SDK에 초점을 둡니다.In this guide, we focus on the client-side managed SDK. Mobile Apps에 대 한 서버 쪽 Sdk에 대해 자세히 알아보려면 .Net 서버 sdk 또는 node.js 서버 sdk에 대 한 설명서를 참조 하세요.To learn more about the server-side SDKs for Mobile Apps, see the documentation for the .NET Server SDK or the Node.js Server SDK.

참조 설명서Reference documentation

클라이언트 SDK에 대한 참조 설명서는 Azure Mobile Apps .NET 클라이언트 참조에서 찾을 수 있습니다.The reference documentation for the client SDK is located here: Azure Mobile Apps .NET client reference. Azure 샘플 GitHub 리포지토리에서 몇 가지 클라이언트 샘플을 찾을 수 있습니다.You can also find several client samples in the Azure-Samples GitHub repository.

지원되는 플랫폼Supported Platforms

.NET 플랫폼은 다음과 같은 플랫폼을 지원합니다.The .NET Platform supports the following platforms:

  • API 19-24(Nougat를 통한 KitKat)용 Xamarin Android 릴리스Xamarin Android releases for API 19 through 24 (KitKat through Nougat)
  • iOS 버전 8.0 이상을 위한 Xamarin iOS 릴리스Xamarin iOS releases for iOS versions 8.0 and later
  • 범용 Windows 플랫폼Universal Windows Platform
  • Windows Phone 8.1Windows Phone 8.1
  • Silverlight 애플리케이션을 제외한 Windows Phone 8.0Windows Phone 8.0 except for Silverlight applications

"서버-흐름" 인증은 표시된 UI에 웹 보기를 사용합니다.The "server-flow" authentication uses a WebView for the presented UI. 디바이스가 웹 보기 UI를 표시할 수 없는 경우 다른 인증 방법이 필요합니다.If the device is not able to present a WebView UI, then other methods of authentication are needed. 따라서 이 SDK는 Watch 유형 또는 그와 비슷하게 제한된 디바이스에는 적합하지 않습니다.This SDK is thus not suitable for Watch-type or similarly restricted devices.

설정 및 필수 조건Setup and Prerequisites

하나 이상의 테이블에 포함된 모바일 앱 백 엔드 프로젝트를 이미 만들고 게시했다고 가정합니다.We assume that you have already created and published your Mobile App backend project, which includes at least one table. 이 토픽에 사용되는 코드에서, 테이블은 이름이 TodoItem(이)고 Id, TextComplete 열이 있습니다.In the code used in this topic, the table is named TodoItem and it has the following columns: Id, Text, and Complete. 이 테이블은 Azure Mobile Apps 빠른 시작 자습서를 완료할 때 만들었던 것과 동일한 테이블입니다.This table is the same table created when you complete the Azure Mobile Apps quickstart.

C#에서 해당하는 형식화된 클라이언트 쪽 형식은 다음 클래스입니다.The corresponding typed client-side type in C# is the following class:

public class TodoItem
{
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")]
    public string Text { get; set; }

    [JsonProperty(PropertyName = "complete")]
    public bool Complete { get; set; }
}

JsonPropertyAttribute 는 클라이언트 필드와 테이블 필드 간의 PropertyName 매핑을 정의 하는 데 사용 됩니다.The JsonPropertyAttribute is used to define the PropertyName mapping between the client field and the table field.

Mobile Apps 백 엔드에서 테이블을 만드는 방법을 알아보려면 .Net 서버 sdk 토픽 또는 node.js 서버 sdk 항목을 참조 하세요.To learn how to create tables in your Mobile Apps backend, see the .NET Server SDK topic or the Node.js Server SDK topic. 빠른 시작을 사용하여 Azure Portal에서 Mobile App 백 엔드를 만든 경우 Azure 포털 에서 쉬운 테이블설정을 사용할 수도 있습니다.If you created your Mobile App backend in the Azure portal using the QuickStart, you can also use the Easy tables setting in the Azure portal.

방법: 관리되는 클라이언트 SDK 패키지 설치How to: Install the managed client SDK package

다음 메서드 중 하나를 사용하여 NuGet에서 Mobile Apps용 관리되는 클라이언트 SDK 패키지를 설치합니다.Use one of the following methods to install the managed client SDK package for Mobile Apps from NuGet:

  • Visual Studio에서 프로젝트를 마우스 오른쪽 단추로 클릭하고 NuGet 패키지 관리를 클릭한 다음, Microsoft.Azure.Mobile.Client 패키지를 검색하고 설치를 클릭합니다.Visual Studio Right-click your project, click Manage NuGet Packages, search for the Microsoft.Azure.Mobile.Client package, then click Install.
  • Xamarin Studio 프로젝트를 마우스 오른쪽 단추로 클릭 하 고 추가 > NuGet 패키지 추가를 클릭 한 다음 Microsoft.Azure.Mobile.Client 패키지를 검색 하 고 패키지 추가를 클릭 합니다.Xamarin Studio Right-click your project, click Add > Add NuGet Packages, search for the Microsoft.Azure.Mobile.Client package, and then click Add Package.

기본 활동 파일에 다음 using 문을 추가합니다.In your main activity file, remember to add the following using statement:

using Microsoft.WindowsAzure.MobileServices;

참고

Android 프로젝트에서 참조하는 모든 지원 패키지의 버전이 동일해야 합니다.Please note that all the support packages referenced in your Android project must have the same version. SDK에는 Android 플랫폼에 대한 Xamarin.Android.Support.CustomTabs 종속성이 있으므로 프로젝트에서 최신 지원 패키지를 사용하는 경우 충돌 방지를 위해 필수 버전이 포함된 이 패키지를 직접 설치해야 합니다.The SDK has Xamarin.Android.Support.CustomTabs dependency for Android platform, so if your project uses newer support packages you need to install this package with required version directly to avoid conflicts.

방법: Visual Studio에서 디버그 작업How to: Work with debug symbols in Visual Studio

Microsoft.Azure.Mobile 네임스페이스의 기호는 SymbolSource에 있습니다.The symbols for the Microsoft.Azure.Mobile namespace are available on SymbolSource. SymbolSource를 Visual Studio와 통합하려면 SymbolSource 지침 을 참조하세요.Refer to the SymbolSource instructions to integrate SymbolSource with Visual Studio.

Mobile Apps 클라이언트 만들기Create the Mobile Apps client

다음 코드는 모바일 앱 백 엔드에 액세스하는 데 사용되는 MobileServiceClient 개체를 만듭니다.The following code creates the MobileServiceClient object that is used to access your Mobile App backend.

var client = new MobileServiceClient("MOBILE_APP_URL");

위의 코드에서 MOBILE_APP_URL 을 모바일 앱 백 엔드의 URL로 대체하며 이는 Azure 포털의 모바일 앱 백 엔드에 대한 블레이드에서 찾을 수 있습니다.In the preceding code, replace MOBILE_APP_URL with the URL of the Mobile App backend, which is found in the blade for your Mobile App backend in the Azure portal. MobileServiceClient 개체는 단일 항목이어야 합니다.The MobileServiceClient object should be a singleton.

테이블 작업Work with Tables

다음 섹션에는 레코드를 검색하고 테이블 내에서 데이터를 수정하는 방법을 자세히 설명합니다.The following section details how to search and retrieve records and modify the data within the table. 다음 항목이 다루어집니다.The following topics are covered:

방법: 테이블 참조 만들기How to: Create a table reference

백 엔드 테이블의 데이터에 액세스하거나 데이터를 수정하는 모든 코드는 MobileServiceTable 개체의 함수를 호출합니다.All the code that accesses or modifies data in a backend table calls functions on the MobileServiceTable object. 다음과 같이 GetTable 메서드를 호출하여 테이블에 대한 참조를 구합니다.Obtain a reference to the table by calling the GetTable method, as follows:

IMobileServiceTable<TodoItem> todoTable = client.GetTable<TodoItem>();

반환된 개체는 형식화된 직렬화 모델을 사용합니다.The returned object uses the typed serialization model. 형식화되지 않은 직렬화 모델도 지원됩니다.An untyped serialization model is also supported. 다음 예제는 형식화되지 않은 테이블에 참조를 만듭니다.The following example creates a reference to an untyped table:

// Get an untyped table reference
IMobileServiceTable untypedTodoTable = client.GetTable("TodoItem");

형식화되지 않은 쿼리에서 기본 OData 쿼리 문자열을 지정해야 합니다.In untyped queries, you must specify the underlying OData query string.

방법: 모바일 앱에서 데이터 쿼리How to: Query data from your Mobile App

이 섹션에서는 다음 기능을 비롯하여 모바일 앱 백 엔드에 대한 쿼리를 실행하는 방법을 설명합니다.This section describes how to issue queries to the Mobile App backend, which includes the following functionality:

참고

모든 행이 반환되는 것을 방지하기 위해 서버 기반 페이지 크기가 적용됩니다.A server-driven page size is enforced to prevent all rows from being returned. 페이징은 대규모 데이터 집합에 대한 기본 요청이 서비스에 부정적인 영향을 미치지 않게 방지합니다.Paging keeps default requests for large data sets from negatively impacting the service. 50개가 넘는 행을 반환하려면 페이지에서 데이터 반환에서 설명하는 대로 SkipTake 메서드를 사용하세요.To return more than 50 rows, use the Skip and Take method, as described in Return data in pages.

방법: 반환된 데이터 필터링How to: Filter returned data

다음 코드는 쿼리에 Where 절을 포함하여 데이터를 필터링하는 방법을 보여줍니다.The following code illustrates how to filter data by including a Where clause in a query. 이 코드에서는 todoTable에서 해당 Complete 속성이 false인 모든 항목을 반환합니다.It returns all items from todoTable whose Complete property is equal to false. Where 함수는 테이블에 대한 쿼리에 행 필터링 조건자를 적용합니다.The Where function applies a row filtering predicate to the query against the table.

// This query filters out completed TodoItems and items without a timestamp.
List<TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false)
    .ToListAsync();

브라우저 개발자 도구 또는 Fiddler와 같은 메시지 검사 소프트웨어를 사용하여 백 엔드에 전송된 요청의 URI를 볼 수 있습니다.You can view the URI of the request sent to the backend by using message inspection software, such as browser developer tools or Fiddler. 이 요청 URI에서 알 수 있듯이 쿼리 문자열이 수정됩니다.If you look at the request URI, notice that the query string is modified:

GET /tables/todoitem?$filter=(complete+eq+false) HTTP/1.1

이 OData 요청은 서버 SDK에 의해 SQL 쿼리로 변환됩니다.This OData request is translated into an SQL query by the Server SDK:

SELECT *
    FROM TodoItem
    WHERE ISNULL(complete, 0) = 0

Where 메서드에 전달되는 함수는 조건을 임의의 수만큼 가질 수 있습니다.The function that is passed to the Where method can have an arbitrary number of conditions.

// This query filters out completed TodoItems where Text isn't null
List<TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false && todoItem.Text != null)
    .ToListAsync();

이 예는 서버 SDK에 의해 SQL 쿼리로 변환됩니다.This example would be translated into an SQL query by the Server SDK:

SELECT *
    FROM TodoItem
    WHERE ISNULL(complete, 0) = 0
          AND ISNULL(text, 0) = 0

이 쿼리는 여러 절로 분할될 수도 있습니다.This query can also be split into multiple clauses:

List<TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false)
    .Where(todoItem => todoItem.Text != null)
    .ToListAsync();

두 메서드는 동등하며 서로 교환해서 사용할 수 있습니다.The two methods are equivalent and may be used interchangeably. 여러 조건자를 하나의 쿼리—에서 연결하는 첫 번째 옵션—이 더 간편하며 권장됩니다.The former option—of concatenating multiple predicates in one query—is more compact and recommended.

Where 절은 OData 하위 집합으로 변환되는 작업을 지원합니다.The Where clause supports operations that be translated into the OData subset. 작업에는 다음 항목이 포함됩니다.Operations include:

  • 관계형 연산자(==, !=, <, <=, >, >=),Relational operators (==, !=, <, <=, >, >=),
  • 산술 연산자(+, -, /, *, %),Arithmetic operators (+, -, /, *, %),
  • 숫자 정밀도(Math.Floor, Math.Ceiling),Number precision (Math.Floor, Math.Ceiling),
  • 문자열 함수(Length, Substring, Replace, IndexOf, StartsWith, EndsWith),String functions (Length, Substring, Replace, IndexOf, StartsWith, EndsWith),
  • 날짜 속성(연도, 월, 일, 시, 분, 초),Date properties (Year, Month, Day, Hour, Minute, Second),
  • 개체의 액세스 속성,Access properties of an object, and
  • 이러한 연산자를 결합하는 식.Expressions combining any of these operations.

서버 SDK가 지원하는 것을 고려할 때 OData v3 설명서를 고려할 수 있습니다.When considering what the Server SDK supports, you can consider the OData v3 Documentation.

방법: 반환된 데이터 정렬How to: Sort returned data

다음 코드는 쿼리에 OrderBy 또는 OrderByDescending 함수를 포함하여 데이터를 정렬하는 방법을 보여 줍니다.The following code illustrates how to sort data by including an OrderBy or OrderByDescending function in the query. todoTable의 항목을 Text 필드를 기준으로 오름차순 정렬한 항목을 반환합니다.It returns items from todoTable sorted ascending by the Text field.

// Sort items in ascending order by Text field
MobileServiceTableQuery<TodoItem> query = todoTable
                .OrderBy(todoItem => todoItem.Text)
List<TodoItem> items = await query.ToListAsync();

// Sort items in descending order by Text field
MobileServiceTableQuery<TodoItem> query = todoTable
                .OrderByDescending(todoItem => todoItem.Text)
List<TodoItem> items = await query.ToListAsync();

방법: 페이지에서 데이터 반환How to: Return data in pages

기본적으로 백 엔드는 첫 50개 행만 반환합니다.By default, the backend returns only the first 50 rows. Take 메서드를 호출하여 반환 행 수를 늘릴 수 있습니다.You can increase the number of returned rows by calling the Take method. Take 을(를) Skip 메서드와 함께 사용하면 쿼리에서 반환되는 전체 데이터 세트의 특정 "페이지"가 요청됩니다.Use Take along with the Skip method to request a specific "page" of the total dataset returned by the query. 다음 쿼리를 실행하면 테이블에서 맨 위에 있는 세 개의 항목을 반환합니다.The following query, when executed, returns the top three items in the table.

// Define a filtered query that returns the top 3 items.
MobileServiceTableQuery<TodoItem> query = todoTable.Take(3);
List<TodoItem> items = await query.ToListAsync();

수정된 다음 쿼리는 처음 세 개 결과를 건너뛰고 그 다음 세 개 결과를 반환합니다.The following revised query skips the first three results and returns the next three results. 이 쿼리는 두 번째 데이터 "페이지"를 생성하며, 페이지 크기는 세 개 항목입니다.This query produces the second "page" of data, where the page size is three items.

// Define a filtered query that skips the top 3 items and returns the next 3 items.
MobileServiceTableQuery<TodoItem> query = todoTable.Skip(3).Take(3);
List<TodoItem> items = await query.ToListAsync();

IncludeTotalCount 메서드는 지정된 페이징/제한 절을 무시하고, 반환되었어야 할 모든 레코드의 총 개수를 요청합니다.The IncludeTotalCount method requests the total count for all the records that would have been returned, ignoring any paging/limit clause specified:

query = query.IncludeTotalCount();

실제 앱에서는 Pager 컨트롤이나 그와 비슷한 UI에서 이전 예제와 비슷한 쿼리를 사용하여 페이지를 탐색할 수 있습니다.In a real world app, you can use queries similar to the preceding example with a pager control or comparable UI to navigate between pages.

참고

모바일 앱 백 엔드에서 50행 제한을 재정의하려면 EnableQueryAttribute 를 공용 GET 메서드에도 적용하고 페이징 동작을 지정해야 합니다.To override the 50-row limit in a Mobile App backend, you must also apply the EnableQueryAttribute to the public GET method and specify the paging behavior. 메서드에 적용할 때 다음은 최대 반환 행을 1000으로 설정합니다.When applied to the method, the following sets the maximum returned rows to 1000:

[EnableQuery(MaxTop=1000)]

방법: 특정 열 선택How to: Select specific columns

쿼리에 Select 절을 추가하면 결과에 포함할 속성 집합을 지정할 수 있습니다.You can specify which set of properties to include in the results by adding a Select clause to your query. 예를 들어 다음 코드는 하나의 필드만 선택하는 방법 및 여러 필드를 선택하고 형식을 지정하는 방법을 보여 줍니다.For example, the following code shows how to select just one field and also how to select and format multiple fields:

// Select one field -- just the Text
MobileServiceTableQuery<TodoItem> query = todoTable
                .Select(todoItem => todoItem.Text);
List<string> items = await query.ToListAsync();

// Select multiple fields -- both Complete and Text info
MobileServiceTableQuery<TodoItem> query = todoTable
                .Select(todoItem => string.Format("{0} -- {1}",
                    todoItem.Text.PadRight(30), todoItem.Complete ?
                    "Now complete!" : "Incomplete!"));
List<string> items = await query.ToListAsync();

지금까지 설명한 모든 함수는 가산적이므로 계속해서 연결 상태를 유지할 수 있습니다.All the functions described so far are additive, so we can keep chaining them. 연결된 각 호출은 더 많은 쿼리에 영향을 줍니다.Each chained call affects more of the query. 한 가지 예를 더 들면 다음과 같습니다.One more example:

MobileServiceTableQuery<TodoItem> query = todoTable
                .Where(todoItem => todoItem.Complete == false)
                .Select(todoItem => todoItem.Text)
                .Skip(3).
                .Take(3);
List<string> items = await query.ToListAsync();

방법: ID를 기준으로 데이터 조회How to: Look up data by ID

LookupAsync 함수를 사용하여 데이터베이스에서 특정 ID를 가진 개체를 조회할 수 있습니다.The LookupAsync function can be used to look up objects from the database with a particular ID.

// This query filters out the item with the ID of 37BBF396-11F0-4B39-85C8-B319C729AF6D
TodoItem item = await todoTable.LookupAsync("37BBF396-11F0-4B39-85C8-B319C729AF6D");

방법: 형식화되지 않은 쿼리 실행How to: Execute untyped queries

형식화되지 않은 테이블 개체를 사용하여 쿼리를 실행하는 경우 다음 예제와 같이 ReadAsync를 호출하여 OData 쿼리 문자열을 명시적으로 지정해야 합니다.When executing a query using an untyped table object, you must explicitly specify the OData query string by calling ReadAsync, as in the following example:

// Lookup untyped data using OData
JToken untypedItems = await untypedTodoTable.ReadAsync("$filter=complete eq 0&$orderby=text");

속성 모음처럼 사용할 수 있는 JSON 값이 반환됩니다.You get back JSON values that you can use like a property bag. JToken 및 Newtonsoft Json.NET에 대한 자세한 내용은 Json.NET 사이트를 참조하세요.For more information on JToken and Newtonsoft Json.NET, see the Json.NET site.

방법: 모바일 앱 백 엔드에 데이터 삽입How to: Insert data into a Mobile App backend

모든 클라이언트 형식은 ID라는 멤버를 포함해야 하며 이는 기본적으로 문자열입니다.All client types must contain a member named Id, which is by default a string. Id 는 CRUD 작업을 수행 하 고 오프 라인 동기화를 수행 하는 데 필요 합니다. 다음 코드는 InsertAsync 메서드를 사용 하 여 테이블에 새 행을 삽입 하는 방법을 보여 줍니다.This Id is required to perform CRUD operations and for offline sync. The following code illustrates how to use the InsertAsync method to insert new rows into a table. 매개 변수에는 .NET 개체로 삽입할 데이터가 포함되어 있습니다.The parameter contains the data to be inserted as a .NET object.

await todoTable.InsertAsync(todoItem);

삽입하는 동안 고유한 사용자 지정 ID 값이 todoItem 에 포함되어 있지 않으면 서버에서 GUID를 생성합니다.If a unique custom ID value is not included in the todoItem during an insert, a GUID is generated by the server. 호출이 반환된 후 개체를 검사하여 생성된 Id를 검색할 수 있습니다.You can retrieve the generated Id by inspecting the object after the call returns.

형식화되지 않은 데이터를 삽입하려는 경우 Json.NET을 활용할 수 있습니다.To insert untyped data, you may take advantage of Json.NET:

JObject jo = new JObject();
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.InsertAsync(jo);

다음은 메일 주소를 고유 문자열 id로 사용하는 예제입니다.Here is an example using an email address as a unique string id:

JObject jo = new JObject();
jo.Add("id", "myemail@emaildomain.com");
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.InsertAsync(jo);

ID 값으로 작업Working with ID values

Mobile Apps는 테이블의 id 열에 대한 고유한 사용자 지정 문자열 값을 지원합니다.Mobile Apps supports unique custom string values for the table's id column. 문자열 값은 애플리케이션에서 전자 메일 주소 또는 사용자 이름과 같은 사용자 지정 값을 ID에 사용할 수 있습니다.A string value allows applications to use custom values such as email addresses or user names for the ID. 문자열 ID는 다음과 같은 이점을 제공합니다.String IDs provide you with the following benefits:

  • ID는 데이터베이스에 대한 왕복 없이도 생성됩니다.IDs are generated without making a round trip to the database.
  • 여러 테이블 또는 데이터베이스의 레코드를 병합하기가 더 쉽습니다.Records are easier to merge from different tables or databases.
  • 애플리케이션의 논리를 통해 ID 값이 더 효율적으로 통합될 수 있습니다.IDs values can integrate better with an application's logic.

문자열 ID 값이 삽입된 레코드에 설정되지 않은 경우 모바일 앱 백 엔드는 해당 ID에 대한 고유한 값을 생성합니다.When a string ID value is not set on an inserted record, the Mobile App backend generates a unique value for the ID. Guid.NewGuid 메서드를 사용하여 클라이언트나 백엔드에서 고유한 ID 값을 생성할 수 있습니다.You can use the Guid.NewGuid method to generate your own ID values, either on the client or in the backend.

JObject jo = new JObject();
jo.Add("id", Guid.NewGuid().ToString("N"));

방법: 모바일 앱 백 엔드의 데이터 수정How to: Modify data in a Mobile App backend

다음 코드는 UpdateAsync 메서드를 사용하여 새로운 정보가 포함된 같은 ID로 기존 기록을 업데이트하는 방법을 보여줍니다.The following code illustrates how to use the UpdateAsync method to update an existing record with the same ID with new information. 매개 변수에는 .NET 개체로 업데이트할 데이터가 포함되어 있습니다.The parameter contains the data to be updated as a .NET object.

await todoTable.UpdateAsync(todoItem);

형식화되지 않은 데이터를 업데이트하려는 경우 다음과 같이 Json.NET 을 활용할 수 있습니다.To update untyped data, you may take advantage of Json.NET as follows:

JObject jo = new JObject();
jo.Add("id", "37BBF396-11F0-4B39-85C8-B319C729AF6D");
jo.Add("Text", "Hello World");
jo.Add("Complete", false);
var inserted = await table.UpdateAsync(jo);

업데이트할 때 id 필드를 지정해야 합니다.An id field must be specified when making an update. 백 엔드는 id 필드를 사용하여 업데이트할 행을 식별합니다.The backend uses the id field to identify which row to update. id 필드는 InsertAsync 호출의 결과에서 가져올 수 있습니다.The id field can be obtained from the result of the InsertAsync call. id 값을 제공하지 않고 항목을 업데이트하려고 할 때 ArgumentException이(가) 발생합니다.An ArgumentException is raised if you try to update an item without providing the id value.

방법: 모바일 앱 백 엔드의 데이터 삭제How to: Delete data in a Mobile App backend

다음 코드는 DeleteAsync 메서드를 사용하여 기존 인스턴스를 삭제하는 방법을 보여 줍니다.The following code illustrates how to use the DeleteAsync method to delete an existing instance. 인스턴스는 todoItem에 설정된 id 필드로 식별됩니다.The instance is identified by the id field set on the todoItem.

await todoTable.DeleteAsync(todoItem);

형식화되지 않은 데이터를 삭제하려면 다음과 같이 Json.NET을 이용할 수 있습니다.To delete untyped data, you may take advantage of Json.NET as follows:

JObject jo = new JObject();
jo.Add("id", "37BBF396-11F0-4B39-85C8-B319C729AF6D");
await table.DeleteAsync(jo);

삭제를 요청할 때 ID를 지정해야 합니다.When you make a delete request, an ID must be specified. 다른 속성은 서비스에 전달되지 않거나 서비스에서 무시됩니다.Other properties are not passed to the service or are ignored at the service. DeleteAsync 호출의 결과는 일반적으로 null입니다.The result of a DeleteAsync call is usually null. 전달할 ID는 InsertAsync 호출의 결과에서 가져올 수 있습니다.The ID to pass in can be obtained from the result of the InsertAsync call. id 필드를 지정하지 않고 항목을 삭제하려고 할 때 MobileServiceInvalidOperationException이(가) 발생합니다.A MobileServiceInvalidOperationException is thrown when you try to delete an item without specifying the id field.

방법: 충돌 해결에 낙관적 동시성 사용How to: Use Optimistic Concurrency for conflict resolution

두 개 이상의 클라이언트가 동시에 동일 항목의 변경 내용을 작성할 수 있습니다.Two or more clients may write changes to the same item at the same time. 충돌 검색 없이, 마지막으로 쓴 내용이 이전 업데이트를 덮어씁니다.Without conflict detection, the last write would overwrite any previous updates. 낙관적 동시성 제어 에서는 각 트랜잭션이 커밋할 수 있으므로 리소스 잠금을 사용하지 않는다고 가정합니다.Optimistic concurrency control assumes that each transaction can commit and therefore does not use any resource locking. 트랜잭션을 커밋하기 전에 낙관적 동시성 제어는 다른 트랜잭션에서 데이터를 수정하지 않았음을 확인합니다.Before committing a transaction, optimistic concurrency control verifies that no other transaction has modified the data. 데이터가 수정된 경우에는 커밋 중인 트랜잭션이 롤백됩니다.If the data has been modified, the committing transaction is rolled back.

Mobile Apps는 Mobile App 백 엔드의 각 테이블에 대해 정의된 version 시스템 속성 열을 사용하는 각 항목의 변경 내용을 추적하여 낙관적 동시성 제어를 지원합니다.Mobile Apps supports optimistic concurrency control by tracking changes to each item using the version system property column that is defined for each table in your Mobile App backend. 레코드가 업데이트될 때마다 Mobile Apps는 해당 레코드의 version 속성을 새 값으로 설정합니다.Each time a record is updated, Mobile Apps sets the version property for that record to a new value. 각 업데이트 요청 중에 요청에 포함된 레코드의 version 속성이 서버에 있는 레코드의 동일 속성과 비교됩니다.During each update request, the version property of the record included with the request is compared to the same property for the record on the server. 요청과 함께 전달된 버전이 백 엔드와 일치하지 않는 경우 클라이언트 라이브러리는 MobileServicePreconditionFailedException<T> 예외를 발생시킵니다.If the version passed with the request does not match the backend, then the client library raises a MobileServicePreconditionFailedException<T> exception. 예외에 포함된 형식은 백 엔드의 레코드이며 서버 버전의 레코드를 포함하고 있습니다.The type included with the exception is the record from the backend containing the servers version of the record. 그러면 애플리케이션은 이 정보를 사용하여 변경을 커밋하기 위해 백 엔드의 올바른 version 값으로 업데이트 요청을 다시 실행할지 여부를 결정할 수 있습니다.The application can then use this information to decide whether to execute the update request again with the correct version value from the backend to commit changes.

낙관적 동시성을 사용하기 위해 version 시스템 속성의 테이블 클래스에 대해 열을 정의합니다.Define a column on the table class for the version system property to enable optimistic concurrency. 다음은 그 예입니다.For example:

public class TodoItem
{
    public string Id { get; set; }

    [JsonProperty(PropertyName = "text")]
    public string Text { get; set; }

    [JsonProperty(PropertyName = "complete")]
    public bool Complete { get; set; }

    // *** Enable Optimistic Concurrency *** //
    [JsonProperty(PropertyName = "version")]
    public string Version { set; get; }
}

형식화되지 않은 테이블을 사용하는 애플리케이션은 다음과 같이 테이블의 SystemProperties에 대해 Version 플래그를 설정하여 낙관적 동시성을 사용합니다.Applications using untyped tables enable optimistic concurrency by setting the Version flag on the SystemProperties of the table as follows.

//Enable optimistic concurrency by retrieving version
todoTable.SystemProperties |= MobileServiceSystemProperties.Version;

낙관적 동시성을 사용하는 것 외에도 UpdateAsync를 호출할 때 코드에서 MobileServicePreconditionFailedException<T> 예외를 검색해야 합니다.In addition to enabling optimistic concurrency, you must also catch the MobileServicePreconditionFailedException<T> exception in your code when calling UpdateAsync. 업데이트된 레코드에 올바른 version 을(를) 적용하여 충돌을 해결하고 해결된 레코드로 UpdateAsync 를 호출합니다.Resolve the conflict by applying the correct version to the updated record and call UpdateAsync with the resolved record. 다음 코드는 감지된 쓰기 충돌을 해결하는 방법을 보여 줍니다.The following code shows how to resolve a write conflict once detected:

private async void UpdateToDoItem(TodoItem item)
{
    MobileServicePreconditionFailedException<TodoItem> exception = null;

    try
    {
        //update at the remote table
        await todoTable.UpdateAsync(item);
    }
    catch (MobileServicePreconditionFailedException<TodoItem> writeException)
    {
        exception = writeException;
    }

    if (exception != null)
    {
        // Conflict detected, the item has changed since the last query
        // Resolve the conflict between the local and server item
        await ResolveConflict(item, exception.Item);
    }
}


private async Task ResolveConflict(TodoItem localItem, TodoItem serverItem)
{
    //Ask user to choose the resolution between versions
    MessageDialog msgDialog = new MessageDialog(
        String.Format("Server Text: \"{0}\" \nLocal Text: \"{1}\"\n",
        serverItem.Text, localItem.Text),
        "CONFLICT DETECTED - Select a resolution:");

    UICommand localBtn = new UICommand("Commit Local Text");
    UICommand ServerBtn = new UICommand("Leave Server Text");
    msgDialog.Commands.Add(localBtn);
    msgDialog.Commands.Add(ServerBtn);

    localBtn.Invoked = async (IUICommand command) =>
    {
        // To resolve the conflict, update the version of the item being committed. Otherwise, you will keep
        // catching a MobileServicePreConditionFailedException.
        localItem.Version = serverItem.Version;

        // Updating recursively here just in case another change happened while the user was making a decision
        UpdateToDoItem(localItem);
    };

    ServerBtn.Invoked = async (IUICommand command) =>
    {
        RefreshTodoItems();
    };

    await msgDialog.ShowAsync();
}

자세한 내용은 Azure Mobile Apps에서 오프라인 데이터 동기화 토픽을 참조하세요.For more information, see the Offline Data Sync in Azure Mobile Apps topic.

방법: Mobile Apps 데이터를 Windows 사용자 인터페이스에 바인딩How to: Bind Mobile Apps data to a Windows user interface

이 섹션에서는 반환된 데이터 개체를 Windows 앱의 UI 요소를 사용해서 표시하는 방법을 보여 줍니다.This section shows how to display returned data objects using UI elements in a Windows app. 다음 예제 코드는 완료되지 않은 항목에 대한 쿼리를 사용하여 목록의 소스에 바인딩합니다.The following example code binds to the source of the list with a query for incomplete items. MobileServiceCollection은 Mobile Apps 인식 바인딩 컬렉션을 만듭니다.The MobileServiceCollection creates a Mobile Apps-aware binding collection.

// This query filters out completed TodoItems.
MobileServiceCollection<TodoItem, TodoItem> items = await todoTable
    .Where(todoItem => todoItem.Complete == false)
    .ToCollectionAsync();

// itemsControl is an IEnumerable that could be bound to a UI list control
IEnumerable itemsControl  = items;

// Bind this to a ListBox
ListBox lb = new ListBox();
lb.ItemsSource = items;

관리되는 런타임의 일부 컨트롤은 ISupportIncrementalLoading이라는 인터페이스를 지원합니다.Some controls in the managed runtime support an interface called ISupportIncrementalLoading. 이 인터페이스에서는 사용자가 스크롤할 때 컨트롤이 추가 데이터를 요청할 수 있습니다.This interface allows controls to request extra data when the user scrolls. 컨트롤에서 발생하는 호출을 자동으로 처리하는 MobileServiceIncrementalLoadingCollection을 통해 유니버설 Windows 앱용으로 이 인터페이스를 기본적으로 지원합니다.There is built-in support for this interface for universal Windows apps via MobileServiceIncrementalLoadingCollection, which automatically handles the calls from the controls. 다음과 같이 Windows 앱에서 MobileServiceIncrementalLoadingCollection 을 사용합니다.Use MobileServiceIncrementalLoadingCollection in Windows apps as follows:

MobileServiceIncrementalLoadingCollection<TodoItem,TodoItem> items;
items = todoTable.Where(todoItem => todoItem.Complete == false).ToIncrementalLoadingCollection();

ListBox lb = new ListBox();
lb.ItemsSource = items;

Windows Phone 8 및 "Silverlight" 앱에서 새 컬렉션을 사용하려면 IMobileServiceTableQuery<T>IMobileServiceTable<T>에서 ToCollection 확장 메서드를 사용합니다.To use the new collection on Windows Phone 8 and "Silverlight" apps, use the ToCollection extension methods on IMobileServiceTableQuery<T> and IMobileServiceTable<T>. 데이터를 로드하려면 LoadMoreItemsAsync()를 호출합니다.To load data, call LoadMoreItemsAsync().

MobileServiceCollection<TodoItem, TodoItem> items = todoTable.Where(todoItem => todoItem.Complete==false).ToCollection();
await items.LoadMoreItemsAsync();

ToCollectionAsync 또는 ToCollection을 호출하여 만들어진 컬렉션을 사용하는 경우 UI 컨트롤에 바인딩할 수 있는 컬렉션을 얻게 됩니다.When you use the collection created by calling ToCollectionAsync or ToCollection, you get a collection that can be bound to UI controls. 이 컬렉션은 페이징을 인식합니다.This collection is paging-aware. 이 컬렉션은 네트워크에서 데이터를 로드하므로 가끔 로드가 실패합니다.Since the collection is loading data from the network, loading sometimes fails. 이 오류를 처리하려면 LoadMoreItemsAsync 호출의 결과로 발생한 예외를 처리하도록 MobileServiceIncrementalLoadingCollection에 대한 OnException 메서드를 재정의합니다.To handle such failures, override the OnException method on MobileServiceIncrementalLoadingCollection to handle exceptions resulting from calls to LoadMoreItemsAsync.

테이블에 여러 필드가 있지만 그 중 일부만 컨트롤에 표시하려는 경우를 가정하겠습니다.Consider if your table has many fields but you only want to display some of them in your control. 앞에서 나온 “특정 열 선택” 섹션의 지침에 따라 UI에 표시할 특정 열을 선택할 수 있습니다.You may use the guidance in the preceding section "Select specific columns" to select specific columns to display in the UI.

페이지 크기 변경Change the Page size

Azure Mobile Apps는 기본적으로 요청당 최대 50개의 항목을 반환합니다.Azure Mobile Apps returns a maximum of 50 items per request by default. 클라이언트와 서버 모두에서 최대 페이지 크기를 늘려 페이징 크기를 변경할 수 있습니다.You can change the paging size by increasing the maximum page size on both the client and server. 요청된 페이지 크기를 늘리려면 PullAsync()를 사용하는 경우 PullOptions를 지정합니다.To increase the requested page size, specify PullOptions when using PullAsync():

PullOptions pullOptions = new PullOptions
    {
        MaxPageSize = 100
    };

서버 내에서 PageSize 를 100보다 크거나 같게 지정했다고 가정할 경우 각 요청에서 최대 100개의 항목을 반환합니다.Assuming you have made the PageSize equal to or greater than 100 within the server, a request returns up to 100 items.

오프라인 데이터 작업Work with Offline Tables

오프 라인 테이블은 오프 라인일 때 사용 하기 위해 로컬 SQLite 저장소에서 저장소 데이터를 사용 합니다.Offline tables use a local SQLite store to store data for use when offline. 모든 테이블 작업은 원격 서버 저장소 대신 로컬 SQLite 저장소에 대해 수행 됩니다.All table operations are done against the local SQLite store instead of the remote server store. 오프라인 테이블을 만들려면, 먼저 프로젝트를 준비합니다.To create an offline table, first prepare your project:

  1. Visual Studio에서 솔루션 > 솔루션에 대한 NuGet 패키지 관리... 를 마우스 오른쪽 단추로 클릭한 후 솔루션의 모든 프로젝트에서 Microsoft.Azure.Mobile.Client.SQLiteStore NuGet 패키지를 검색하고 설치합니다.In Visual Studio, right-click the solution > Manage NuGet Packages for Solution..., then search for and install the Microsoft.Azure.Mobile.Client.SQLiteStore NuGet package for all projects in the solution.

  2. (선택 사항) Windows 디바이스를 지원하려면 다음 SQLite 런타임 패키지 중 하나를 설치합니다.(Optional) To support Windows devices, install one of the following SQLite runtime packages:

  3. (선택 사항).(Optional). Windows 디바이스의 경우, 참조 > 참조 추가... , Windows 폴더 > 확장을 펼친 후, Visual C++ 2013 Runtime for Windows SDK와 함께 해당 SQLite for Windows SDK를 사용하도록 설정합니다.For Windows devices, click References > Add Reference..., expand the Windows folder > Extensions, then enable the appropriate SQLite for Windows SDK along with the Visual C++ 2013 Runtime for Windows SDK. SQLite SDK 이름은 Windows 플랫폼마다 약간 다릅니다.The SQLite SDK names vary slightly with each Windows platform.

테이블 참조를 만들기 전에, 로컬 저장소를 준비해야 합니다.Before a table reference can be created, the local store must be prepared:

var store = new MobileServiceSQLiteStore(Constants.OfflineDbPath);
store.DefineTable<TodoItem>();

//Initializes the SyncContext using the default IMobileServiceSyncHandler.
await this.client.SyncContext.InitializeAsync(store);

클라이언트를 만든 후 저장소 초기화는 일반적으로 즉시 이루어집니다.Store initialization is normally done immediately after the client is created. OfflineDbPath는 모든 플랫폼에서 사용하기에 적합한 이름이어야 합니다.The OfflineDbPath should be a filename suitable for use on all platforms that you support. 경로가 정규화 된 경로인 경우 (즉, 슬래시로 시작), 해당 경로를 사용 합니다.If the path is a fully qualified path (that is, it starts with a slash), then that path is used. 경로가 정규화되지 않은 경우 파일은 플랫폼 특정 위치에 배치됩니다.If the path is not fully qualified, the file is placed in a platform-specific location.

  • IOS 및 Android 디바이스에 대한 기본 경로는 "개인 파일" 폴더입니다.For iOS and Android devices, the default path is the "Personal Files" folder.
  • Windows 디바이스에 대한 기본 경로는 애플리케이션별 "AppData" 폴더입니다.For Windows devices, the default path is the application-specific "AppData" folder.

GetSyncTable<> 메서드를 사용하여 테이블 참조를 가져올 수 있습니다.A table reference can be obtained using the GetSyncTable<> method:

var table = client.GetSyncTable<TodoItem>();

오프라인 테이블을 사용하여 인증할 필요가 없습니다.You do not need to authenticate to use an offline table. 백 엔드 서비스와 통신하는 경우 인증 해야 합니다.You only need to authenticate when you are communicating with the backend service.

오프라인 테이블 동기화Syncing an Offline Table

기본적으로 오프라인 테이블은 백 엔드와 동기화되지 않습니다.Offline tables are not synchronized with the backend by default. 동기화는 두 부분으로 분할됩니다.Synchronization is split into two pieces. 새 항목 다운로드에서 별도로 변경 내용을 푸시할 수 있습니다.You can push changes separately from downloading new items. 다음은 일반적인 동기화 메서드입니다.Here is a typical sync method:

public async Task SyncAsync()
{
    ReadOnlyCollection<MobileServiceTableOperationError> syncErrors = null;

    try
    {
        await this.client.SyncContext.PushAsync();

        await this.todoTable.PullAsync(
            //The first parameter is a query name that is used internally by the client SDK to implement incremental sync.
            //Use a different query name for each unique query in your program
            "allTodoItems",
            this.todoTable.CreateQuery());
    }
    catch (MobileServicePushFailedException exc)
    {
        if (exc.PushResult != null)
        {
            syncErrors = exc.PushResult.Errors;
        }
    }

    // Simple error/conflict handling. A real application would handle the various errors like network conditions,
    // server conflicts and others via the IMobileServiceSyncHandler.
    if (syncErrors != null)
    {
        foreach (var error in syncErrors)
        {
            if (error.OperationKind == MobileServiceTableOperationKind.Update && error.Result != null)
            {
                //Update failed, reverting to server's copy.
                await error.CancelAndUpdateItemAsync(error.Result);
            }
            else
            {
                // Discard local change.
                await error.CancelAndDiscardItemAsync();
            }

            Debug.WriteLine(@"Error executing sync operation. Item: {0} ({1}). Operation discarded.", error.TableName, error.Item["id"]);
        }
    }
}

PullAsync에 대한 첫 번째 인수가 null인 경우, 증분 동기화가 사용되지 않습니다.If the first argument to PullAsync is null, then incremental sync is not used. 각 동기화 작업은 모든 레코드를 가져옵니다.Each sync operation retrieves all records.

SDK는 레코드를 끌어오기 전에 암시적 PushAsync()을(를) 수행합니다.The SDK performs an implicit PushAsync() before pulling records.

PullAsync() 메서드에서 충돌 처리가 발생합니다.Conflict handling happens on a PullAsync() method. 온라인 테이블과 같은 방식으로 충돌을 처리할 수 있습니다.You can deal with conflicts in the same way as online tables. 충돌은 삽입, 업데이트 또는 삭제하는 동안 이를 대신하여 PullAsync()이 호출될 때 충돌이 생성됩니다.The conflict is produced when PullAsync() is called instead of during the insert, update, or delete. 여러 충돌이 발생하는 경우 단일 MobileServicePushFailedException에 함께 포함됩니다.If multiple conflicts happen, they are bundled into a single MobileServicePushFailedException. 각 오류를 개별적으로 처리합니다.Handle each failure separately.

사용자 지정 API 작업Work with a custom API

사용자 지정 API는 삽입, 업데이트, 삭제 또는 읽기 작업에 매핑되지 않는 서버 기능을 노출하는 사용자 지정 엔드포인트를 정의할 수 있게 합니다.A custom API enables you to define custom endpoints that expose server functionality that does not map to an insert, update, delete, or read operation. 사용자 지정 API를 사용하면 HTTP 메시지 헤더 읽기와 설정 및 JSON 이외의 메시지 본문 형식 정의를 비롯하여 더 효율적으로 메시징을 제어할 수 있습니다.By using a custom API, you can have more control over messaging, including reading and setting HTTP message headers and defining a message body format other than JSON.

클라이언트에서 InvokeApiAsync 메서드 중 하나를 호출하여 사용자 지정 API를 호출합니다.You call a custom API by calling one of the InvokeApiAsync methods on the client. 예를 들어 다음 코드 줄은 백 엔드에서 completeAll API로 POST 요청을 보냅니다.For example, the following line of code sends a POST request to the completeAll API on the backend:

var result = await client.InvokeApiAsync<MarkAllResult>("completeAll", System.Net.Http.HttpMethod.Post, null);

이 양식은 형식화된 메서드 호출이며 MarkAllResult 반환 형식을 정의해야 합니다.This form is a typed method call and requires that the MarkAllResult return type is defined. 형식화된 메서드와 형식화되지 않은 메서드가 모두 지원됩니다.Both typed and untyped methods are supported.

InvokeApiAsync() 메소드는 API가 '/'로 시작하는 경우를 제외하고 호출하려는 API 앞에 '/api/'를 추가합니다.The InvokeApiAsync() method prepends '/api/' to the API that you wish to call unless the API starts with a '/'. 다음은 그 예입니다.For example:

  • InvokeApiAsync("completeAll",...) - 백 엔드에서 /api/completeAll 호출InvokeApiAsync("completeAll",...) calls /api/completeAll on the backend
  • InvokeApiAsync("/.auth/me",...) - 백 엔드에서 /.auth/me 호출InvokeApiAsync("/.auth/me",...) calls /.auth/me on the backend

InvokeApiAsync를 사용하여 Azure Mobile Apps로 정의되지 않은 WebAPI를 포함한 WebAPI를 호출할 수 있습니다.You can use InvokeApiAsync to call any WebAPI, including those WebAPIs that are not defined with Azure Mobile Apps. InvokeApiAsync()를 사용할 경우 인증 헤더를 포함한 적합한 헤더가 요청과 함께 전송됩니다.When you use InvokeApiAsync(), the appropriate headers, including authentication headers, are sent with the request.

사용자 인증Authenticate users

Mobile Apps는 Facebook, Google, Microsoft 계정, Twitter 및 Azure Active Directory와 같이 다양한 외부 ID 공급자를 사용하여 앱 사용자의 인증 및 권한 부여를 지원합니다.Mobile Apps supports authenticating and authorizing app users using various external identity providers: Facebook, Google, Microsoft Account, Twitter, and Azure Active Directory. 테이블에 대해 사용 권한을 설정하여 특정 작업을 위한 액세스를 인증된 사용자로만 제한할 수 있습니다.You can set permissions on tables to restrict access for specific operations to only authenticated users. 인증된 사용자의 ID를 사용하여 서버 스크립트에 인증 규칙을 구현할 수도 있습니다.You can also use the identity of authenticated users to implement authorization rules in server scripts. 자세한 내용은 앱에 인증 추가자습서를 참조하세요.For more information, see the tutorial Add authentication to your app.

두 가지의 인증 흐름이 지원 됩니다: 클라이언트 관리서버 관리 흐름입니다.Two authentication flows are supported: client-managed and server-managed flow. 서버 관리 흐름의 경우 공급자의 웹 인증 인터페이스를 사용하므로 인증 경험이 가장 단순합니다.The server-managed flow provides the simplest authentication experience, as it relies on the provider's web authentication interface. 클라이언트 관리 흐름의 경우 공급자 특정 디바이스별 SDK를 사용하므로 디바이스 특정 기능을 통해 더욱 강력한 통합이 가능합니다.The client-managed flow allows for deeper integration with device-specific capabilities as it relies on provider-specific device-specific SDKs.

참고

프로덕션 앱에서 클라이언트 관리 흐름을 사용하는 것이 좋습니다.We recommend using a client-managed flow in your production apps.

인증을 설정하려면 하나 이상의 ID 공급자로 앱을 등록해야 합니다.To set up authentication, you must register your app with one or more identity providers. ID 공급자는 앱의 클라이언트 ID 및 클라이언트 암호를 생성합니다.The identity provider generates a client ID and a client secret for your app. 그러면 Azure App Service 인증/권한 부여를 사용할 수 있도록 백 엔드에서 이러한 값이 설정됩니다.These values are then set in your backend to enable Azure App Service authentication/authorization. 자세한 내용은 앱에 인증 추가자습서의 자세한 지침을 따르세요.For more information, follow the detailed instructions in the tutorial Add authentication to your app.

이 섹션에서 다루는 토픽은 다음과 같습니다.The following topics are covered in this section:

클라이언트 관리 인증Client-managed authentication

앱이 독립적으로 ID 공급자에 연결한 후 반환된 토큰을 백 엔드로 로그인하는 동안 제공할 수도 있습니다.Your app can independently contact the identity provider and then provide the returned token during login with your backend. 이 클라이언트 흐름을 사용하면 단일 로그온 환경을 사용자에게 제공하거나 ID 공급자로부터 더 많은 사용자 데이터를 검색할 수 있습니다.This client flow enables you to provide a single sign-on experience for users or to retrieve additional user data from the identity provider. 클라이언트 흐름 인증은 ID 공급자 SDK가 UX 느낌을 그대로 제공하고 추가 사용자 지정을 허용하기에 서버 흐름보다 선호도가 높습니다.Client flow authentication is preferred to using a server flow as the identity provider SDK provides a more native UX feel and allows for additional customization.

다음 클라이언트 흐름 인증 패턴에 대한 예제가 제공됩니다.Examples are provided for the following client-flow authentication patterns:

Active Directory 인증 라이브러리를 사용하여 사용자 인증Authenticate users with the Active Directory Authentication Library

Azure Active Directory 인증을 사용하여 클라이언트에서 사용자 인증을 시작하려면 Active Directory 인증 라이브러리(ADAL)를 사용할 수 있습니다.You can use the Active Directory Authentication Library (ADAL) to initiate user authentication from the client using Azure Active Directory authentication.

  1. 다음으로 Active Directory 로그인에 대한 App Service를 구성하는 방법 자습서를 수행하여 AAD 로그인에 모바일 앱 백 엔드를 구성합니다.Configure your mobile app backend for AAD sign-on by following the How to configure App Service for Active Directory login tutorial. 네이티브 클라이언트 애플리케이션을 등록하는 선택적 단계를 완료해야 합니다.Make sure to complete the optional step of registering a native client application.

  2. Visual Studio 또는 Xamarin Studio에서 프로젝트를 열고 Microsoft.IdentityModel.Clients.ActiveDirectory NuGet 패키지에 참조를 추가합니다.In Visual Studio or Xamarin Studio, open your project and add a reference to the Microsoft.IdentityModel.Clients.ActiveDirectory NuGet package. 검색할 때 시험판 버전을 포함합니다.When searching, include pre-release versions.

  3. 사용하는 플랫폼에 따라 애플리케이션에 다음 코드를 추가합니다.Add the following code to your application, according to the platform you are using. 각각에서 다음과 같이 대체합니다.In each, make the following replacements:

    • INSERT-AUTHORITY-HERE를 애플리케이션이 프로비전된 테넌트의 이름으로 바꿉니다.Replace INSERT-AUTHORITY-HERE with the name of the tenant in which you provisioned your application. 형식은 https://login.microsoftonline.com/contoso.onmicrosoft.com 이어야 합니다.The format should be https://login.microsoftonline.com/contoso.onmicrosoft.com. 이 값은 Azure 포털의 Azure Active Directory에 있는 도메인 탭에서 복사할 수 있습니다.This value can be copied from the Domain tab in your Azure Active Directory in the Azure portal.

    • INSERT-RESOURCE-ID-HERE 를 모바일 앱 백 엔드에 대한 클라이언트 ID로 바꿉니다.Replace INSERT-RESOURCE-ID-HERE with the client ID for your mobile app backend. 포털의 Azure Active Directory 설정에 있는 고급 탭에서 클라이언트 ID를 가져올 수 있습니다.You can obtain the client ID from the Advanced tab under Azure Active Directory Settings in the portal.

    • INSERT-CLIENT-ID-HERE를 네이티브 클라이언트 애플리케이션에서 복사한 클라이언트 ID로 바꿉니다.Replace INSERT-CLIENT-ID-HERE with the client ID you copied from the native client application.

    • HTTPS 체계를 사용하여 INSERT-REDIRECT-URI-HERE 를 사이트의 /.auth/login/done 엔드포인트로 바꿉니다.Replace INSERT-REDIRECT-URI-HERE with your site's /.auth/login/done endpoint, using the HTTPS scheme. 이 값은 https://contoso.azurewebsites.net/.auth/login/done 과 비슷해야 합니다.This value should be similar to https://contoso.azurewebsites.net/.auth/login/done.

      각 플랫폼에 필요한 코드는 다음과 같습니다.The code needed for each platform follows:

      Windows:Windows:

      private MobileServiceUser user;
      private async Task AuthenticateAsync()
      {
      
         string authority = "INSERT-AUTHORITY-HERE";
         string resourceId = "INSERT-RESOURCE-ID-HERE";
         string clientId = "INSERT-CLIENT-ID-HERE";
         string redirectUri = "INSERT-REDIRECT-URI-HERE";
         while (user == null)
         {
             string message;
             try
             {
                 AuthenticationContext ac = new AuthenticationContext(authority);
                 AuthenticationResult ar = await ac.AcquireTokenAsync(resourceId, clientId,
                     new Uri(redirectUri), new PlatformParameters(PromptBehavior.Auto, false) );
                 JObject payload = new JObject();
                 payload["access_token"] = ar.AccessToken;
                 user = await App.MobileService.LoginAsync(
                     MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
                 message = string.Format("You are now logged in - {0}", user.UserId);
             }
             catch (InvalidOperationException)
             {
                 message = "You must log in. Login Required";
             }
             var dialog = new MessageDialog(message);
             dialog.Commands.Add(new UICommand("OK"));
             await dialog.ShowAsync();
         }
      }
      

      Xamarin.iOSXamarin.iOS

      private MobileServiceUser user;
      private async Task AuthenticateAsync(UIViewController view)
      {
      
         string authority = "INSERT-AUTHORITY-HERE";
         string resourceId = "INSERT-RESOURCE-ID-HERE";
         string clientId = "INSERT-CLIENT-ID-HERE";
         string redirectUri = "INSERT-REDIRECT-URI-HERE";
         try
         {
             AuthenticationContext ac = new AuthenticationContext(authority);
             AuthenticationResult ar = await ac.AcquireTokenAsync(resourceId, clientId,
                 new Uri(redirectUri), new PlatformParameters(view));
             JObject payload = new JObject();
             payload["access_token"] = ar.AccessToken;
             user = await client.LoginAsync(
                 MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
         }
         catch (Exception ex)
         {
             Console.Error.WriteLine(@"ERROR - AUTHENTICATION FAILED {0}", ex.Message);
         }
      }
      

      Xamarin.AndroidXamarin.Android

      private MobileServiceUser user;
      private async Task AuthenticateAsync()
      {
      
         string authority = "INSERT-AUTHORITY-HERE";
         string resourceId = "INSERT-RESOURCE-ID-HERE";
         string clientId = "INSERT-CLIENT-ID-HERE";
         string redirectUri = "INSERT-REDIRECT-URI-HERE";
         try
         {
             AuthenticationContext ac = new AuthenticationContext(authority);
             AuthenticationResult ar = await ac.AcquireTokenAsync(resourceId, clientId,
                 new Uri(redirectUri), new PlatformParameters(this));
             JObject payload = new JObject();
             payload["access_token"] = ar.AccessToken;
             user = await client.LoginAsync(
                 MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, payload);
         }
         catch (Exception ex)
         {
             AlertDialog.Builder builder = new AlertDialog.Builder(this);
             builder.SetMessage(ex.Message);
             builder.SetTitle("You must log in. Login Required");
             builder.Create().Show();
         }
      }
      protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
      {
      
         base.OnActivityResult(requestCode, resultCode, data);
         AuthenticationAgentContinuationHelper.SetAuthenticationAgentContinuationEventArgs(requestCode, resultCode, data);
      }
      

Facebook 또는 Google의 토큰을 사용하는 Single Sign-OnSingle Sign-On using a token from Facebook or Google

다음과 같은 Facebook 또는 Google용 코드 조각에 나온 대로 클라이언트 흐름을 사용할 수 있습니다.You can use the client flow as shown in this snippet for Facebook or Google.

var token = new JObject();
// Replace access_token_value with actual value of your access token obtained
// using the Facebook or Google SDK.
token.Add("access_token", "access_token_value");

private MobileServiceUser user;
private async Task AuthenticateAsync()
{
    while (user == null)
    {
        string message;
        try
        {
            // Change MobileServiceAuthenticationProvider.Facebook
            // to MobileServiceAuthenticationProvider.Google if using Google auth.
            user = await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);
            message = string.Format("You are now logged in - {0}", user.UserId);
        }
        catch (InvalidOperationException)
        {
            message = "You must log in. Login Required";
        }

        var dialog = new MessageDialog(message);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();
    }
}

서버 관리 인증Server-managed authentication

ID 공급자를 등록하고 나면, 공급자의 MobileServiceAuthenticationProvider 값을 사용하여 MobileServiceClient의 LoginAsync 메서드를 호출합니다.Once you have registered your identity provider, call the LoginAsync method on the [MobileServiceClient] with the MobileServiceAuthenticationProvider value of your provider. 예를 들어 다음 코드는 Facebook을 사용한 서버 흐름 로그인을 시작합니다.For example, the following code initiates a server flow sign-in by using Facebook.

private MobileServiceUser user;
private async System.Threading.Tasks.Task Authenticate()
{
    while (user == null)
    {
        string message;
        try
        {
            user = await client
                .LoginAsync(MobileServiceAuthenticationProvider.Facebook);
            message =
                string.Format("You are now logged in - {0}", user.UserId);
        }
        catch (InvalidOperationException)
        {
            message = "You must log in. Login Required";
        }

        var dialog = new MessageDialog(message);
        dialog.Commands.Add(new UICommand("OK"));
        await dialog.ShowAsync();
    }
}

Facebook 이외의 ID 공급자를 사용하는 경우, MobileServiceAuthenticationProvider 값을 공급자에 대한 값으로 변경합니다.If you are using an identity provider other than Facebook, change the value of MobileServiceAuthenticationProvider to the value for your provider.

서버 흐름에서 Azure App Service는 선택한 공급자의 로그인 페이지를 표시하여 OAuth 인증 흐름을 관리합니다.In a server flow, Azure App Service manages the OAuth authentication flow by displaying the sign-in page of the selected provider. ID 공급자가 결과를 반환하면 Azure App Service가 App Service 인증 토큰을 생성합니다.Once the identity provider returns, Azure App Service generates an App Service authentication token. LoginAsync 메서드는 MobileServiceUser를 반환하며, 여기서 인증된 사용자의 UserIdMobileServiceAuthenticationToken이 JWT(JSON web token)로 제공됩니다.The LoginAsync method returns a MobileServiceUser, which provides both the UserId of the authenticated user and the MobileServiceAuthenticationToken, as a JSON web token (JWT). 이 토큰은 캐시했다가 만료될 때까지 다시 사용할 수 있습니다.This token can be cached and reused until it expires. 자세한 내용은 인증 토큰 캐시를 참조하십시오.For more information, see Caching the authentication token.

인증 토큰 캐시Caching the authentication token

경우에 따라 공급자의 인증 토큰을 저장하여 첫 번째 인증 후 login 메서드에 대한 호출을 방지할 수 있습니다.In some cases, the call to the login method can be avoided after the first successful authentication by storing the authentication token from the provider. Microsoft Store 및 UWP 앱은 PasswordVault 를 사용하여 다음과 같이 성공적인 로그인 후 현재 인증 토큰을 캐시할 수 있습니다.Microsoft Store and UWP apps can use PasswordVault to cache the current authentication token after a successful sign-in, as follows:

await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook);

PasswordVault vault = new PasswordVault();
vault.Add(new PasswordCredential("Facebook", client.currentUser.UserId,
    client.currentUser.MobileServiceAuthenticationToken));

UserId 값은 자격 증명의 사용자 이름으로 저장되며 토큰은 암호로 저장됩니다.The UserId value is stored as the UserName of the credential and the token is the stored as the Password. 이후 시작 시 캐시된 자격 증명에 대한 PasswordVault 를 확인할 수 있습니다.On subsequent start-ups, you can check the PasswordVault for cached credentials. 다음 예제는 검색될 때 캐시된 자격 증명을 사용하고 그렇지 않으면 백 엔드로 인증을 다시 시도합니다.The following example uses cached credentials when they are found, and otherwise attempts to authenticate again with the backend:

// Try to retrieve stored credentials.
var creds = vault.FindAllByResource("Facebook").FirstOrDefault();
if (creds != null)
{
    // Create the current user from the stored credentials.
    client.currentUser = new MobileServiceUser(creds.UserName);
    client.currentUser.MobileServiceAuthenticationToken =
        vault.Retrieve("Facebook", creds.UserName).Password;
}
else
{
    // Regular login flow and cache the token as shown above.
}

사용자를 로그아웃할 때 다음과 같이 저장된 자격 증명도 삭제해야 합니다.When you sign out a user, you must also remove the stored credential, as follows:

client.Logout();
vault.Remove(vault.Retrieve("Facebook", client.currentUser.UserId));

Xamarin 앱은 Xamarin.Auth API를 사용하여 Account 개체에 자격 증명을 안전하게 저장합니다.Xamarin apps use the Xamarin.Auth APIs to securely store credentials in an Account object. 이러한 API 사용의 예제는 ContosoMoments 사진 공유 샘플에서 AuthStore.cs 코드 파일을 참조하세요.For an example of using these APIs, see the AuthStore.cs code file in the ContosoMoments photo sharing sample.

클라이언트 관리 인증을 사용하는 경우 Facebook 또는 Twitter와 같은 공급자로부터 얻은 액세스 토큰을 캐시할 수도 있습니다.When you use client-managed authentication, you can also cache the access token obtained from your provider such as Facebook or Twitter. 다음과 같이 백 엔드에서 새 인증 토큰을 요청하기 위해 이 토큰을 제공할 수 있습니다.This token can be supplied to request a new authentication token from the backend, as follows:

var token = new JObject();
// Replace <your_access_token_value> with actual value of your access token
token.Add("access_token", "<your_access_token_value>");

// Authenticate using the access token.
await client.LoginAsync(MobileServiceAuthenticationProvider.Facebook, token);

푸시 알림Push Notifications

다음 토픽에서는 푸시 알림에 대해 다룹니다.The following topics cover Push Notifications:

방법: 푸시 알림 등록How to: Register for Push Notifications

Mobile Apps 클라이언트를 사용하면 Azure Notification Hubs로 푸시 알림을 등록할 수 있습니다.The Mobile Apps client enables you to register for push notifications with Azure Notification Hubs. 등록할 때 플랫폼 특정 푸시 알림 서비스(PNS)에서 구하는 핸들을 가져옵니다.When registering, you obtain a handle that you obtain from the platform-specific Push Notification Service (PNS). 그런 다음 등록을 만들 때 태그와 함께 이 값을 제공합니다.You then provide this value along with any tags when you create the registration. 다음 코드는 Windows 알림 서비스(WNS)를 통한 푸시 알림에 Windows 앱을 등록합니다.The following code registers your Windows app for push notifications with the Windows Notification Service (WNS):

private async void InitNotificationsAsync()
{
    // Request a push notification channel.
    var channel = await PushNotificationChannelManager.CreatePushNotificationChannelForApplicationAsync();

    // Register for notifications using the new channel.
    await MobileService.GetPush().RegisterNativeAsync(channel.Uri, null);
}

WNS에 푸시하는 경우, Microsoft Store 패키지 SID를 가져와야 합니다.If you are pushing to WNS, then you MUST obtain a Microsoft Store package SID. 템플릿 등록 방법을 비롯하여 Windows 앱에 대한 자세한 내용은 앱에 푸시 알림 추가를 참조하세요.For more information on Windows apps, including how to register for template registrations, see Add push notifications to your app.

클라이언트에서 태그 요청은 지원되지 않습니다.Requesting tags from the client is not supported. 태그 요청은 등록에서 자동으로 삭제됩니다.Tag Requests are silently dropped from registration. 태그로 디바이스를 등록하려는 경우 사용자를 대신해 Notification Hubs API를 사용하여 등록을 수행하는 사용자 지정 API를 만듭니다.If you wish to register your device with tags, create a Custom API that uses the Notification Hubs API to perform the registration on your behalf. RegisterNativeAsync() 메서드 대신에 사용자 지정 API를 호출합니다.Call the Custom API instead of the RegisterNativeAsync() method.

방법: Microsoft Store 패키지 SID 가져오기How to: Obtain a Microsoft Store package SID

Microsoft Store 앱에서 푸시 알림 사용에 패키지 SID가 필요합니다.A package SID is needed for enabling push notifications in Microsoft Store apps. 패키지 SID를 수신하려면 Microsoft Store에 애플리케이션을 등록합니다.To receive a package SID, register your application with the Microsoft Store.

이 값을 가져오려면To obtain this value:

  1. Visual Studio 솔루션 탐색기에서 Microsoft Store 앱 프로젝트를 마우스 오른쪽 단추로 클릭하고, 스토어 > 스토어와 앱을 연결... 을 클릭합니다.In Visual Studio Solution Explorer, right-click the Microsoft Store app project, click Store > Associate App with the Store....
  2. 마법사에서 다음을 클릭하고, Microsoft 계정으로 로그인하고, 새로운 앱 이름 예약에서 앱 이름을 입력한 후 예약을 클릭합니다.In the wizard, click Next, sign in with your Microsoft account, type a name for your app in Reserve a new app name, then click Reserve.
  3. 앱을 등록한 후에는 앱 이름을 선택하고 다음, 연결을 차례로 클릭합니다.After the app registration is successfully created, select the app name, click Next, and then click Associate.
  4. Microsoft 계정을 사용하여 Windows 개발자 센터 에 로그인합니다.Log in to the Windows Dev Center using your Microsoft Account. 내 앱에서 방금 만든 앱 등록을 클릭합니다.Under My apps, click the app registration you created.
  5. 앱 관리 > 앱 ID를 클릭한 다음, 아래로 스크롤하여 패키지 SID를 찾습니다.Click App management > App identity, and then scroll down to find your Package SID.

패키지 SID를 URI로 처리하여 다양하게 사용할 수 있으며, 이 경우 ms-app:// 를 스키마로 사용해야 합니다.Many uses of the package SID treat it as a URI, in which case you need to use ms-app:// as the scheme. 이 값을 접두사로 연결하여 만든 패키지 SID의 버전을 기록합니다.Make note of the version of your package SID formed by concatenating this value as a prefix.

iOS 또는 Android 플랫폼에서 실행되는 앱을 등록하려면 Xamarin 앱에 추가 코드가 필요합니다.Xamarin apps require some additional code to be able to register an app running on the iOS or Android platforms. 자세한 내용은 사용하는 플랫폼에 대한 토픽을 참조하세요.For more information, see the topic for your platform:

방법: 플랫폼 간 알림을 보내기 위해 푸시 템플릿 등록How to: Register push templates to send cross-platform notifications

템플릿을 등록하려면 다음과 같이 템플릿으로 RegisterAsync() 메서드를 사용합니다.To register templates, use the RegisterAsync() method with the templates, as follows:

JObject templates = myTemplates();
MobileService.GetPush().RegisterAsync(channel.Uri, templates);

템플릿은 JObject 형식이어야 하며 다음 JSON 형식으로 여러 템플릿을 포함할 수 있습니다.Your templates should be JObject types and can contain multiple templates in the following JSON format:

public JObject myTemplates()
{
    // single template for Windows Notification Service toast
    var template = "<toast><visual><binding template=\"ToastText01\"><text id=\"1\">$(message)</text></binding></visual></toast>";

    var templates = new JObject
    {
        ["generic-message"] = new JObject
        {
            ["body"] = template,
            ["headers"] = new JObject
            {
                ["X-WNS-Type"] = "wns/toast"
            },
            ["tags"] = new JArray()
        },
        ["more-templates"] = new JObject {...}
    };
    return templates;
}

또한 RegisterAsync() 메서드는 보조 타일을 허용할 수 있습니다.The method RegisterAsync() also accepts Secondary Tiles:

MobileService.GetPush().RegisterAsync(string channelUri, JObject templates, JObject secondaryTiles);

보안을 위해 등록하는 동안 모든 태그가 제거됩니다.All tags are stripped away during registration for security. 설치에 태그를 추가하거나 설치 내에 템플릿을 추가하려면 [Azure Mobile Apps에 대해 .NET 백 엔드 서버 SDK로 작업]을 참조하세요.To add tags to installations or templates within installations, see [Work with the .NET backend server SDK for Azure Mobile Apps].

이러한 등록된 템플릿을 활용하여 알림을 보내려면 Notification Hubs API를 참조하세요.To send notifications utilizing these registered templates, refer to the Notification Hubs APIs.

기타 토픽Miscellaneous Topics

방법: 오류 처리How to: Handle errors

백 엔드에서 오류가 발생하는 경우 클라이언트 SDK가 MobileServiceInvalidOperationException을 발생시킵니다.When an error occurs in the backend, the client SDK raises a MobileServiceInvalidOperationException. 다음 예제에서는 백 엔드에서 반환되는 예외를 처리하는 방법을 보여 줍니다.The following example shows how to handle an exception that is returned by the backend:

private async void InsertTodoItem(TodoItem todoItem)
{
    // This code inserts a new TodoItem into the database. When the operation completes
    // and App Service has assigned an Id, the item is added to the CollectionView
    try
    {
        await todoTable.InsertAsync(todoItem);
        items.Add(todoItem);
    }
    catch (MobileServiceInvalidOperationException e)
    {
        // Handle error
    }
}

오류 조건을 처리하는 또 다른 예는 Mobile Apps 파일 샘플에서 찾을 수 있습니다.Another example of dealing with error conditions can be found in the Mobile Apps Files Sample. LoggingHandler 예제는 백 엔드에 대해 생성되는 요청을 기록하는 로깅 대리자 처리기를 제공합니다.The LoggingHandler example provides a logging delegate handler to log the requests being made to the backend.

방법: 요청 헤더 사용자 지정How to: Customize request headers

특정 앱 시나리오를 지원하려면 모바일 앱 백 엔드와의 통신을 사용자 지정해야 할 수 있습니다.To support your specific app scenario, you might need to customize communication with the Mobile App backend. 예를들어, 모든 보내는 요청이나 변경 응답 상태 코드에 사용자 지정 헤더를 추가하고자 할 수 있습니다.For example, you may want to add a custom header to every outgoing request or even change responses status codes. 다음 예제와 같이 사용자 지정 DelegatingHandler를 사용할 수 있습니다.You can use a custom DelegatingHandler, as in the following example:

public async Task CallClientWithHandler()
{
    MobileServiceClient client = new MobileServiceClient("AppUrl", new MyHandler());
    IMobileServiceTable<TodoItem> todoTable = client.GetTable<TodoItem>();
    var newItem = new TodoItem { Text = "Hello world", Complete = false };
    await todoTable.InsertAsync(newItem);
}

public class MyHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage>
        SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        // Change the request-side here based on the HttpRequestMessage
        request.Headers.Add("x-my-header", "my value");

        // Do the request
        var response = await base.SendAsync(request, cancellationToken);

        // Change the response-side here based on the HttpResponseMessage

        // Return the modified response
        return response;
    }
}