Skip to content

Commit 2d7c4d1

Browse files
Multi-application support (#27)
* Added `XummSdk` class to support multiple Xumm Applications in one .NET application * File-scoped namespaces * Updated XML documentation * Implemented the `XummSdk` in XUMM.NET.WebApp * Added error message to the alert box * Added `XummSdk` blazor component for the Xumm API credentials * Implemented `XummSdk` in XUMM.NET.ServerApp and marked `ResponseAlertBox` and `XummSdkCredentials` as nullable to suppress CS8625 * Updated Readme * Updated gitignore
1 parent 1fa7ddb commit 2d7c4d1

File tree

73 files changed

+903
-719
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+903
-719
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ _TeamCity*
140140
# Visual Studio code coverage results
141141
*.coverage
142142
*.coveragexml
143+
*.lutconfig
143144

144145
# NCrunch
145146
_NCrunch_*

README.md

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,25 @@ More information about the XUMM API, payloads, the API workflow, sending Push no
4646
- https://xumm.readme.io/docs
4747

4848

49+
### Multiple Xumm Applications support
50+
You can create an instance of `XummSdk` if your .NET application has to connect to multiple Xumm Applications.
51+
The `XummSdk` class contains client properties instead of using the clients by dependency injection.
52+
* **IXummMiscAppStorageClient**: `XummSdk.AppStorage`
53+
* **IXummMiscClient**: `XummSdk.Miscellaneous`
54+
* **IXummPayloadClient**: `XummSdk.Payload`
55+
56+
```C#
57+
var xummSdk = new XummSdk("00000000-0000-0000-000-000000000000", "00000000-0000-0000-000-000000000000");
58+
var pong = await xummSdk.Miscellaneous.GetPingAsync();
59+
```
60+
4961
##### IXummMiscClient.GetPingAsync()
5062

5163
The `GetPingAsync()` method allows you to verify API access (valid credentials) and returns some info on your XUMM APP:
5264

5365
```C#
54-
@inject IXummMiscClient _miscClient
55-
var pong = await _miscClient.GetPingAsync();
66+
@inject IXummMiscClient MiscClient
67+
var pong = await MiscClient.GetPingAsync();
5668
```
5769

5870
Returns: [`XummPong`](https://github.com/XRPL-Labs/XUMM.NET.SDK/blob/main/XUMM.Net/Models/Misc/XummPong.cs)
@@ -95,8 +107,8 @@ Alternatively, KYC status can be retrieved for an XPRL account address: the addr
95107
XUMM when the session KYC was initiated by.
96108

97109
```C#
98-
@inject IXummMiscClient _miscClient
99-
var kycStatus = await _miscClient.GetKycStatusAsync("rBLomsmaSJ1ttBmS3WPmPpWLAUDKFwiF9Q");
110+
@inject IXummMiscClient MiscClient
111+
var kycStatus = await MiscClient.GetKycStatusAsync("rBLomsmaSJ1ttBmS3WPmPpWLAUDKFwiF9Q");
100112
```
101113

102114
Returns: [`XummKycStatus`](https://github.com/XRPL-Labs/XUMM.NET.SDK/blob/main/XUMM.Net/Enums/XummKycStatus.cs)
@@ -117,8 +129,8 @@ live from the XRP ledger, as fetched for you by the XUMM backend.
117129
[![npm version](https://badge.fury.io/js/xrpl-txdata.svg)](https://www.npmjs.com/xrpl-txdata)
118130

119131
```C#
120-
@inject IXummMiscClient _miscClient
121-
var txInfo = await _miscClient.GetTransactionAsync("00000000-0000-0000-0000-000000000000");
132+
@inject IXummMiscClient MiscClient
133+
var txInfo = await MiscClient.GetTransactionAsync("00000000-0000-0000-0000-000000000000");
122134
```
123135

124136
Returns: [`XummTransaction`](https://github.com/XRPL-Labs/XUMM.NET.SDK/blob/main/XUMM.Net/Models/Misc/XummTransaction.cs)
@@ -132,21 +144,21 @@ Your XUMM APP storage is stored at the XUMM API backend, meaning it persists unt
132144
This data is private, and accessible only with your own API credentials. This private JSON data can be used to store credentials / config / bootstrap info / ... for your headless application (eg. POS device).
133145

134146
```C#
135-
@inject IXummMiscAppStorageClient _miscAppStorageClient
147+
@inject IXummMiscAppStorageClient MiscAppStorageClient
136148

137-
var storageSet = await _miscAppStorageClient.StoreAsync({name: 'Dominique', age: 32, male: true});
149+
var storageSet = await MiscAppStorageClient.StoreAsync({name: 'Dominique', age: 32, male: true});
138150
Console.WriteLine(storageSet.Stored)
139151
// true
140152
141-
var storageGet = await _miscAppStorageClient.GetAsync()
153+
var storageGet = await MiscAppStorageClient.GetAsync()
142154
Console.WriteLine(storageGet.Data)
143155
// { name: 'Dominique', age: 32, male: true }
144156
145-
var storageDelete = await _miscAppStorageClient.ClearAsync()
157+
var storageDelete = await MiscAppStorageClient.ClearAsync()
146158
Console.WriteLine(storageSet.Stored)
147159
// true
148160
149-
var storageGetAfterDelete = await _miscAppStorageClient.GetAsync()
161+
var storageGetAfterDelete = await MiscAppStorageClient.GetAsync()
150162
Console.WriteLine(storageGetAfterDelete.Data)
151163
// null
152164
```
@@ -191,23 +203,23 @@ Note! Please don't use _polling_! The XUMM API offers Webhooks (configure your W
191203
You can `GetAsync()` a payload by:
192204
- Payload UUID
193205
```C#
194-
@inject IXummPayloadClient _payloadClient
195-
var payload = await _payloadClient.GetAsync("00000000-0000-0000-0000-000000000000");
206+
@inject IXummPayloadClient PayloadClient
207+
var payload = await PayloadClient.GetAsync("00000000-0000-0000-0000-000000000000");
196208
```
197209

198210
- Passing a created Payload object (see: [IXummPayloadClient.CreateAsync](#IXummPayloadClient.CreateAsync))
199211
```C#
200-
@inject IXummPayloadClient _payloadClient
212+
@inject IXummPayloadClient PayloadClient
201213
var newPayload = new XummPostJsonPayload("{...}");
202-
var created = await _payloadClient.CreateAsync(newPayload);
203-
var payload = await _payloadClient.GetAsync(created);
214+
var created = await PayloadClient.CreateAsync(newPayload);
215+
var payload = await PayloadClient.GetAsync(created);
204216
```
205217

206218
If a payload can't be fetched (eg. doesn't exist), `null` will be returned, unless a second param (boolean) is provided to get the SDK to throw an exception in case a payload can't be retrieved:
207219

208220
```C#
209-
@inject IXummPayloadClient _payloadClient
210-
var payload = await _payloadClient.GetAsync("00000000-0000-0000-0000-000000000000", true);
221+
@inject IXummPayloadClient PayloadClient
222+
var payload = await PayloadClient.GetAsync("00000000-0000-0000-0000-000000000000", true);
211223
```
212224

213225

examples/XUMM.NET.ServerApp/Pages/Misc/AccountMeta.razor

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
@page "/account-meta"
2-
@using XUMM.NET.SDK.Clients.Interfaces
32
@using XUMM.NET.SDK.Extensions
43
@using XUMM.NET.SDK.Models.Misc
5-
@using XUMM.NET.ServerApp.Extensions
64

75
@inject IOptions<XrplConfig> Config
8-
@inject IXummMiscClient _miscClient
6+
@inject IXummMiscClient MiscClient
97

108
<PageTitle>Account Meta</PageTitle>
119

@@ -99,7 +97,7 @@
9997
</div>
10098
</div>
10199
@code {
102-
private ResponseAlertBox _responseAlertBox = default!;
100+
private ResponseAlertBox? _responseAlertBox;
103101
private string _account = default!;
104102
private XummAccountMetaResponse? _accountMeta;
105103

@@ -110,7 +108,7 @@
110108
_account = Config.Value.Account;
111109
}
112110

113-
_accountMeta = await _responseAlertBox.GetResponseAndSetAlertAsync(() => _miscClient.AccountMetaAsync(_account));
111+
_accountMeta = await _responseAlertBox!.GetResponseAndSetAlertAsync(() => MiscClient.AccountMetaAsync(_account));
114112
_responseAlertBox.SetAlert("Account Meta", _accountMeta != null);
115113
}
116114
}

examples/XUMM.NET.ServerApp/Pages/Misc/UserTokens.razor

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
@page "/user-tokens"
2-
@using XUMM.NET.SDK.Clients.Interfaces
32
@using XUMM.NET.SDK.Models.Misc
43
@using System.Text.RegularExpressions
54

6-
@inject IXummMiscClient _miscClient
5+
@inject IXummMiscClient MiscClient
76

87
<PageTitle>User Tokens</PageTitle>
98

@@ -51,7 +50,7 @@
5150
}
5251

5352
@code {
54-
private ResponseAlertBox _responseAlertBox = default!;
53+
private ResponseAlertBox? _responseAlertBox;
5554
private string _userTokens = default!;
5655
private XummUserTokens? _xummUserTokens;
5756

@@ -70,11 +69,11 @@
7069

7170
if (userTokens.Length == 1)
7271
{
73-
_xummUserTokens = await _responseAlertBox.GetResponseAndSetAlertAsync(() => _miscClient.VerifyUserTokenAsync(userTokens[0]));
72+
_xummUserTokens = await _responseAlertBox!.GetResponseAndSetAlertAsync(() => MiscClient.VerifyUserTokenAsync(userTokens[0]));
7473
}
7574
else
7675
{
77-
_xummUserTokens = await _responseAlertBox.GetResponseAndSetAlertAsync(() => _miscClient.VerifyUserTokensAsync(userTokens));
76+
_xummUserTokens = await _responseAlertBox!.GetResponseAndSetAlertAsync(() => MiscClient.VerifyUserTokensAsync(userTokens));
7877
}
7978

8079
_responseAlertBox.SetAlert("User Token validity", _xummUserTokens != null);

examples/XUMM.NET.ServerApp/Pages/Payload/Details.razor

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
@page "/payload-details"
2-
@using XUMM.NET.SDK.Clients.Interfaces
32
@using XUMM.NET.SDK.Models.Payload
43
@using XUMM.NET.ServerApp.Extensions
54
@using System.Text.Json
65

7-
@inject IXummPayloadClient _payloadClient
8-
96
<PageTitle>Payload Details</PageTitle>
107

118
<ResponseAlertBox @ref="_responseAlertBox"></ResponseAlertBox>
@@ -14,13 +11,15 @@
1411
<div>Fetch payload details by providing the UUID or Custom Identifier.</div>
1512

1613
<div class="row">
14+
<XummSdkCredentials @ref="_xummSdkCredentials"></XummSdkCredentials>
15+
1716
<div class="mb-3">
1817
<label for="payloadUuid" class="form-label">Payload UUID</label>
1918
<input id="payloadUuid" type="text" class="form-control" placeholder="Payload UUID" aria-label="Payload UUID" aria-describedby="basic-addon2" @bind="_payloadUuid">
2019
</div>
2120
<div class="mb-3">
2221
<label for="customIdentifier" class="form-label">Custom Identifier</label>
23-
<input id="customIdentifier" type="text" class="form-control" placeholder="Custom Identifier" aria-label="Custom Identifier" aria-describedby="basic-addon2" @bind="_customIdentifier">
22+
<input id="customIdentifier" type="text" class="form-control" placeholder="Custom Identifier" maxlength="40" aria-label="Custom Identifier" aria-describedby="basic-addon2" @bind="_customIdentifier">
2423
</div>
2524
<div class="btn-group mb-3" role="group">
2625
<button class="btn btn-primary" type="button" @onclick="GetPayloadAsync">Fetch details</button>
@@ -40,7 +39,8 @@
4039
}
4140

4241
@code {
43-
private ResponseAlertBox _responseAlertBox = default!;
42+
private ResponseAlertBox? _responseAlertBox;
43+
private XummSdkCredentials? _xummSdkCredentials;
4444
private string? _payloadUuid;
4545
private string? _customIdentifier;
4646
private XummPayloadDetails? _payloadDetails;
@@ -49,13 +49,13 @@
4949
{
5050
if (!string.IsNullOrWhiteSpace(_payloadUuid))
5151
{
52-
_payloadDetails = await _responseAlertBox.GetResponseAndSetAlertAsync(() => _payloadClient.GetAsync(_payloadUuid));
52+
_payloadDetails = await _responseAlertBox!.GetResponseAndSetAlertAsync(() => _xummSdkCredentials!.Payload.GetAsync(_payloadUuid));
5353
}
5454
else if (!string.IsNullOrWhiteSpace(_customIdentifier))
5555
{
56-
_payloadDetails = await _responseAlertBox.GetResponseAndSetAlertAsync(() => _payloadClient.GetByCustomIdentifierAsync(_customIdentifier));
56+
_payloadDetails = await _responseAlertBox!.GetResponseAndSetAlertAsync(() => _xummSdkCredentials!.Payload.GetByCustomIdentifierAsync(_customIdentifier));
5757
}
5858

59-
_responseAlertBox.SetAlert("Payload Details", _payloadDetails != null);
59+
_responseAlertBox!.SetAlert("Payload Details", _payloadDetails != null);
6060
}
6161
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
@using XUMM.NET.SDK
2+
@using XUMM.NET.SDK.Clients.Interfaces
3+
4+
@inject IXummMiscClient MiscClient;
5+
@inject IXummMiscAppStorageClient MiscAppStorageClient;
6+
@inject IXummPayloadClient PayloadClient;
7+
8+
<div class="mb-3">
9+
<label for="apikey" class="form-label">API Key <small>(Optional)</small></label>
10+
<input id="apikey" type="password" class="form-control @_cssClass" placeholder="API Key" aria-label="API Key" aria-describedby="basic-addon2" @bind="_apiKey">
11+
<small id="apikeyhelp" class="form-text text-muted">Leave empty to use the configured API Key.</small>
12+
</div>
13+
<div class="mb-3">
14+
<label for="apisecret" class="form-label">API Secret <small>(Optional)</small></label>
15+
<input id="apisecret" type="password" min="0" class="form-control @_cssClass" placeholder="API Secret" aria-label="API Secret" aria-describedby="basic-addon2" @bind="_apiSecret">
16+
<small id="apisecrethelp" class="form-text text-muted">Leave empty to use the configured API Secret.</small>
17+
</div>
18+
19+
@code {
20+
private string? _apiKey;
21+
private string? _apiSecret;
22+
private string? _cssClass;
23+
24+
private XummSdk? GetXummSdk()
25+
{
26+
if (string.IsNullOrWhiteSpace(_apiKey) || string.IsNullOrWhiteSpace(_apiSecret))
27+
{
28+
return null;
29+
}
30+
31+
XummSdk? xummSdk = null;
32+
33+
try
34+
{
35+
xummSdk = new XummSdk(_apiKey, _apiSecret);
36+
_cssClass = null;
37+
}
38+
catch
39+
{
40+
_cssClass = "invalid";
41+
}
42+
43+
StateHasChanged();
44+
return xummSdk;
45+
}
46+
47+
public IXummMiscAppStorageClient AppStorage => GetXummSdk()?.AppStorage ?? MiscAppStorageClient;
48+
public IXummMiscClient Miscellaneous => GetXummSdk()?.Miscellaneous ?? MiscClient;
49+
public IXummPayloadClient Payload => GetXummSdk()?.Payload ?? PayloadClient;
50+
}

examples/XUMM.NET.WebApp/Pages/PingPong.cshtml

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,34 @@
77

88
<h1>@ViewData["Title"]</h1>
99

10-
@if (Model.Pong.Pong)
10+
@if (Model.Pong != null)
1111
{
1212
<div class="alert alert-success" role="alert">
13-
<h4 class="alert-heading">Retrieved Pong!</h4>
13+
<h4 class="alert-heading">Retrieved pong of @Model.Pong.Auth.Application.Name</h4>
1414
</div>
1515
}
16-
else
16+
else if (!string.IsNullOrWhiteSpace(Model.ErrorMessage))
1717
{
1818
<div class="alert alert-danger" role="alert">
1919
<h4 class="alert-heading">Failed to retrieve Pong!</h4>
20+
<div>@Model.ErrorMessage</div>
2021
</div>
21-
}
22+
}
23+
24+
<form method="post">
25+
<div class="col-md-6">
26+
<div class="mb-3">
27+
<label for="apikey" class="form-label">API Key <small>(Optional)</small></label>
28+
<input id="apikey" type="password" class="form-control" placeholder="API Key" aria-label="API Key" aria-describedby="basic-addon2" asp-for="ApiKey">
29+
<small id="apikeyhelp" class="form-text text-muted">Leave empty to use the configured API Key.</small>
30+
</div>
31+
<div class="mb-3">
32+
<label for="apisecret" class="form-label">API Secret <small>(Optional)</small></label>
33+
<input id="apisecret" type="password" min="0" class="form-control" placeholder="API Secret" aria-label="API Secret" aria-describedby="basic-addon2" asp-for="ApiSecret">
34+
<small id="apisecrethelp" class="form-text text-muted">Leave empty to use the configured API Secret.</small>
35+
</div>
36+
<div class="btn-group mb-3" role="group">
37+
<button type="submit" class="btn btn-primary">Ping</button>
38+
</div>
39+
</div>
40+
</form>
Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
using System.Threading.Tasks;
1+
using Microsoft.AspNetCore.Mvc;
22
using Microsoft.AspNetCore.Mvc.RazorPages;
3+
using System;
4+
using System.Threading.Tasks;
5+
using XUMM.NET.SDK;
36
using XUMM.NET.SDK.Clients.Interfaces;
47
using XUMM.NET.SDK.Models.Misc;
58

@@ -9,16 +12,33 @@ public class PingPongModel : PageModel
912
{
1013
public XummPong Pong { get; set; }
1114

15+
[BindProperty]
16+
public string ApiKey { get; set; }
17+
18+
[BindProperty]
19+
public string ApiSecret { get; set; }
20+
21+
public string? ErrorMessage { get; set; }
22+
1223
private readonly IXummMiscClient _miscClient;
1324

1425
public PingPongModel(IXummMiscClient miscClient)
1526
{
1627
_miscClient = miscClient;
1728
}
1829

19-
public async Task OnGetAsync()
30+
public async Task OnPostAsync()
2031
{
21-
Pong = await _miscClient.GetPingAsync();
32+
try
33+
{
34+
var client = !string.IsNullOrWhiteSpace(ApiKey) && !string.IsNullOrWhiteSpace(ApiSecret) ? new XummSdk(ApiKey, ApiSecret).Miscellaneous : _miscClient;
35+
Pong = await client.GetPingAsync();
36+
ErrorMessage = null;
37+
}
38+
catch (Exception ex)
39+
{
40+
ErrorMessage = ex.Message;
41+
}
2242
}
2343
}
2444
}

examples/XUMM.Net.ServerApp/Pages/Misc/Avatar.razor

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
@page "/avatar"
2-
@using XUMM.NET.SDK.Clients.Interfaces
32
@using XUMM.NET.SDK.Extensions
43

54
@inject IOptions<XrplConfig> Config
6-
@inject IXummMiscClient _miscClient
5+
@inject IXummMiscClient MiscClient
76

87
<PageTitle>Avatar</PageTitle>
98

@@ -66,6 +65,6 @@
6665
_padding = 0;
6766
}
6867

69-
_avatarUrl = _miscClient.GetAvatarUrl(_account, _dimensions, _padding);
68+
_avatarUrl = MiscClient.GetAvatarUrl(_account, _dimensions, _padding);
7069
}
7170
}

0 commit comments

Comments
 (0)