Alan Grgic
@spellgrgicright
- Software Development
- Board Games
- Metal Music
- Corgis
- Beverages
- HttpClient
- async/await
- Compiler settings
- Image Optimizations
- Binding Optimizations
- Layout Optimizations
- you miss out on the benefits of keep-alive even though it is being used
- a new socket is opened each time a request is made
- each of those sockets stays open because of keep-alive
- executing lots of requests quickly makes the server run out of sockets
- your app is doing unnecessary work and your server is weeping in agony
using (var client = new HttpClient())
{
// do stuff with the http client
}
public class MyClient
{
private static HttpClient _client = new HttpClient();
public Task<HttpResponseMessage> Get(string uri)
{
return _client.GetAsync(uri);
}
}
public class MyClient
{
private static HttpClient _client = BuildClient();
public Task<HttpResponseMessage> Get(string uri)
{
return _client.GetAsync(uri);
}
private static HttpClient BuildClient(){
{
var httpClient = new HttpClient();
var header = new StringWithQualityHeaderValue("gzip");
httpClient.DefaultRequestHeaders.AcceptEncoding.Add(header);
return httpClient;
}
}
public class MyClient
{
private static HttpClient _client = new HttpClient();
public async Task<Stream> GetStream(string uri)
{
var response = await _httpClient.GetAsync("http://abigfile.com");
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStreamAsync();
}
}
public class MyClient
{
private static HttpClient _client = new HttpClient();
public async Task<Stream> GetStream(string uri)
{
var response = await _httpClient.GetAsync("http://abigfile.com",
HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStreamAsync();
}
}
public class MyClient
{
private static HttpClient _client = new HttpClient();
private static JsonSerializer _serializer = new JsonSerializer();
public async Task<T> Get(string uri)
{
var response = await _httpClient.GetAsync("http://somejson.com",
HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
using (var stream = await response.Content.ReadAsStreamAsync())
using (var reader = new StreamReader(stream))
using (var json = new JsonTextReader(reader))
{
return _serializer.Deserialize<T>(json);
}
}
}protected override async void OnAppearing()
{
await _viewModel.LoadOrderInfoAsync();
}protected override void OnAppearing()
{ // "fire and forget"
_viewModel.LoadOrderInfoAsync().WithErrorHandling();
}
public static class TaskExtensions
{
// one async void to rule them all
public static async void WithErrorHandling(this Task task)
{
try
{
await task;
}
catch (Exception ex)
{
// log and show a sytem dialog or something
}
}
}public async Task LoadOrderAsync()
{
await _viewModel.LoadBasicOrderInfoAsync();
await _viewModel.LoadOrderItemsAsync();
}public void LoadOrderAsync()
{
_viewModel.LoadBasicOrderInfoAsync();
_viewModel.LoadOrderItemsAsync();
}public void LoadOrderAsync()
{
_viewModel.LoadBasicOrderInfoAsync().Wait();
_viewModel.LoadOrderItemsAsync().Wait();
}public async Task LoadOrderAsync()
{
var order = _viewModel.LoadBasicOrderInfoAsync();
var items = _viewModel.LoadOrderItemsAsync();
await Task.WhenAll(order, items);
}
// instead of this
public async Task GetOrderAsync()
{
return await _myClient.GetAsync<Order>("https://getymyorder.com");
}
// try this
public Task GetOrderAsync()
{
return _myClient.GetAsync<Order>("https://getymyorder.com");
}public async Task LoadOrderAsync()
{
var order = _viewModel.LoadBasicOrderInfoAsync();
var items = _viewModel.LoadOrderItemsAsync();
await Task.WhenAll(order, items).ConfigureAwait(false);
}| Setting | Behavior | Ideal For |
|---|---|---|
| Don't Link | Include all of Mono and Xamarin | Debugging |
| Link SDK Assemblies | Remove unused Xamarin and Mono code | "safe/lazy" release builds |
| Link All Assemblies | Remove all unused code (from all 3rd party libraries, plus your own code)* | optimized release builds |
* Including stuff you might not want removed. Use Preserve attributes!
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<AndroidEnableProfiledAot>true</AndroidEnableProfiledAot>
</PropertyGroup>In Android Studio...
<Image
HorizontalOptions="CenterAndExpand"
VerticalOptions ="CenterAndExpand">
<Image.Source>
<UriImageSource Uri="{Binding Image}"
CacheValidity="14"
CachingEnabled="true"/>
</Image.Source>
</Image><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:DataBindingDemos"
x:Class="DataBindingDemos.CompiledColorSelectorPage"
Title="Compiled Color Selector">
<StackLayout x:DataType="local:HslColorViewModel">
<StackLayout.BindingContext>
<local:HslColorViewModel Color="Sienna" />
</StackLayout.BindingContext>
<StackLayout Margin="10, 0">
<Label Text="{Binding Name}" />
<Slider Value="{Binding Hue}" />
<Label Text="{Binding Hue, StringFormat='Hue = {0:F2}'}" />
<Slider Value="{Binding Saturation}" />
<Label Text="{Binding Saturation, StringFormat='Saturation = {0:F2}'}" />
<Slider Value="{Binding Luminosity}" />
<Label Text="{Binding Luminosity, StringFormat='Luminosity = {0:F2}'}" />
</StackLayout>
</StackLayout>
</ContentPage>8-20x Performance improvement, depending on Binding Mode!
| Binding Mode | Behavior |
|---|---|
| TwoWay | data goes both ways |
| OneWay | data goes from source to target |
| OneWayToSource | data goes from target to source |
| OneTime | data goes from source to target, but only when the BindingContext changes |
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Name:" />
<Entry Placeholder="Enter your name" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Age:" />
<Entry Placeholder="Enter your age" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Occupation:" />
<Entry Placeholder="Enter your occupation" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Address:" />
<Entry Placeholder="Enter your address" />
</StackLayout>
</StackLayout>
</ContentPage><ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Details.HomePage"
Padding="0,20,0,0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
<RowDefinition Height="30" />
</Grid.RowDefinitions>
<Label Text="Name:" />
<Entry Grid.Column="1" Placeholder="Enter your name" />
<Label Grid.Row="1" Text="Age:" />
<Entry Grid.Row="1" Grid.Column="1" Placeholder="Enter your age" />
<Label Grid.Row="2" Text="Occupation:" />
<Entry Grid.Row="2" Grid.Column="1" Placeholder="Enter your occupation" />
<Label Grid.Row="3" Text="Address:" />
<Entry Grid.Row="3" Grid.Column="1" Placeholder="Enter your address" />
</Grid>
</ContentPage>Alan Grgic
@spellgrgicright