Microsoft Azureバックエンド

これまでのところ、資料が非常に少ない別のトピックについてお話したいと思います。 これは、Microsoft Azureモバイルサービスに基づいたバックエンドの開発に関するものです。 このテーマに関する入門記事は多数ありますが、従来のTodoItemsの例(紹介の大部分はこれに限定されています)には、大規模プロジェクトの潜在的な問題が含まれていることに気付くのは簡単です。



デモプロジェクトの主な欠点は、EntityDomainManagerの機能にあります。これにより、ORMで使用されるJSONを介して同じクラスを送信することが強制されます(Entity Frameworkを使用するとしましょう)。 まず、直列化可能クラスはEntityDataから継承する必要があります。データベースには必要で便利なフィールドが常にあるわけではありません(たとえば、文字列で識別されますが、文字列に常にインデックスを構築するのは良いことです)。 第二に、EFは、コードファーストスキームのクラス継承のみを処理します。これは、現在のバージョンのストアドプロシージャのマッピングを提供しません(再び、データベースパフォーマンスの問題)。 そして最後に、ロジック層はどこにありますか? 結局のところ、データベースの構造は外部インターフェイスと必ずしも同一ではありません。



これらの理由から、別の方法を検討してください。 また、基本については紹介しませんが、読者はすでに簡単な紹介に精通していることを前提としています。



したがって、上記の欠点を克服するために、EntityDomainManagerをMappedEntityDomainManagerに置き換えます。 後者は、NuGetを介して簡単に見つけることができるAutoMapperモジュールの使用に焦点を当てています。さらに、このモジュールはAzure Mobile Servicesプロジェクトの一部です。 WebApiConfig.csファイルでその機能を使用する必要があります。



例として、TodoItemsプロジェクト全体を変換し、データベースの操作はモデルに基づいたEFを介して最初に実行されると想定します。 対応するORMモデルでは、エンティティクラスを表現とストアドプロシージャにマッピングし、ストアドプロシージャを呼び出すことができます。 EFを使用する場合、ストアドプロシージャを介したデータの単純な選択でさえ、少なくとも2倍の速さで発生します。 データベースとEF機能の検討は、このMicrsoft Azureの説明の範囲外であり、この場合、プロジェクトで作成されたコンテキストが使用されますが、置き換え可能です。



EntityDomainManagerとは対照的に、MappedEntityDomainManagerクラスは抽象的であるため、単に行を置き換える方法はないという事実に注意してください。



DomainManager = new EntityDomainManager<TodoItem>(context, Request, Services);
      
      





MappedEntityDomainManagerクラスのインスタンスを作成します。 したがって、TodoItemsDomainManagerクラスを作成します。 しかしその前に、アプリケーションの異なるレイヤーのクラス間の混乱を避けるために、データ変換クラス(またはシリアル化クラス)をTodoItemDTOという名前で示します。 継承されたクラスのもう1つの汎用パラメーターは、データベースマッピングクラスです。このクラスでは、データベースインデックスの最適なオプションとして、識別に数値を使用します。 その結果、クラスは次のようになります。



  public class TodoItemsDomainManager : MappedEntityDomainManager<TodoItemDTO, TodoItemDA> { private readonly AzureBackendDemoContext _context; public TodoItemsDomainManager(AzureBackendDemoContext context, HttpRequestMessage request, ApiServices services) : base(context, request, services) { _context = context; } public override System.Threading.Tasks.Task<bool> DeleteAsync(string id) { return base.DeleteItemAsync(id); } public override System.Web.Http.SingleResult<TodoItemDTO> Lookup(string id) { return base.LookupEntity(c => c.Id.ToString() == id); } public override System.Threading.Tasks.Task<TodoItemDTO> UpdateAsync(string id, System.Web.Http.OData.Delta<TodoItemDTO> patch) { return base.UpdateEntityAsync(patch, id); } }
      
      





以下に、実装の最も単純な例を示しますが、元のバージョンとは異なり、さらなる開発にはるかに適合しています。 TodoItemsDomainManagerがクラスTodoItemDTOとTodoItemDAをマップする方法をまだ知らない瞬間が残っています。 したがって、WebApiConfigクラスを見つけて、Registerメソッドに行を追加します。



  Mapper.Initialize(cfg => { cfg.CreateMap<TodoItemDA, TodoItemDTO>(). ForMember(dst => dst.Id, map => map.MapFrom(c => c.Id.ToString())) .ForMember(dst => dst.Text, map => map.MapFrom(c => c.Text)) .ForMember(dst => dst.Complete, map => map.MapFrom(c => c.Complete)); cfg.CreateMap<TodoItemDTO, TodoItemDA>(). ForMember(dst => dst.Id, map => map.MapFrom(c => int.Parse(c.Id))) .ForMember(dst => dst.Text, map => map.MapFrom(c => c.Text)) .ForMember(dst => dst.Complete, map => map.MapFrom(c => c.Complete)); });
      
      





