Initialize a store the first time is created in sembast - database

I'm developing a mobile application in Flutter, and I would like to manage the settings of my application (light theme or dark theme, ...).
I'm using sembast to store the settings of my application. I would like to initialize the store with some initial values the first time is created. How can I do that?
This is the my database helper class:
class AppDatabase {
// Name of the database.
static final String _dbName = 'mydb.db';
// Singleton instance.
static final AppDatabase _singleton = AppDatabase._();
// Singleton getter.
static AppDatabase get instance => _singleton;
// Transforms synchronous code into asynchronous code.
Completer<Database> _dbOpenCompleter;
// Private constructor.
AppDatabase._();
// Database object getter.
Future<Database> get database async {
// If completer is null, AppDatabaseClass is newly instantiated, so database is not yet opened.
if (_dbOpenCompleter == null) {
_dbOpenCompleter = Completer();
_openDatabase();
}
return _dbOpenCompleter.future;
}
Future<void> _openDatabase() async {
// Get a platform-specific directory where persistent app data can be stored.
final appDocumentDir = await getApplicationDocumentsDirectory();
// Path with the form: /platform-specific-directory/demo.db
final dbPath = join(appDocumentDir.path, _dbName);
final database = await databaseFactoryIo.openDatabase(dbPath);
// Any code awaiting the Completer's future will now start executing.
_dbOpenCompleter.complete(database);
}
}
Then I use the following repository to perform CRUD operations on my Settings:
class SettingsDatabaseRepository implements SettingsRepository {
// The name of the store.
static const String SETTINGS_STORE_NAME = 'settings';
// This store acts like a persistent map, values of which are Settings objects
// converted to Map.
final _settingsStore = intMapStoreFactory.store(SETTINGS_STORE_NAME);
// Private getter to shorten the amount of code needed to get the singleton
// instance of an opened database.
Future<Database> get _db async => await AppDatabase.instance.database;
#override
Future<void> insert(Settings settings) async {
await _settingsStore.add(await _db, settings.toMap());
}
#override
Future<void> update(Settings settings) async {
final finder = Finder(filter: Filter.byKey(settings.settingsId));
await _settingsStore.update(
await _db,
settings.toMap(),
finder: finder,
);
}
#override
Future<Settings> getSettings() async {
final recordSnapshots = await _settingsStore.find(await _db);
final settingsList = recordSnapshots.map((snapshot) {
final settings = Settings.fromMap(snapshot.value);
settings.copyWith(settingsId: snapshot.key);
return settings;
}).toList();
if (settingsList.isEmpty)
return null;
else
return settingsList.first;
}
}

I would like to initialize the store with some initial values the first time is created.
You cannot perform action when a store is created (since a store is not really created, it just holds records), however you can perform action when the database is created.
Sembast supports a database versioning system similar to sqlite, although here there is not much schema to modify. You can use this system to perform action when the database is created (or when you decide later in a new version to update it).
// Our shop store sample data
var store = intMapStoreFactory.store('shop');
var db = await factory.openDatabase(path, version: 1,
onVersionChanged: (db, oldVersion, newVersion) async {
// If the db does not exist, create some data
if (oldVersion == 0) {
await store.add(db, {'name': 'Lamp', 'price': 10});
await store.add(db, {'name': 'Chair', 'price': 15});
}
});
See more info

Related

How to save app data after restart of an app - flutter?

