Maxime FRAPPAT

Hum …no thanks ! – Lordinaire

Page 2 of 18

Managing health check

Do I need an health check ?

When you have an application who calls several middlewares that manage many services, it might be helpful to monitor all that stuff to know if a service is up or down. You can achieve that by using Health Check. It is nothing more than a system that call a service (or a group of services), each specific interval of time, to test if it responds to a request. For example, it can be just a simple check to a specific route of a WebAPI. If it returns a 200, everything is fine. If it returns a 500, you need to do something because your service is down :)

I need a medic !

Let’s start with a simple architecture :

Give me a favor, help me

Your app call 2 services. In that case, it can be great to monitor both of us. Service1 uses HTTP to communicate with the app so it’s easy to call a web request to have the status of that one. For the Service2 it is a little bit different because it uses a socket and, for simplicity, we just want to use web request. The easy way is to start a tiny web server, in the service, with a single route in order to do the health check.

Great, we have two routes to call to check the status of our services but who will do the job ? Surprise, we need a new web server/console app/whateveryouwant to display a monitoring page that will check each X seconds the status of all the services.

Any feedback, doc ?

We are now very happy to have an amazing page with some red and green dots but it’s not entirely satisfying. What if my app can be notified when the status of a service changes ? Let me explain why it can be useful and terrific for your users. In our app, we want to add a chat that uses Service1. With health checks, you can retrieve the status of all your services, including Service1 who is needed to be able to chat.

Your first idea may to call your monitoring page or directly do a health check on Service1 with a polling system but that’s a bad idea. Your application can be used by thousands (hundreds?) of users simultaneously and each of it will do a health check each X seconds ! That’s not even an option. It may be smarter that your app be notified (push notification) when the status of a service changes, by using WebSocket for example. When you receive the notification, you can enable or disable the chat depending on the status of Service1. Amazing !

As we can see, health checks is not very difficult to deal with and can highly increase your application. Your users will thank you :)

C# implementation sample :

 

 

[UWP] FlyoutView control

In a project, I needed a control like the old SettingsFlyout which is now obselete. What I wanted is just a panel that come-and-go with a great animation.

Style


<Style TargetType="flyoutView:FlyoutView">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="flyoutView:FlyoutView">
                <Grid>
                    <Grid x:Name="PART_OVERLAY" Background="{TemplateBinding BackgroundOverlay}" Visibility="Collapsed" />

                    <Grid x:Name="PART_CONTENT">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition />
                        </Grid.RowDefinitions>

                        <Grid.RenderTransform>
                            <CompositeTransform />
                        </Grid.RenderTransform>

                        <ContentControl ContentTemplate="{TemplateBinding HeaderTemplate}" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch" />

                        <ContentPresenter Grid.Row="1" Content="{TemplateBinding Content}" />
                    </Grid>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

The logic

We need to create the storyboards by hand because the content width/height aren’t static.

[TemplatePart(Name = PartOverlay, Type = typeof(Grid))]
[TemplatePart(Name = PartContent, Type = typeof(Grid))]
public partial class FlyoutView : ContentControl
{
    #region Dependency properties

    public static readonly DependencyProperty HeaderTemplateProperty = DependencyProperty.Register(
            "HeaderTemplate", typeof(DataTemplate), typeof(FlyoutView),
            new PropertyMetadata(default(DataTemplate)));

    public DataTemplate HeaderTemplate
    {
        get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
        set { SetValue(HeaderTemplateProperty, value); }
    }

    public static readonly DependencyProperty PlacementProperty = DependencyProperty.Register(
        "Placement", typeof(PlacementType), typeof(FlyoutView),
        new PropertyMetadata(default(PlacementType), OnPlacementChanged));

    public PlacementType Placement
    {
        get { return (PlacementType)GetValue(PlacementProperty); }
        set { SetValue(PlacementProperty, value); }
    }

    public static readonly DependencyProperty UseDismissOvelayProperty = DependencyProperty.Register(
        "UseDismissOvelay", typeof(bool), typeof(FlyoutView),
        new PropertyMetadata(default(bool)));

    public bool UseDismissOvelay
    {
        get { return (bool)GetValue(UseDismissOvelayProperty); }
        set { SetValue(UseDismissOvelayProperty, value); }
    }

    public static readonly DependencyProperty BackgroundOverlayProperty = DependencyProperty.Register(
        "BackgroundOverlay", typeof(SolidColorBrush), typeof(FlyoutView),
        new PropertyMetadata(default(SolidColorBrush)));

    public SolidColorBrush BackgroundOverlay
    {
        get { return (SolidColorBrush)GetValue(BackgroundOverlayProperty); }
        set { SetValue(BackgroundOverlayProperty, value); }
    }