マッピングクラスは必ずしも1対1ではないことに注意してください。 AutoMapperの使用に関する詳細は、このトピックに関する多くの資料があるため、ここでは考慮しません。



次に、テーブルコントローラーでドメインマネージャーを作成するための行を置き換えます。



 DomainManager = new TodoItemsDomainManager(context, Request, Services);
      
      





また、コンテキストクラスとそれに関連付けられたすべてのクラスで、TodoItemDTOをTodoItemDAに置き換えて、このクラスをOnModelCreatingメソッドに登録する必要があります。



 modelBuilder.Entity<TodoItemDA>();
      
      





この例では実際のデータモデルが作成されていないため、DropCreateDatabaseIfModelChangesから継承された元のAzureBackendDemoInitializerクラスが使用されました。 接続文字列を介してデータベースに接続する実際のプロジェクトでは、IDatabaseInitializerインターフェイスを実装することをお勧めします。この場合、次のようになります。



  public class DatabaseModelInitializer : IDatabaseInitializer<SomeDatabaseContext> { public void InitializeDatabase(SomeDatabaseContext context) { context.Set<TodoItemDA>().Load(); } }
      
      





元のサンプルテストデータを使用してプロジェクトを実行し、アドレスにline / tables / TodoItemを追加します。 その結果、リクエストの結果が表示されます。



[{"id":"1","complete":false,"text":"First item"},{"id":"2","complete":false,"text":"Second item"}]







ちょっとした追加として、プロジェクトのフロントエンドの例を示します。 この例を単純化するために、WPFに基づいたWindowsのバージョンが使用されます。 しかし、オペレーティングシステムAndroid、iOS、Windows Phone、Windows RT上のモバイルデバイスでも実装は可能です。 同時に、WPFプロジェクトはAzure Mobile Servicesと互換性があるとは見なされませんが、実際には互換性があるため、NuGetコンソールで次のように入力します。



Install-Package WindowsAzure.MobileServices







次に、これらのリンクをプロジェクトに追加します。 データを受信するクラスを作成しましょう。 クラスの名前によるクエリの場合、TodoItemを呼び出す必要があります。その後、呼び出しは適切なコントローラーになります。 ただし、この名前はデータモデルとデータのアップロードなどのローカルシリアル化クラスの両方を参照できるため、DataTableAttributeを適用し、次のようにクラスを宣言します。



  [DataTable("TodoItem")] public class TodoItemDTO { [CreatedAt] public DateTimeOffset? CreatedAt { get; set; } public string Id { get; set; } [UpdatedAt] public DateTimeOffset? UpdatedAt { get; set; } [Version] public byte[] Version { get; set; } public string Text { get; set; } public bool Complete { get; set; } }
      
      





クエリ行は次のようになります。



  public async Task Load() { MobileServiceClient client = new MobileServiceClient("http://localhost:1146/"); try { IEnumerable<TodoItemDTO> items = await client.GetTable<TodoItemDTO>().ToEnumerableAsync(); _items = items.Select(slo => new TodoItemModel { Complete = slo.Complete, Text = slo.Text }).ToList(); } catch (MobileServiceInvalidOperationException ex) { OnGotError(); } catch (TaskCanceledException ex) { OnGotError(); } }
      
      





サーバーロジックのレイヤーはここでは考慮されませんでしたが、抽象クラスからの継承の使用は、対応するメソッドで必要な論理オブジェクトを呼び出す可能性を示しています。 例として、文字列識別子を数値に置き換える方法を示しました。 ApiControllerを忘れないでください。



当然、名前自体はデスクトップ用ではなく、モバイルデバイス用のバックエンドの目的を表していますが、上記のオペレーティングシステムのPCLでこれらの同じ行を実行できます。 これで、例のソースコードファイルを提供する内容をわかりやすくするために、この例を終了します(例のソースコードが完全に揃っていないチュートリアルは好きではないので、何らかの形で提供できる場合は修正してください)。



All Articles