I was wondering how to make my app save data after restart? (The user can delete task and add new task to list, as well as check the box that the task is done. I want the app to save this data so when the user exists the app it will display all the tasks that he left the app with)
I was reading on google for few hours now, I got to
[1]: https://flutter.dev/docs/cookbook/persistence/reading-writing-files
This link as someone recommended on a similar post. But after reading it through I am a bit confused about where to start with my app.
Including some of my code and if you could help me I would really appreciate it as after hours of reading and watching tutorials I am still quite unsure where to start or which way of doing this is best.
My main.dart is this
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) =>
TaskData(), //changing builder: to create: fixed the errors i been having
child: MaterialApp(
home: TasksScreen(),
),
);
}
}
class TaskData extends ChangeNotifier {
List<Task> _tasks = [
Task(name: "Sample task 1"),
Task(name: "Sample task 2"),
Task(name: "Sample task 3"),
];
UnmodifiableListView<Task> get tasks {
return UnmodifiableListView(_tasks);
}
int get taskCount {
return _tasks.length;
}
void addTask(String newTaskTitle) {
final task = Task(name: newTaskTitle);
_tasks.add(task);
notifyListeners();
}
void updateTask(Task task) {
task.toggleDone();
notifyListeners();
}
void deleteTask(Task task) {
_tasks.remove(task);
notifyListeners();
}
Thank you so much!
The basic method is using the device local storage.
1 - Add the shared_preferences in your pubspec.yaml
2 - Create a class to write and read data :
import 'dart:convert';
import 'package:shared_preferences/shared_preferences.dart';
class StoreData {
StoreData._privateConstructor();
static final StoreData instance = StoreData._privateConstructor();
Future<void> saveString(String key, String value) async {
try{
SharedPreferences pref = await SharedPreferences.getInstance();
final encodedValue = base64.encode(utf8.encode(value));
pref.setString(key, encodedValue);
} catch (e){
print('saveString ${e.toString()}');
}
}
Future<String> getString(String key) async {
SharedPreferences pref = await SharedPreferences.getInstance();
final value = pref.getString(key) == null ? '' : pref.getString(key);
if (value.length > 0) {
final decodedValue = utf8.decode(base64.decode(value));
return decodedValue.toString();
}
return '';
}
Future<bool> remove(String key) async {
SharedPreferences pref = await SharedPreferences.getInstance();
return pref.remove(key);
}
}
3 Use :
Save Data:
StoreData.instance.saveString('name', 'sergio');
Retrieve Data:
final String storedName = await StoreData.instance.getString('name');
print('The name is $storedName');
We have many other methods, like use a SQlite, NoSql or a Database in back-end, but the local storage is the most basic case
What you need is a database or a document based data storage. You can store data in a local sqlite db, using sqflite plugin. Or you can store in a JSON asset file.
You can also use a server or cloud service. Firebase is pretty well integrated with flutter, but AWS and Azure are also great.
You can write the data in a text file in the asset, but that would very complicated.

How to use async functions to connect to database in Flutter?

I am trying to connect to a static database as it is explained in this answer. I therefore created an asynchronous function that looks like this:
Future<void> loadDataBase() async {
// Construct a file path to copy database to
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "asset_worldcities.db");
// Only copy if the database doesn't exist
if (FileSystemEntity.typeSync(path) == FileSystemEntityType.notFound) {
// Load database from asset and copy
ByteData data = await rootBundle.load(join('assets', 'worldcities.db'));
List<int> bytes = data.buffer.asUint8List(
data.offsetInBytes, data.lengthInBytes);
// Save copied asset to documents
await new File(path).writeAsBytes(bytes);
}
}
Now I thought I could access my database inside my main widget by using this function and then call
Directory appDocDir = await getApplicationDocumentsDirectory();
String databasePath = join(appDocDir.path, 'asset_database.db');
this.db = await openDatabase(databasePath);
initialized = true;
Future<List<Page>> search(String word, int parentId) async {
if (!initialized) await this._initialize();
String query = '''
SELECT * FROM users
LIMIT 25''';
return await this.db.rawQuery(query);
}
but this way I am not allowed to use this.db and also not await as I am not inside an async function. Where do I need to put this database request so that it works?
Depending whether you need to do this every time and the database could grow, or whether it's a one-time operation (which it seems like it might be?) and the database is small enough that it's not going to take long to query it, there are different approaches I'd take.
If it's a one-time per install sort of thing and the database will always be small, making the user wait while it copies the file across probably isn't a huge deal. In that case I'd do something like this:
main() async {
WidgetsFlutterBinding.ensureInitialized();
if (needToLoadDatabase()) {
await loadDatabase();
}
let users = await queryUsers();
runApp(MainWidget(users: users));
}
However, if you're reading from the database and it's something that could take any significant amount of time, I'd recommend initiating the load and then passing the future into your main widget, where it could use a FutureBuilder to build an intermediate UI.
That'd look something like this:
main() async {
WidgetsFlutterBinding.ensureInitialized();
let loadUsers = () async {
if (needToLoadDatabase()) {
await loadDatabase();
}
return await queryUsers();
}();
runApp(MainWidget(loadUsers: loadUsers));
}
class MainApp extends StatelessWidget {
final Future<Users> loadUsers;
MainApp({#required this.loadUsers, Key key}): super(key: key);
Widget build(BuildContext context) {
return FutureBuilder(
builder: (ctx, snapshot) {
if (snapshot.hasData) {
// build your UI with data
} else {
// build your UI without data
}
}
);
}
}
Also note that there's no reason you have to do the loading in the main function - you could make your widget stateful and kick that off in the initState, or any number of places like directly where you use the list. You could also look at the FutureProvider from the Provider package.

NoSQL creating and accessing different store references

I am trying to create a NoSQL database for a Flutter app that has different stores for different activities done throughout the day (sleep, exercise, eating, etc.). I don't want to hard code the stores and want to be able to add and delete stores as needed.
The issue I'm encountering is the intMapStoreFactory.store() requires a static input but the inputs for SembastActivityRepository cannot be static. Is there a way to create and access custom store names from outside this WembastActivityRepository class?
Thank you!
import 'package:get_it/get_it.dart';
import 'package:sembast/sembast.dart';
import './activity.dart';
import './activity_repository.dart';
class SembastActivityRepository extends ActivityRepository {
final activityName;
SembastActivityRepository({this.activityName});
final Database _database = GetIt.I.get();
final StoreRef _store = intMapStoreFactory.store(activityName);
#override
Future<int> insertActivity(Activity activity) async {
return await _store.add(_database, activity.toMap());
}
#override
Future updateActivity(Activity activity) async {
await _store.record(activity.id).update(_database, activity.toMap());
}
#override
Future deleteActivity(int activityId) async {
await _store.record(activityId).delete(_database);
}
#override
Future<List<Activity>> getAllActivities() async {
final snapshots = await _store.find(_database);
return snapshots
.map((snapshot) => Activity.fromMap(snapshot.key, snapshot.value))
.toList(growable: false);
}
}
I'm not sure what you mean by static but anyway your code could not compile and I strongly suggest using Strong mode to get compile time recommendation. A StoreRef is just a declaration of a store and its key and value type, you can create/and re-created a StoreRef at any time, the store itself is only created when you add records to it.
If it is just to to get your code to compile, initialize _store in the constructor:
class SembastActivityRepository {
final String activityName;
final StoreRef<int, Map<String, dynamic>> _store;
SembastActivityRepository({this.activityName})
: _store = intMapStoreFactory.store(activityName);
// ...
}

About load supported cultures from DB in .NET CORE

I have a Language entity with all supported languages in my db, each language has a culture string attribute. I want to load supported cultures from DB.
In my service initializer I have it:
public void ConfigureServices(IServiceCollection services)
{
// ... previous configuration not shown
services.Configure<RequestLocalizationOptions>(
opts =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-GB"),
new CultureInfo("en-US"),
new CultureInfo("en"),
new CultureInfo("fr-FR"),
new CultureInfo("fr"),
};
opts.DefaultRequestCulture = new RequestCulture("en-GB");
// Formatting numbers, dates, etc.
opts.SupportedCultures = supportedCultures;
// UI strings that we have localized.
opts.SupportedUICultures = supportedCultures;
});
}
How I can access my DB context inside it?
There is any other better way to do it?
I don't think there's an out of the box solution for this.
However, you can implement your own middleware that achieves this by using ASP.Net's RequestLocalizationMiddleware:
public class CustomRequestLocalizationMiddleware
{
private readonly RequestDelegate next;
private readonly ILoggerFactory loggerFactory;
public CustomRequestLocalizationMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
this.next = next;
this.loggerFactory = loggerFactory;
}
public async Task Invoke(HttpContext context /* You can inject services here, such as DbContext or IDbConnection*/)
{
// You can search your database for your supported and/or default languages here
// This query will execute for all requests, so consider using caching
var cultures = await Task.FromResult(new[] { "en" });
var defaultCulture = await Task.FromResult("en");
// You can configure the options here as you would do by calling services.Configure<RequestLocalizationOptions>()
var options = new RequestLocalizationOptions()
.AddSupportedCultures(cultures)
.AddSupportedUICultures(cultures)
.SetDefaultCulture(defaultCulture);
// Finally, we instantiate ASP.Net's default RequestLocalizationMiddleware and call it
var defaultImplementation = new RequestLocalizationMiddleware(next, Options.Create(options), loggerFactory);
await defaultImplementation.Invoke(context);
}
}
Then, we inject the required services and use the custom middleware in Startup.cs or Program.cs as follows:
services.AddLocalization()
/* ... */
app.UseMiddleware<CustomRequestLocalizationMiddleware>()
Do not call app.UseRequestLocalization(), because this would call ASP.Net's RequestLocalizationMiddleware again with the default options, and override the culture that has been resolved previously.

