From edddaab5520fbe2b71c21930f41cdc7aea9d8218 Mon Sep 17 00:00:00 2001 From: Esteban Solano G Date: Fri, 20 Mar 2020 23:36:27 -0600 Subject: [PATCH 1/7] Added CosmosDb write to SignalR --- Serverless/SignalR/.vscode/launch.json | 12 ++++- Serverless/SignalR/.vscode/settings.json | 2 +- Serverless/SignalR/.vscode/tasks.json | 2 +- Serverless/SignalR/HttpGetTrigger.cs | 56 +++++++++--------------- Serverless/SignalR/Shared.MongoDb.cs | 29 ++++++++++++ Serverless/SignalR/SignalRTrigger.cs | 28 +++++++++--- 6 files changed, 84 insertions(+), 45 deletions(-) create mode 100644 Serverless/SignalR/Shared.MongoDb.cs diff --git a/Serverless/SignalR/.vscode/launch.json b/Serverless/SignalR/.vscode/launch.json index 894cbe6..a9c4058 100644 --- a/Serverless/SignalR/.vscode/launch.json +++ b/Serverless/SignalR/.vscode/launch.json @@ -1,6 +1,16 @@ { "version": "0.2.0", - "configurations": [ + "configurations": + [ + { + "name": "Docker .NET Core Attach (Preview)", + "type": "docker", + "request": "attach", + "platform": "netCore", + "sourceFileMap": { + "/src": "${workspaceFolder}" + } + }, { "name": "Attach to .NET Functions", "type": "coreclr", diff --git a/Serverless/SignalR/.vscode/settings.json b/Serverless/SignalR/.vscode/settings.json index 9977b0e..7e4a9ba 100644 --- a/Serverless/SignalR/.vscode/settings.json +++ b/Serverless/SignalR/.vscode/settings.json @@ -1,5 +1,5 @@ { - "azureFunctions.deploySubpath": "bin/Release/netcoreapp3.1/publish", + "azureFunctions.deploySubpath": "bin/Release/netcoreapp3.0/publish", "azureFunctions.projectLanguage": "C#", "azureFunctions.projectRuntime": "~3", "debug.internalConsoleOptions": "neverOpen", diff --git a/Serverless/SignalR/.vscode/tasks.json b/Serverless/SignalR/.vscode/tasks.json index 9ee1b65..a656257 100644 --- a/Serverless/SignalR/.vscode/tasks.json +++ b/Serverless/SignalR/.vscode/tasks.json @@ -59,7 +59,7 @@ "type": "func", "dependsOn": "build", "options": { - "cwd": "${workspaceFolder}/bin/Debug/netcoreapp3.1" + "cwd": "${workspaceFolder}/bin/Debug/netcoreapp3.0" }, "command": "host start", "isBackground": true, diff --git a/Serverless/SignalR/HttpGetTrigger.cs b/Serverless/SignalR/HttpGetTrigger.cs index 3eac4a3..bf2e5e4 100644 --- a/Serverless/SignalR/HttpGetTrigger.cs +++ b/Serverless/SignalR/HttpGetTrigger.cs @@ -9,54 +9,38 @@ using MongoDB.Driver; using Newtonsoft.Json; -namespace Serverless +namespace Serverless { - public static class HttpGetTrigger + public static class HttpGetTrigger { - [FunctionName("HttpGetTrigger")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, - ILogger log = null) + [FunctionName ("HttpGetTrigger")] + public static async Task Run ( + [HttpTrigger (AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req, + ILogger log = null) { - log.LogInformation("C# HTTP trigger function processed a request."); + log.LogInformation ("C# HTTP trigger function processed a request."); bool parsed; - bool displayErrors = bool.TryParse(req.Query["displayErrors"].ToString(), out parsed) && parsed; + bool displayErrors = bool.TryParse (req.Query["displayErrors"].ToString (), out parsed) && parsed; -// string requestBody = await new StreamReader(req.Body).ReadToEndAsync(); -// dynamic data = JsonConvert.DeserializeObject(requestBody); - - try + try { - var connection = Environment.GetEnvironmentVariable("MongoDbConnection"); - var databaseName = Environment.GetEnvironmentVariable("MongoDbDatabase"); - var collectionName = Environment.GetEnvironmentVariable("MongoDbCollection"); - - MongoClientSettings settings = MongoClientSettings.FromUrl( - new MongoUrl(connection) + var collection = Shared.GetDocumentCollection ( + Environment.GetEnvironmentVariable ("MongoDbCollection") ); + var result = await collection.Find (FilterDefinition.Empty) + .ToListAsync (); - settings.SslSettings = new SslSettings() { EnabledSslProtocols = SslProtocols.Tls12 }; - - var mongoClient = new MongoClient(settings); - var client = new MongoClient(connection); - var database = client.GetDatabase(databaseName); - - IMongoCollection collection = database.GetCollection(collectionName); - - var result = await collection.Find(FilterDefinition.Empty) - .ToListAsync(); - - return new OkObjectResult(JsonConvert.SerializeObject(result)); - } - catch (System.Exception ex) + return new OkObjectResult (JsonConvert.SerializeObject (result)); + } + catch (System.Exception ex) { - log.LogInformation("C# HTTP trigger function processed a request."); + log.LogInformation ("C# HTTP trigger function processed a request."); - if (displayErrors){ - return new OkObjectResult(ex.Message); + if (displayErrors) { + return new OkObjectResult (ex.Message); } - return new OkObjectResult("Failed to fetch data"); + return new OkObjectResult ("Failed to fetch data"); } } } diff --git a/Serverless/SignalR/Shared.MongoDb.cs b/Serverless/SignalR/Shared.MongoDb.cs new file mode 100644 index 0000000..acb09ae --- /dev/null +++ b/Serverless/SignalR/Shared.MongoDb.cs @@ -0,0 +1,29 @@ +using System; +using System.Security.Authentication; +using MongoDB.Driver; + +namespace Serverless +{ + public static partial class Shared + { + public static IMongoCollection GetDocumentCollection (string collectionName) + { + var connection = Environment.GetEnvironmentVariable ("MongoDbConnection"); + var databaseName = Environment.GetEnvironmentVariable ("MongoDbDatabase"); + + MongoClientSettings settings = MongoClientSettings.FromUrl ( + new MongoUrl (connection) + ); + + settings.SslSettings = new SslSettings () { EnabledSslProtocols = SslProtocols.Tls12 }; + + var mongoClient = new MongoClient (settings); + var client = new MongoClient (connection); + var database = client.GetDatabase (databaseName); + + IMongoCollection collection = database.GetCollection (collectionName); + + return collection; + } + } +} \ No newline at end of file diff --git a/Serverless/SignalR/SignalRTrigger.cs b/Serverless/SignalR/SignalRTrigger.cs index e1d3ceb..9c7a815 100644 --- a/Serverless/SignalR/SignalRTrigger.cs +++ b/Serverless/SignalR/SignalRTrigger.cs @@ -6,9 +6,13 @@ using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; -using Newtonsoft.Json; using Microsoft.Azure.WebJobs.Extensions.SignalRService; +// Document Storage +using Microsoft.Azure.Documents; +using System.Collections.Generic; +using Newtonsoft.Json; + namespace Serverless { public static class SignalRTrigger @@ -16,14 +20,16 @@ public static class SignalRTrigger // POST http://localhost:7071/api/SignalRTrigger /* { - "Name" : "To-do", - "Description" : "description here" + "Id": "1bc8279b-4813-4ae8-a66b-8cd207f2c310", + "Title": "Do something 2", + "IsCompleted": true } */ [FunctionName("SignalRTrigger")] public static async Task Run( - [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, + [HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] + HttpRequest req, [SignalR(HubName = "broadcast")]IAsyncCollector signalRMessages, ILogger log) { @@ -34,13 +40,23 @@ public static async Task Run( return new BadRequestObjectResult("Please pass a payload to broadcast in the request body."); } + var data = JsonConvert.DeserializeObject(requestBody); + + var documentCollection = Shared.GetDocumentCollection( + Environment.GetEnvironmentVariable("MongoDbCollection") + ); + data.Id = Guid.NewGuid().ToString(); + data._Id = MongoDB.Bson.ObjectId.GenerateNewId(); + + await documentCollection.InsertOneAsync(data); + await signalRMessages.AddAsync(new SignalRMessage() { Target = "notify", - Arguments = new object[] { requestBody } + Arguments = new object[] { data } }); - return new OkResult(); + return new CreatedResult($"/api/HttpGet/{data._Id}", data); } } } \ No newline at end of file From 5474efd773bbec619e0b41c9876932a1d423a57e Mon Sep 17 00:00:00 2001 From: Esteban Solano G Date: Sat, 21 Mar 2020 14:06:30 -0600 Subject: [PATCH 2/7] Updated ToDos for POST --- Shared/Item.cs | 6 +- .../XamarinExplorer.iOS.csproj | 2 + XamarinExplorer/App.xaml.cs | 10 ++-- XamarinExplorer/AppConstants.cs | 2 + XamarinExplorer/Services/IHttpFactory.cs | 4 +- XamarinExplorer/Services/MockDataStore.cs | 13 ++-- .../Services/ToDoItemsRepository.cs | 35 +++++++++++ XamarinExplorer/ViewModels/ListViewModel.cs | 2 +- XamarinExplorer/Views/ItemDetailPage.xaml.cs | 5 +- XamarinExplorer/Views/ItemsPage.xaml | 19 +++--- XamarinExplorer/Views/ItemsPage.xaml.cs | 14 ++--- XamarinExplorer/Views/ToDoListViewModel.cs | 59 +++++++++++++++++++ 12 files changed, 133 insertions(+), 38 deletions(-) create mode 100644 XamarinExplorer/Services/ToDoItemsRepository.cs create mode 100644 XamarinExplorer/Views/ToDoListViewModel.cs diff --git a/Shared/Item.cs b/Shared/Item.cs index fec7b85..7384a88 100644 --- a/Shared/Item.cs +++ b/Shared/Item.cs @@ -5,13 +5,15 @@ namespace Shared { public class Item { - public int Id { get; set; } + public string Id { get; set; } - [JsonProperty("Name")] + [JsonProperty("Title")] public string Text { get; set; } public string Description { get; set; } = "This is the description"; + public bool IsCompleted { get; set; } + [JsonProperty("ListedPrice")] public string Price { get; set; } } diff --git a/XamarinExplorer.iOS/XamarinExplorer.iOS.csproj b/XamarinExplorer.iOS/XamarinExplorer.iOS.csproj index dc88775..4e91895 100644 --- a/XamarinExplorer.iOS/XamarinExplorer.iOS.csproj +++ b/XamarinExplorer.iOS/XamarinExplorer.iOS.csproj @@ -52,6 +52,8 @@ iPhone Developer true Entitlements.plist + 13.2 + None none diff --git a/XamarinExplorer/App.xaml.cs b/XamarinExplorer/App.xaml.cs index d5e5b14..5d11d1c 100644 --- a/XamarinExplorer/App.xaml.cs +++ b/XamarinExplorer/App.xaml.cs @@ -14,10 +14,7 @@ namespace XamarinExplorer { public partial class App : Application { - // HTTPS - public const string WebServiceUrl = AdventureWorksApi.URL_BASE; - - public static bool UseMockDataStore = string.IsNullOrEmpty(WebServiceUrl); + public static bool UseMockDataStore = string.IsNullOrEmpty(AppConstants.WebServiceUrl); public App() { @@ -34,9 +31,10 @@ public App() if (UseMockDataStore) DependencyService.Register, MockDataStore>(); else - DependencyService.Register, Repository>(); + DependencyService.Register, ToDoItemsRepository>(); - MainPage = new NavigationPage(new TabsPage()); + MainPage = new NavigationPage(new ItemsPage()); + //MainPage = new NavigationPage(new TabsPage()); } protected override void OnStart() diff --git a/XamarinExplorer/AppConstants.cs b/XamarinExplorer/AppConstants.cs index a229605..a2a80d0 100644 --- a/XamarinExplorer/AppConstants.cs +++ b/XamarinExplorer/AppConstants.cs @@ -6,6 +6,8 @@ namespace XamarinExplorer { public static class AppConstants { + public const string WebServiceUrl = "https://my-signalr-functions.azurewebsites.net/api/"; + public static string AppCenterSecret { get diff --git a/XamarinExplorer/Services/IHttpFactory.cs b/XamarinExplorer/Services/IHttpFactory.cs index 8107fa0..7b769fb 100644 --- a/XamarinExplorer/Services/IHttpFactory.cs +++ b/XamarinExplorer/Services/IHttpFactory.cs @@ -13,9 +13,9 @@ public class HttpFactory : IHttpFactory public virtual HttpClient GetClient() { var client = new HttpClient(); - if (!string.IsNullOrEmpty(App.WebServiceUrl)) + if (!string.IsNullOrEmpty(AppConstants.WebServiceUrl)) { - client.BaseAddress = new Uri($"{App.WebServiceUrl}/"); + client.BaseAddress = new Uri($"{AppConstants.WebServiceUrl}"); } return client; diff --git a/XamarinExplorer/Services/MockDataStore.cs b/XamarinExplorer/Services/MockDataStore.cs index 90f24bf..8cbf080 100644 --- a/XamarinExplorer/Services/MockDataStore.cs +++ b/XamarinExplorer/Services/MockDataStore.cs @@ -13,16 +13,15 @@ public class MockDataStore : Repository public MockDataStore() { items = new List(); - int id = 0; var mockItems = new List { - new Item { Id = ++id, Text = "First item", Description="This is an item description." }, - new Item { Id = ++id, Text = "Second item", Description="This is an item description." }, - new Item { Id = ++id, Text = "Third item", Description="This is an item description." }, - new Item { Id = ++id, Text = "Fourth item", Description="This is an item description." }, - new Item { Id = ++id, Text = "Fifth item", Description="This is an item description." }, - new Item { Id = ++id, Text = "Sixth item", Description="This is an item description." }, + new Item { Id = Guid.NewGuid().ToString(), Text = "First item", Description="This is an item description." }, + new Item { Id = Guid.NewGuid().ToString(), Text = "Second item", Description="This is an item description." }, + new Item { Id = Guid.NewGuid().ToString(), Text = "Third item", Description="This is an item description." }, + new Item { Id = Guid.NewGuid().ToString(), Text = "Fourth item", Description="This is an item description." }, + new Item { Id = Guid.NewGuid().ToString(), Text = "Fifth item", Description="This is an item description." }, + new Item { Id = Guid.NewGuid().ToString(), Text = "Sixth item", Description="This is an item description." }, }; foreach (var item in mockItems) diff --git a/XamarinExplorer/Services/ToDoItemsRepository.cs b/XamarinExplorer/Services/ToDoItemsRepository.cs new file mode 100644 index 0000000..0b3e552 --- /dev/null +++ b/XamarinExplorer/Services/ToDoItemsRepository.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using System.Net.Http; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Shared; +using Xamarin.Essentials; +using XamarinExplorer.Services; + +namespace XamarinExplorer +{ + public class ToDoItemsRepository : Repository + { + private List _items; + + public override async Task> GetAsync(bool forceRefresh = false) + { + if (forceRefresh && Connectivity.NetworkAccess == NetworkAccess.Internet) + { + var json = await GetClient().GetStringAsync("HttpGetTrigger"); + _items = JsonConvert.DeserializeObject>(json); + } + + return _items; + } + + public async Task PostAsync(Item model) + { + _items.Add(model); + + var content = new StringContent(JsonConvert.SerializeObject(model), System.Text.Encoding.UTF8, "application/json"); + + await GetClient().PostAsync("SignalRTrigger", content); + } + } +} \ No newline at end of file diff --git a/XamarinExplorer/ViewModels/ListViewModel.cs b/XamarinExplorer/ViewModels/ListViewModel.cs index 830ff36..9dc40b8 100644 --- a/XamarinExplorer/ViewModels/ListViewModel.cs +++ b/XamarinExplorer/ViewModels/ListViewModel.cs @@ -75,7 +75,7 @@ public virtual string Filter } set { - SetProperty(ref _filter, value); + SetProperty(ref _filter, value); OnPropertyChanged(nameof(Items)); } } diff --git a/XamarinExplorer/Views/ItemDetailPage.xaml.cs b/XamarinExplorer/Views/ItemDetailPage.xaml.cs index a32fcf8..ac91b1b 100644 --- a/XamarinExplorer/Views/ItemDetailPage.xaml.cs +++ b/XamarinExplorer/Views/ItemDetailPage.xaml.cs @@ -1,7 +1,4 @@ -using System.Collections.Generic; -using Microsoft.AppCenter.Analytics; -using Shared; -using Shared.WordPress; +using Shared; namespace XamarinExplorer.Views { diff --git a/XamarinExplorer/Views/ItemsPage.xaml b/XamarinExplorer/Views/ItemsPage.xaml index b848fed..4a79b12 100644 --- a/XamarinExplorer/Views/ItemsPage.xaml +++ b/XamarinExplorer/Views/ItemsPage.xaml @@ -13,16 +13,19 @@ - - -