AppBeat Blog

Perfect Monitoring for Your Cloud

.NET library for detecting temporary / disposable email addresses


We published open-source, simple and easy to use .NET Standard 2.0 library with some useful utilities.

For example, you can now easily check if email address is temporary / disposable. With string extension methods this can be as easy as following:

bool isTemporary = "".IsTemporaryEmail(); //true

Current implementation is offline (known temporary domains are "baked in") and for this reason also very fast.

GitHub repository with examples:

Our official NuGet Package for this library:

We plan to upgrade this in future and add some more useful functions.

Please let us know if you have any questions or suggestions.

Coming soon: recurring unmonitored time functionality

Soon you will be able to define recurring time periods when service and all its child checks will be temporary excluded from monitoring:

This may be useful for some customers who don't need 24/7 monitoring and don't want to use our API integration to pause / resume service with web services.

New feature will be added as part of our 1.8.0 application version upgrade in it is scheduled to be publicly available in beginning of 2018.

Stay tuned :)

Migration of our monitoring stack to .NET Core 2.0 and .NET Standard 2.0

After successful migration of our monitoring front-end, back-end and microservices to .NET Core 2.0 and .NET Standard 2.0, here is quick summary of this process.

Migration decision

Although we were very very satisfied with .NET Core 1.0, we decided for migration to newest version for following reasons:

  • bigger API and more libraries available (thanks to .NET Standard 2.0)
  • much easier to share common internal projects between .NET Core 2.0 and Full .NET Framework on Windows (.NET Framework 4.6.1 and newer)
  • security and performance improvements


We started official migration from .NET Core 1.0 as soon as Microsoft released RTM version of .NET Core 2.0 and Visual Studio tooling. Entire process went quite smoothly and without major issues. We followed official instructions published on Microsoft Docs (very useful).

During migration, most time was spent for resolving NuGet conflicts and we also encountered one runtime problem with Entity Framework Core 2.0 - we resolved this by doing simple workaround and rewriting this one problematic query. Everything else was - perfect!


Our migrated solution is now deployed on Windows and Linux production servers and everything runs without any issues. Improvements on web front-end are very noticeable (Kestrel, compiled MVC views, smaller deployments). Mission accomplished!

Thanks to Microsoft and all open source contributors for making such a great product!

Implementing WebDriverIO support in .NET Core 2.0 for efficient Selenium testing

We are currently implementing experimental subset of WebDriverIO API (higher level API on top of Selenium WebDriver) in .NET Core so we could run synthetic (transaction) monitoring very efficiently from different geographic locations.

Implementation goals:

  • cross-platform, efficient and lightweight framework
  • easy to use (REST API / web interface)
  • high compatiblity with WebDriverIO because users are already familiar with it
  • for security reasons we will probably implement simple JavaScript interpreter for WebDriverIO commands (instead of running tests in Node.js)

Currently we have basic prototype but it looks very promising:

If you have any ideas or suggestions, please let us know!

How to build .NET Microservices

We would like to share with you very interesting NDC Conference session from Sydney which describes pros and cons of a microservices solution and how you can build one using .NET and a number of open source tools like EventStore, RabbitMq and Redis.

Presentation was done by Richard Banks and you can watch it on YouTube:

Robust and affordable Browser as a Service (BaaS)

That is our goal for next year!

We want to offer you real browsers, for example Chrome and Firefox, so you can periodically check if your web application always behaves as it should.

This kind of service will be very useful for your continuous integration and testing your website after you deploy new version into production environment.

If you would like to participate in closed beta, please contact us.

C# method for very fast and efficient traceroute (network diagnostic tool)

We like C#, .NET and .NET Core!

Last time we played a little bit with traceroute utility and thought, could we write something fast, efficient, and since we love Asynchronous Programming with async and await (C#), something that would include this pattern as well?

Here is what we came up with :)

using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;