    public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
            "IsOpen", typeof(bool), typeof(FlyoutView),
            new PropertyMetadata(default(bool), OnIsOpenChanged));

    public bool IsOpen
    {
        get { return (bool)GetValue(IsOpenProperty); }
        set { SetValue(IsOpenProperty, value); }
    }

    public static readonly DependencyProperty ContentWidthProperty = DependencyProperty.Register(
        "ContentWidth", typeof(double), typeof(FlyoutView),
        new PropertyMetadata(default(double)));

    public double ContentWidth
    {
        get { return (double)GetValue(ContentWidthProperty); }
        set { SetValue(ContentWidthProperty, value); }
    }

    public static readonly DependencyProperty ContentHeightProperty = DependencyProperty.Register(
        "ContentHeight", typeof(double), typeof(FlyoutView),
        new PropertyMetadata(default(double)));

    public double ContentHeight
    {
        get { return (double)GetValue(ContentHeightProperty); }
        set { SetValue(ContentHeightProperty, value); }
    }

    #endregion

    #region Properties

    public enum PlacementType
    {

        Left,
        Top,
        Right,
        Bottom
    }

    private const string PartOverlay = "PART_OVERLAY";
    private const string PartContent = "PART_CONTENT";

    private Storyboard _openStoryboard;
    private Storyboard _closeStoryboard;
    private Grid _content;
    private Grid _overlay;

    #endregion

    #region Constructor

    public FlyoutView()
    {
        DefaultStyleKey = typeof(FlyoutView);
    }

    #endregion

    #region Override

    protected override void OnApplyTemplate()
    {
        _overlay = GetTemplateChild(PartOverlay) as Grid;
        _content = GetTemplateChild(PartContent) as Grid;

        if (_content != null)
        {
            _content.Loaded += OnContentLoaded;
            HandleOpening();
        }

        if (_overlay != null)
            _overlay.Tapped += OnOverlayTapped;

        UpdateFromLayout();

        base.OnApplyTemplate();
    }

    #endregion

    #region Methods

    private void UpdateFromLayout()
    {
        if (_content == null || _overlay == null)
            return;

        double overflow;
        if (Placement == PlacementType.Left
            || Placement == PlacementType.Right)
            overflow = Placement == PlacementType.Left
                ? -ContentWidth
                : ContentWidth;
        else
            overflow = Placement == PlacementType.Top
                ? -ContentHeight
                : ContentHeight;

        UpdatePlacement(overflow);
        UpdateAnimations(overflow);
    }

    private void UpdatePlacement(double overflow)
    {
        if (Placement == PlacementType.Left
            || Placement == PlacementType.Right)
        {
            _content.Width = ContentWidth;
            _content.Height = double.NaN;
            _content.RenderTransform = new CompositeTransform { TranslateX = overflow, TranslateY = 0 };
            _content.HorizontalAlignment = Placement == PlacementType.Left
                ? HorizontalAlignment.Left
                : HorizontalAlignment.Right;
            _content.VerticalAlignment = VerticalAlignment.Stretch;
        }
        else
        {
            _content.Width = double.NaN;
            _content.Height = ContentHeight;
            _content.RenderTransform = new CompositeTransform { TranslateX = 0, TranslateY = overflow };
            _content.VerticalAlignment = Placement == PlacementType.Top
                ? VerticalAlignment.Top
                : VerticalAlignment.Bottom;
            _content.HorizontalAlignment = HorizontalAlignment.Stretch;
        }
    }

    private void UpdateAnimations(double overflow)
    {
        var targetProperty = Placement == PlacementType.Left || Placement == PlacementType.Right
            ? "(UIElement.RenderTransform).(CompositeTransform.TranslateX)"
            : "(UIElement.RenderTransform).(CompositeTransform.TranslateY)";

        // Create animations
        _openStoryboard = new Storyboard();
        var openAnimation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(500),
            From = overflow,
            To = 0,
            EasingFunction = new PowerEase { EasingMode = EasingMode.EaseIn, Power = 2 }
        };
        Storyboard.SetTargetProperty(openAnimation, targetProperty);
        Storyboard.SetTarget(openAnimation, _content);
        _openStoryboard.Children.Add(openAnimation);

        _closeStoryboard = new Storyboard();
        var closeAnimation = new DoubleAnimation
        {
            Duration = TimeSpan.FromMilliseconds(500),
            From = 0,
            To = overflow,
            EasingFunction = new PowerEase { EasingMode = EasingMode.EaseOut, Power = 2 }
        };
        Storyboard.SetTargetProperty(closeAnimation, targetProperty);
        Storyboard.SetTarget(closeAnimation, _content);
        _closeStoryboard.Children.Add(closeAnimation);
    }

    #endregion

    #region Events

    private void OnContentLoaded(object sender, object o)
    {
        _content.Loaded -= OnContentLoaded;

        UpdateFromLayout();
    }

    private void OnOverlayTapped(object sender, TappedRoutedEventArgs e)
    {
        if (IsOpen)
            IsOpen = false;
    }

    private static void OnIsOpenChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var control = sender as FlyoutView;

        control?.HandleOpening();
    }

    private void HandleOpening()
    {
        if (IsOpen)
        {
            if (UseDismissOvelay)
                _overlay.Visibility = Visibility.Visible;

            _openStoryboard?.Begin();
        }
        else
        {
            if (UseDismissOvelay)
                _overlay.Visibility = Visibility.Collapsed;

            _closeStoryboard?.Begin();
        }
    }

    private static void OnPlacementChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
    {
        var control = sender as FlyoutView;

        control?.UpdateFromLayout();
    }

    #endregion
}

Usage

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Image Width="300" Height="300" Source="ms-appx:///Assets/ToolkitLogo.png" />

    <flyoutView:FlyoutView IsOpen="{Binding Path=IsOpen.Value, Mode=TwoWay}" Placement="{Binding Path=Placement.Value, Mode=TwoWay}" UseDismissOvelay="True" BackgroundOverlay="#BBF0F0F0" ContentWidth="300" ContentHeight="150">
        <flyoutView:FlyoutView.HeaderTemplate>
            <DataTemplate>
                <Grid Background="{StaticResource Brush-Grey-02}">
                    <TextBlock Text="{Binding Path=Header.Value}" Style="{StaticResource HeaderTextBlockStyle}" Margin="20" />
                </Grid>
            </DataTemplate>
        </flyoutView:FlyoutView.HeaderTemplate>

        <Grid Background="{StaticResource Brush-Grey-03}">
            <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="This is the content" VerticalAlignment="Center" Style="{StaticResource SubtitleTextBlockStyle}" />
        </Grid>
    </flyoutView:FlyoutView>
</Grid>

Demo

Page 2 of 18

Powered by WordPress & Theme by Anders Norén

%d bloggers like this: