public async void Subscribe_HttpHeaderDiscoveryUrl_PostsToHttpHeaderDiscoveryHubUrl()
        {
            Mock <HttpClient> webSubRocksHttpClientMock = PrepareWebSubRocksHttpClientMock();
            WebSubSubscriber  webSubSubscriber          = PrepareWebSubRocksWebSubSubscriber(webSubRocksHttpClientMock.Object);

            WebSubSubscribedUrls webSubSubscription = await webSubSubscriber.SubscribeAsync(new WebSubSubscribeParameters(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_URL, WebSubRocksConstants.WEBHOOK_URL), CancellationToken.None);

            webSubRocksHttpClientMock.Verify(m => m.SendAsync(It.Is <HttpRequestMessage>(request => (request.Method == HttpMethod.Post) && (request.RequestUri.AbsoluteUri == WebSubRocksConstants.HTTP_HEADER_DISCOVERY_HUB_URL)), CancellationToken.None), Times.Once);
        }
        public async void Subscribe_HttpHeaderDiscoveryUrl_HubTopicParameterEqualsHttpHeaderDiscoveryTopicUrl()
        {
            Mock <HttpClient> webSubRocksHttpClientMock = PrepareWebSubRocksHttpClientMock();
            WebSubSubscriber  webSubSubscriber          = PrepareWebSubRocksWebSubSubscriber(webSubRocksHttpClientMock.Object);

            WebSubSubscribedUrls webSubSubscription = await webSubSubscriber.SubscribeAsync(new WebSubSubscribeParameters(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_URL, WebSubRocksConstants.WEBHOOK_URL), CancellationToken.None);

            webSubRocksHttpClientMock.Verify(m => m.SendAsync(It.Is <HttpRequestMessage>(request => request.Content.ReadAsStringAsync().Result.Contains($"{HUB_TOPIC_PARAMETER_NAME}={WebUtility.UrlEncode(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_TOPIC_URL)}")), CancellationToken.None), Times.Once);
        }
        public async void Subscribe_CallsDiscoverWithContentUrl()
        {
            Mock <IWebSubDiscoverer> webSubRocksDiscovererMock = PrepareWebSubRocksDiscovererMock();
            WebSubSubscriber         webSubSubscriber          = PrepareWebSubRocksWebSubSubscriber(webSubRocksDiscoverer: webSubRocksDiscovererMock.Object);

            WebSubSubscribedUrls webSubSubscription = await webSubSubscriber.SubscribeAsync(new WebSubSubscribeParameters(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_URL, WebSubRocksConstants.WEBHOOK_URL), CancellationToken.None);

            webSubRocksDiscovererMock.Verify(m => m.DiscoverAsync(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_URL, CancellationToken.None), Times.Once);
        }
        public async void Subscribe_HttpHeaderDiscoveryUrlNoSecret_HubSecretParameterNotPresent()
        {
            Mock <HttpClient> webSubRocksHttpClientMock = PrepareWebSubRocksHttpClientMock();
            WebSubSubscriber  webSubSubscriber          = PrepareWebSubRocksWebSubSubscriber(webSubRocksHttpClientMock.Object);

            WebSubSubscribedUrls webSubSubscription = await webSubSubscriber.SubscribeAsync(new WebSubSubscribeParameters(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_URL, WebSubRocksConstants.WEBHOOK_URL), CancellationToken.None);

            webSubRocksHttpClientMock.Verify(m => m.SendAsync(It.Is <HttpRequestMessage>(request => request.Content.ReadAsStringAsync().Result.Contains($"{HUB_SECRET_PARAMETER_NAME}=")), CancellationToken.None), Times.Never);
        }
        public async void Subscribe_HttpHeaderDiscoveryUrlWithLeaseSeconds_HubLeaseSecondsParameterEqualsLeaseSeconds()
        {
            Mock <HttpClient> webSubRocksHttpClientMock = PrepareWebSubRocksHttpClientMock();
            WebSubSubscriber  webSubSubscriber          = PrepareWebSubRocksWebSubSubscriber(webSubRocksHttpClientMock.Object);

            WebSubSubscribedUrls webSubSubscription = await webSubSubscriber.SubscribeAsync(new WebSubSubscribeParameters(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_URL, WebSubRocksConstants.WEBHOOK_URL) { LeaseSeconds = LEASE_SECONDS }, CancellationToken.None);

            webSubRocksHttpClientMock.Verify(m => m.SendAsync(It.Is <HttpRequestMessage>(request => request.Content.ReadAsStringAsync().Result.Contains($"{HUB_LEASE_SECONDS_PARAMETER_NAME}={LEASE_SECONDS.ToString(CultureInfo.InvariantCulture)}")), CancellationToken.None), Times.Once);
        }
        public async void Unsubscribe_HttpHeaderDiscoverySubscribedUrls_HubCallbackParameterEqualsWebHookUrl()
        {
            WebSubSubscribedUrls httpHeaderDiscoverySubscribedUrls = new WebSubSubscribedUrls(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_TOPIC_URL, WebSubRocksConstants.HTTP_HEADER_DISCOVERY_HUB_URL);
            Mock <HttpClient>    webSubRocksHttpClientMock         = PrepareWebSubRocksHttpClientMock();
            WebSubSubscriber     webSubSubscriber = PrepareWebSubRocksWebSubSubscriber(webSubRocksHttpClientMock.Object);

            bool accepted = await webSubSubscriber.UnsubscribeAsync(httpHeaderDiscoverySubscribedUrls, WebSubRocksConstants.WEBHOOK_URL, CancellationToken.None);

            webSubRocksHttpClientMock.Verify(m => m.SendAsync(It.Is <HttpRequestMessage>(request => request.Content.ReadAsStringAsync().Result.Contains($"{HUB_CALLBACK_PARAMETER_NAME}={WebUtility.UrlEncode(WebSubRocksConstants.WEBHOOK_URL)}")), CancellationToken.None), Times.Once);
        }
        public async void Unsubscribe_HttpHeaderDiscoverySubscribedUrls_PostsToHttpHeaderDiscoveryHubUrl()
        {
            WebSubSubscribedUrls httpHeaderDiscoverySubscribedUrls = new WebSubSubscribedUrls(WebSubRocksConstants.HTTP_HEADER_DISCOVERY_TOPIC_URL, WebSubRocksConstants.HTTP_HEADER_DISCOVERY_HUB_URL);
            Mock <HttpClient>    webSubRocksHttpClientMock         = PrepareWebSubRocksHttpClientMock();
            WebSubSubscriber     webSubSubscriber = PrepareWebSubRocksWebSubSubscriber(webSubRocksHttpClientMock.Object);

            bool accepted = await webSubSubscriber.UnsubscribeAsync(httpHeaderDiscoverySubscribedUrls, WebSubRocksConstants.WEBHOOK_URL, CancellationToken.None);

            webSubRocksHttpClientMock.Verify(m => m.SendAsync(It.Is <HttpRequestMessage>(request => (request.Method == HttpMethod.Post) && (request.RequestUri.AbsoluteUri == WebSubRocksConstants.HTTP_HEADER_DISCOVERY_HUB_URL)), CancellationToken.None), Times.Once);
        }
        public async Task <SubscriptionViewModel> Subscribe(SubscribeViewModel subscribeViewModel, WebSubSubscriber webSubSubscriber)
        {
            if (!ModelState.IsValid)
            {
                return(new SubscriptionViewModel(ModelState));
            }

            WebSubSubscription webSubSubscription = null;

            try
            {
                webSubSubscription = await _webSubSubscriptionsStore.CreateAsync();

                webSubSubscription.CallbackUrl = Request.GetWebSubWebHookUrl(webSubSubscription.Id);

                WebSubSubscribeParameters webSubSubscribeParameters = new WebSubSubscribeParameters(subscribeViewModel.Url, webSubSubscription.CallbackUrl)
                {
                    OnDiscoveredAsync = async(WebSubDiscoveredUrls discovery, CancellationToken cancellationToken) =>
                    {
                        webSubSubscription.State    = WebSubSubscriptionState.SubscribeRequested;
                        webSubSubscription.TopicUrl = discovery.Topic;

                        await _webSubSubscriptionsStore.UpdateAsync(webSubSubscription);
                    }
                };

                if (!String.IsNullOrWhiteSpace(subscribeViewModel.Secret))
                {
                    webSubSubscription.Secret        = subscribeViewModel.Secret;
                    webSubSubscribeParameters.Secret = subscribeViewModel.Secret;
                }


                webSubSubscription.HubUrl = (await webSubSubscriber.SubscribeAsync(webSubSubscribeParameters, HttpContext.RequestAborted)).Hub;

                return(new SubscriptionViewModel(webSubSubscription));
            }
            catch (Exception ex) when((ex is WebSubDiscoveryException) || (ex is WebSubSubscriptionException))
            {
                await _webSubSubscriptionsStore.RemoveAsync(webSubSubscription);

                return(new SubscriptionViewModel(ex));
            }
        }