namespace AppBeat.Core.Utility
    public class TraceRoute
        private const string DATA = "AppBeat Monitoring - - AppBeat Monitoring"; //60 Bytes
        private static readonly byte[] _buffer = Encoding.ASCII.GetBytes(DATA);
        private const int MAX_HOPS = 15;
        private const string STR_REQUEST_TIMEOUT = "Request timed out.";
        private const string STR_REQUEST_TIME_NA = "*";
        private const int REQUEST_TIMEOUT = 4000;

        /// <summary>
        /// Runs traceroute and writes result to console.
        /// </summary>
        public static async Task TryTraceRouteAsync(string hostNameOrAddress)

            using (var console = Console.OpenStandardOutput())
            using (var sw = new StreamWriter(console))
                await TryTraceRouteAsync(hostNameOrAddress, sw);

        /// <summary>
        /// Runs traceroute and writes result to provided stream.
        /// </summary>
        public static async Task TryTraceRouteAsync(string hostNameOrAddress, StreamWriter outputStreamWriter)
            if (outputStreamWriter == null)
                throw new ArgumentNullException(nameof(outputStreamWriter));

            await outputStreamWriter.WriteLineAsync($"traceroute to {hostNameOrAddress}, {MAX_HOPS} hops max, {_buffer.Length} byte packets");

            //dispatch parallel tasks for each hop
            var arrTraceRouteTasks = new Task<TraceRouteResult>[MAX_HOPS];
            for (int zeroBasedHop = 0; zeroBasedHop < MAX_HOPS; zeroBasedHop++)
                arrTraceRouteTasks[zeroBasedHop] = TryTraceRouteInternalAsync(hostNameOrAddress, zeroBasedHop);

            //and wait for them to finish
            await Task.WhenAll(arrTraceRouteTasks);

            //now just collect all results and write them to output stream
            for (int hop = 0; hop < MAX_HOPS; hop++)
                var traceTask = arrTraceRouteTasks[hop];
                if (traceTask.Status == TaskStatus.RanToCompletion)
                    var res = traceTask.Result;
                    await outputStreamWriter.WriteLineAsync(res.Message);

                    if (res.IsComplete)
                        //trace complete
                    await outputStreamWriter.WriteLineAsync($"Could not get result for hop #{hop + 1}");

        private static void EnsureCommonArguments(string hostNameOrAddress)
            if (hostNameOrAddress == null)
                throw new ArgumentNullException(nameof(hostNameOrAddress));

            if (string.IsNullOrWhiteSpace(hostNameOrAddress))
                throw new ArgumentException("Hostname or address is required", nameof(hostNameOrAddress));

        public class TraceRouteResult
            public TraceRouteResult(string message, bool isComplete)
                Message = message;
                IsComplete = isComplete;

            public string Message
                get; private set;

            public bool IsComplete
                get;private set;

        public static async Task<TraceRouteResult> TryTraceRouteInternalAsync(string hostNameOrAddress, int zeroBasedHop)
            using (Ping pingSender = new Ping())
                var hop = zeroBasedHop + 1;

                PingOptions pingOptions = new PingOptions();
                Stopwatch stopWatch = new Stopwatch();
                pingOptions.DontFragment = true;
                pingOptions.Ttl = hop;


                PingReply pingReply = await pingSender.SendPingAsync(


                var elapsedMilliseconds = stopWatch.ElapsedMilliseconds;

                string pingReplyAddress;
                string strElapsedMilliseconds;

                if (pingReply.Status == IPStatus.TimedOut)
                    pingReplyAddress = STR_REQUEST_TIMEOUT;
                    strElapsedMilliseconds = STR_REQUEST_TIME_NA;
                    pingReplyAddress = pingReply.Address.ToString();
                    strElapsedMilliseconds = $"{elapsedMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture)} ms";

                var traceResults = new StringBuilder();
                traceResults.Append(hop.ToString(System.Globalization.CultureInfo.InvariantCulture).PadRight(4, ' '));
                traceResults.Append(strElapsedMilliseconds.PadRight(10, ' '));

                return new TraceRouteResult(traceResults.ToString(), pingReply.Status == IPStatus.Success);

Method above basically dispatches 15 parallel (asynchronous) tasks and waits for their result. For this reason it is really fast compared to standard implementation, which would do only one step at a time, and wait for each step (15 times in a row).

Hopefully you will find this useful :)

Coming soon: multi expression rules for better monitoring experience

Very soon we will add multi expression support for Warning and Error notification rules. Syntax will be as following:

[trigger_rule: YOUR_RULE_NAME_1]

[trigger_rule: YOUR_RULE_NAME_2]

[trigger_rule: YOUR_RULE_NAME_N]

On user interface this will look something like this:

This example rule then triggers "Warning" notification which is sent to you and it is also visible in monitor log:


Source code for our website monitoring command line tool

As we have previously promised, we published full source code of our cross-platform website monitoring command line tool. You can get it from

Tool is written in C# and targets cross-platform .NET Core framework. This means you can run it on Windows, Linux or Mac.

Tool currently supports following commands:

AppBeat Command Line Interface for monitoring automation, version 1.0.0
Usage: dotnet AppBeat.CLI.dll [command] [options]

  help                Displays this help.

  link                Links this command line tool with your AppBeat account by providing secret access key.

  unlink              Unlinks this command line tool from your AppBeat account.

  status              Returns current status overview of your system with all services and checks.

  list                Lists active checks or services and returns unique identifier for each resource (resource identifiers).

  pause               Pauses check(s) and/or service(s) by using resource identifiers.

  resume              Resumes check(s) and/or service(s) by using resource identifiers.

  new-check           Creates new AppBeat check (periodic monitor) from json settings provided by UTF-8 encoded input file or standard input.

  delete              Permanently deletes check(s) and/or service(s) by using resource identifiers.

If you have any questions or ideas for improvement, please contact us at any time.