Integration testing with in-memory IdentityServer

I have an API that uses IdentityServer4 for token validation.
I want to unit test this API with an in-memory TestServer. I'd like to host the IdentityServer in the in-memory TestServer.
I have managed to create a token from the IdentityServer.
This is how far I've come, but I get an error "Unable to obtain configuration from http://localhost:54100/.well-known/openid-configuration"
The Api uses [Authorize]-attribute with different policies. This is what I want to test.
Can this be done, and what am I doing wrong?
I have tried to look at the source code for IdentityServer4, but have not come across a similar integration test scenario.
protected IntegrationTestBase()
{
var startupAssembly = typeof(Startup).GetTypeInfo().Assembly;
_contentRoot = SolutionPathUtility.GetProjectPath(#"<my project path>", startupAssembly);
Configure(_contentRoot);
var orderApiServerBuilder = new WebHostBuilder()
.UseContentRoot(_contentRoot)
.ConfigureServices(InitializeServices)
.UseStartup<Startup>();
orderApiServerBuilder.Configure(ConfigureApp);
OrderApiTestServer = new TestServer(orderApiServerBuilder);
HttpClient = OrderApiTestServer.CreateClient();
}
private void InitializeServices(IServiceCollection services)
{
var cert = new X509Certificate2(Path.Combine(_contentRoot, "idsvr3test.pfx"), "idsrv3test");
services.AddIdentityServer(options =>
{
options.IssuerUri = "http://localhost:54100";
})
.AddInMemoryClients(Clients.Get())
.AddInMemoryScopes(Scopes.Get())
.AddInMemoryUsers(Users.Get())
.SetSigningCredential(cert);
services.AddAuthorization(options =>
{
options.AddPolicy(OrderApiConstants.StoreIdPolicyName, policy => policy.Requirements.Add(new StoreIdRequirement("storeId")));
});
services.AddSingleton<IPersistedGrantStore, InMemoryPersistedGrantStore>();
services.AddSingleton(_orderManagerMock.Object);
services.AddMvc();
}
private void ConfigureApp(IApplicationBuilder app)
{
app.UseIdentityServer();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
var options = new IdentityServerAuthenticationOptions
{
Authority = _appsettings.IdentityServerAddress,
RequireHttpsMetadata = false,
ScopeName = _appsettings.IdentityServerScopeName,
AutomaticAuthenticate = false
};
app.UseIdentityServerAuthentication(options);
app.UseMvc();
}
And in my unit-test:
private HttpMessageHandler _handler;
const string TokenEndpoint = "http://localhost/connect/token";
public Test()
{
_handler = OrderApiTestServer.CreateHandler();
}
[Fact]
public async Task LeTest()
{
var accessToken = await GetToken();
HttpClient.SetBearerToken(accessToken);
var httpResponseMessage = await HttpClient.GetAsync("stores/11/orders/asdf"); // Fails on this line
}
private async Task<string> GetToken()
{
var client = new TokenClient(TokenEndpoint, "client", "secret", innerHttpMessageHandler: _handler);
var response = await client.RequestClientCredentialsAsync("TheMOON.OrderApi");
return response.AccessToken;
}
You were on the right track with the code posted in your initial question.
The IdentityServerAuthenticationOptions object has properties to override the default HttpMessageHandlers it uses for back channel communication.
Once you combine this with the CreateHandler() method on your TestServer object you get:
//build identity server here
var idBuilder = new WebBuilderHost();
idBuilder.UseStartup<Startup>();
//...
TestServer identityTestServer = new TestServer(idBuilder);
var identityServerClient = identityTestServer.CreateClient();
var token = //use identityServerClient to get Token from IdentityServer
//build Api TestServer
var options = new IdentityServerAuthenticationOptions()
{
Authority = "http://localhost:5001",
// IMPORTANT PART HERE
JwtBackChannelHandler = identityTestServer.CreateHandler(),
IntrospectionDiscoveryHandler = identityTestServer.CreateHandler(),
IntrospectionBackChannelHandler = identityTestServer.CreateHandler()
};
var apiBuilder = new WebHostBuilder();
apiBuilder.ConfigureServices(c => c.AddSingleton(options));
//build api server here
var apiClient = new TestServer(apiBuilder).CreateClient();
apiClient.SetBearerToken(token);
//proceed with auth testing
This allows the AccessTokenValidation middleware in your Api project to communicate directly with your In-Memory IdentityServer without the need to jump through hoops.
As a side note, for an Api project, I find it useful to add IdentityServerAuthenticationOptions to the services collection in Startup.cs using TryAddSingleton instead of creating it inline:
public void ConfigureServices(IServiceCollection services)
{
services.TryAddSingleton(new IdentityServerAuthenticationOptions
{
Authority = Configuration.IdentityServerAuthority(),
ScopeName = "api1",
ScopeSecret = "secret",
//...,
});
}
public void Configure(IApplicationBuilder app)
{
var options = app.ApplicationServices.GetService<IdentityServerAuthenticationOptions>()
app.UseIdentityServerAuthentication(options);
//...
}
This allows you to register the IdentityServerAuthenticationOptions object in your tests without having to alter the code in the Api project.
I understand there is a need for a more complete answer than what #james-fera posted. I have learned from his answer and made a github project consisting of a test project and API project. The code should be self-explanatory and not hard to understand.
https://github.com/emedbo/identityserver-test-template
The IdentityServerSetup.cs class https://github.com/emedbo/identityserver-test-template/blob/master/tests/API.Tests/Config/IdentityServerSetup.cs can be abstracted away e.g. NuGetted away, leaving the base class IntegrationTestBase.cs
The essences is that can make the test IdentityServer work just like a normal IdentityServer, with users, clients, scopes, passwords etc. I have made the DELETE method [Authorize(Role="admin)] to prove this.
Instead of posting code here, I recommend read #james-fera's post to get the basics then pull my project and run tests.
IdentityServer is such a great tool, and with the ability to use the TestServer framework it gets even better.
I think you probably need to make a test double fake for your authorization middleware depending on how much functionality you want. So basically you want a middleware that does everything that the Authorization middleware does minus the back channel call to the discovery doc.
IdentityServer4.AccessTokenValidation is a wrapper around two middlewares. The JwtBearerAuthentication middleware, and the OAuth2IntrospectionAuthentication middleware. Both of these grab the discovery document over http to use for token validation. Which is a problem if you want to do an in-memory self-contained test.
If you want to go through the trouble you will probably need to make a fake version of app.UseIdentityServerAuthentication that doesnt do the external call that fetches the discovery document. It only populates the HttpContext principal so that your [Authorize] policies can be tested.
Check out how the meat of IdentityServer4.AccessTokenValidation looks here. And follow up with a look at how JwtBearer Middleware looks here
We stepped away from trying to host a mock IdentityServer and used dummy/mock authorizers as suggested by others here.
Here's how we did that in case it's useful:
Created a function which takes a type, creates a test Authentication Middleware and adds it to the DI engine using ConfigureTestServices (so that it's called after the call to Startup.)
internal HttpClient GetImpersonatedClient<T>() where T : AuthenticationHandler<AuthenticationSchemeOptions>
{
var _apiFactory = new WebApplicationFactory<Startup>();
var client = _apiFactory
.WithWebHostBuilder(builder =>
{
builder.ConfigureTestServices(services =>
{
services.AddAuthentication("Test")
.AddScheme<AuthenticationSchemeOptions, T>("Test", options => { });
});
})
.CreateClient(new WebApplicationFactoryClientOptions
{
AllowAutoRedirect = false,
});
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Test");
return client;
}
Then we create what we called 'Impersonators' (AuthenticationHandlers) with the desired roles to mimic users with roles (We actually used this as a base class, and create derived classes based on this to mock different users):
public abstract class FreeUserImpersonator : AuthenticationHandler<AuthenticationSchemeOptions>
{
public Impersonator(
IOptionsMonitor<AuthenticationSchemeOptions> options,
ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock)
: base(options, logger, encoder, clock)
{
base.claims.Add(new Claim(ClaimTypes.Role, "FreeUser"));
}
protected List<Claim> claims = new List<Claim>();
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
{
var identity = new ClaimsIdentity(claims, "Test");
var principal = new ClaimsPrincipal(identity);
var ticket = new AuthenticationTicket(principal, "Test");
var result = AuthenticateResult.Success(ticket);
return Task.FromResult(result);
}
}
Finally, we can perform our integration tests as follows:
// Arrange
HttpClient client = GetImpersonatedClient<FreeUserImpersonator>();
// Act
var response = await client.GetAsync("api/things");
// Assert
Assert.That.IsSuccessful(response);
Test API startup:
public class Startup
{
public static HttpMessageHandler BackChannelHandler { get; set; }
public void Configuration(IAppBuilder app)
{
//accept access tokens from identityserver and require a scope of 'Test'
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = "https://localhost",
BackchannelHttpHandler = BackChannelHandler,
...
});
...
}
}
Assigning the AuthServer.Handler to TestApi BackChannelHandler in my unit test project:
protected TestServer AuthServer { get; set; }
protected TestServer MockApiServer { get; set; }
protected TestServer TestApiServer { get; set; }
[OneTimeSetUp]
public void Setup()
{
...
AuthServer = TestServer.Create<AuthenticationServer.Startup>();
TestApi.Startup.BackChannelHandler = AuthServer.CreateHandler();
TestApiServer = TestServer.Create<TestApi.Startup>();
}
The trick is to create a handler using the TestServer that is configured to use IdentityServer4. Samples can be found here.
I created a nuget-package available to install and test using the Microsoft.AspNetCore.Mvc.Testing library and the latest version of IdentityServer4 for this purpose.
It encapsulates all the infrastructure code necessary to build an appropriate WebHostBuilder which is then used to create a TestServer by generating the HttpMessageHandler for the HttpClient used internally.
None of the other answers worked for me because they rely on 1) a static field to hold your HttpHandler and 2) the Startup class to have knowledge that it may be given a test handler. I've found the following to work, which I think is a lot cleaner.
First create an object that you can instantiate before your TestHost is created. This is because you won't have the HttpHandler until after the TestHost is created, so you need to use a wrapper.
public class TestHttpMessageHandler : DelegatingHandler
{
private ILogger _logger;
public TestHttpMessageHandler(ILogger logger)
{
_logger = logger;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
_logger.Information($"Sending HTTP message using TestHttpMessageHandler. Uri: '{request.RequestUri.ToString()}'");
if (WrappedMessageHandler == null) throw new Exception("You must set WrappedMessageHandler before TestHttpMessageHandler can be used.");
var method = typeof(HttpMessageHandler).GetMethod("SendAsync", BindingFlags.Instance | BindingFlags.NonPublic);
var result = method.Invoke(this.WrappedMessageHandler, new object[] { request, cancellationToken });
return await (Task<HttpResponseMessage>)result;
}
public HttpMessageHandler WrappedMessageHandler { get; set; }
}
Then
var testMessageHandler = new TestHttpMessageHandler(logger);
var webHostBuilder = new WebHostBuilder()
...
services.PostConfigureAll<JwtBearerOptions>(options =>
{
options.Audience = "http://localhost";
options.Authority = "http://localhost";
options.BackchannelHttpHandler = testMessageHandler;
});
...
var server = new TestServer(webHostBuilder);
var innerHttpMessageHandler = server.CreateHandler();
testMessageHandler.WrappedMessageHandler = innerHttpMessageHandler;

Resources