diff --git a/Realm/Realm/Handles/AppHandle.cs b/Realm/Realm/Handles/AppHandle.cs index a7e8f89a39..2a4746cc3e 100644 --- a/Realm/Realm/Handles/AppHandle.cs +++ b/Realm/Realm/Handles/AppHandle.cs @@ -349,13 +349,13 @@ public Uri GetBaseUri() return new Uri(uriString); } - public async Task UpdateBaseUriAsync(Uri newUri) + public async Task UpdateBaseUriAsync(Uri? newUri) { var tcs = new TaskCompletionSource(); var tcsHandle = GCHandle.Alloc(tcs); try { - var url = newUri.ToString(); + var url = newUri?.ToString().TrimEnd('/') ?? string.Empty; NativeMethods.update_base_uri(this, url, (IntPtr)url.Length, GCHandle.ToIntPtr(tcsHandle), out var ex); ex.ThrowIfNecessary(); await tcs.Task; diff --git a/Realm/Realm/Sync/App.cs b/Realm/Realm/Sync/App.cs index 98a8f4edec..88036677bc 100644 --- a/Realm/Realm/Sync/App.cs +++ b/Realm/Realm/Sync/App.cs @@ -275,7 +275,10 @@ public Task DeleteUserFromServerAsync(User user) /// Temporarily overrides the value from /// with a new value used for communicating with the server. /// - /// The new uri that will be used for communicating with the server. + /// + /// The new uri that will be used for communicating with the server. If set to null, the base uri will + /// be reset to its default value. + /// /// An awaitable that represents the asynchronous operation. /// /// The App will revert to using the value in [AppConfiguration] when it is restarted. @@ -287,7 +290,7 @@ public Task DeleteUserFromServerAsync(User user) /// This API is experimental and subject to change without a major version increase. /// [Experimental("Rlm001", UrlFormat = "www.mongodb.com/docs/atlas/app-services/edge-server/connect/#roaming-between-edge-servers")] - public Task UpdateBaseUriAsync(Uri newUri) => Handle.UpdateBaseUriAsync(newUri); + public Task UpdateBaseUriAsync(Uri? newUri) => Handle.UpdateBaseUriAsync(newUri); /// public override bool Equals(object? obj) diff --git a/Tests/Realm.Tests/Sync/AppTests.cs b/Tests/Realm.Tests/Sync/AppTests.cs index 72f3d3cfb1..3ee2ec1620 100644 --- a/Tests/Realm.Tests/Sync/AppTests.cs +++ b/Tests/Realm.Tests/Sync/AppTests.cs @@ -401,7 +401,7 @@ public void RealmConfigurationBaseUrl_ReturnsExpectedValue() } [Test] - public void App_ChangeBaseUri_UpdatesBaseUri() + public void App_UpdateBaseUri_UpdatesBaseUri() { SyncTestHelpers.RunBaasTestAsync(async () => { @@ -411,12 +411,32 @@ public void App_ChangeBaseUri_UpdatesBaseUri() Assert.That(app.BaseUri, Is.EqualTo(new Uri("https://services.mongodb.com"))); -#pragma warning disable RLM001 +#pragma warning disable Rlm001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. await app.UpdateBaseUriAsync(SyncTestHelpers.BaasUri!); -#pragma warning restore RLM001 +#pragma warning restore Rlm001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. Assert.That(app.BaseUri, Is.EqualTo(SyncTestHelpers.BaasUri)); }); } + + [Test] + public void App_UpdateBaseUri_WhenUnreachable_Throws() + { + SyncTestHelpers.RunBaasTestAsync(async () => + { + var appConfig = SyncTestHelpers.GetAppConfig(AppConfigType.FlexibleSync); + appConfig.BaseUri = new Uri("https://services.mongodb.com"); + var app = App.Create(appConfig); + + Assert.That(app.BaseUri, Is.EqualTo(new Uri("https://services.mongodb.com"))); + +#pragma warning disable Rlm001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + var ex = await TestHelpers.AssertThrows(() => app.UpdateBaseUriAsync(new Uri("https://google.com"))); +#pragma warning restore Rlm001 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. + + Assert.That(ex.Message, Does.Contain("404")); + Assert.That(ex.StatusCode, Is.EqualTo(HttpStatusCode.NotFound)); + }); + } } } diff --git a/wrappers/src/app_cs.cpp b/wrappers/src/app_cs.cpp index 90fe1e144c..ccf3f694d1 100644 --- a/wrappers/src/app_cs.cpp +++ b/wrappers/src/app_cs.cpp @@ -347,6 +347,25 @@ extern "C" { }); } + REALM_EXPORT void shared_app_update_base_url(SharedApp& app, uint16_t* url_buf, size_t url_len, void* tcs_ptr, NativeException::Marshallable& ex) + { + return handle_errors(ex, [&]() { + std::string url(Utf16StringAccessor(url_buf, url_len)); + + app->update_base_url(url, [tcs_ptr](util::Optional err) { + if (err) { + auto& err_copy = *err; + MarshaledAppError app_error(err_copy); + + s_void_callback(tcs_ptr, app_error); + } + else { + s_void_callback(tcs_ptr, MarshaledAppError()); + } + }); + }); + } + #pragma region EmailPassword REALM_EXPORT void shared_app_email_register_user(SharedApp& app, uint16_t* username_buf, size_t username_len, uint16_t* password_buf, size_t password_len, void* tcs_ptr, NativeException::Marshallable& ex)