public async Task <IHttpActionResult> DeletePersonalResource(int id)
        {
            var userId = this.GetUserId();
            await DapperHelper.ExecuteResilientlyAsync("dbo.libDeletePersonalResource",
                                                       new
            {
                UserId     = userId,
                ResourceId = id,
            },
                                                       CommandType.StoredProcedure);

            var indexHelper = new PersonalIndexHelper(DapperHelper.GetConnectionString());
            await indexHelper.IndexUserResource(CancellationToken.None, userId, id, false);

            // The client immidiately re-requests personal categories at the end of the delete operation. Ensure Azure Search keeps pace. BTW, there is additional delay in JS on the client side.
            await Task.Delay(1000);

            return(StatusCode(HttpStatusCode.NoContent));
        }
        public async Task <IHttpActionResult> PostResource(ResourceDto resource)
        {
            ResourceDto result;

            // In the case of a new resource Id is not passed. In the case of a common resource Id has a value.
            if (resource.Id == 0)
            {
                var newResource = await LibraryUtils.TryValidateResource(resource.Url);

                // If validation is unsuccessfull, TryValidateResource returns null
                if (newResource != null)
                {
                    resource.Format     = newResource.Format;
                    resource.NaturalKey = newResource.NaturalKey;
                    resource.Title      = newResource.Title ?? resource.Title;
                    resource.HasVideo   = newResource.HasVideo || resource.HasVideo;
                }
                else
                {
                    resource.NaturalKey = null;
                }
            }

            if (resource.NaturalKey != null)
            {
                var userId = this.GetUserId();
                // Idempotent
                result = (await DapperHelper.QueryResilientlyAsync <ResourceDto>("dbo.libCreatePersonalResource",
                                                                                 new
                {
                    UserId = userId,
                    Id = resource.Id,
                    Format = resource.Format,
                    NaturalKey = resource.NaturalKey,
                    Segment = resource.Segment,
                    Title = resource.Title,
                    CategoryIds = GeneralUtils.SanitizeSpaceSeparatedWords(resource.CategoryIds),
                    Tags = GeneralUtils.SanitizeSpaceSeparatedWords((resource.Tags ?? "").Replace("-", String.Empty).ToLower()),
                    SourceId = resource.SourceId,
                    HasExplanation = resource.HasExplanation,
                    HasExample = resource.HasExample,
                    HasExercise = resource.HasExercise,
                    HasText = resource.HasText,
                    HasPicture = resource.HasPicture,
                    HasAudio = resource.HasAudio,
                    HasVideo = resource.HasVideo,
                    Comment = resource.Comment,
                },
                                                                                 CommandType.StoredProcedure))
                         .SingleOrDefault();

                // Update the search index.
                var indexHelper = new PersonalIndexHelper(DapperHelper.GetConnectionString());
                if (resource.Id == 0)
                {
                    // A new resource is added on the Personal tab. It is waiting to update the category list. Update the index ASAP.
                    await indexHelper.IndexUserResource(CancellationToken.None, userId, result.Id, true);
                }
                else
                {
                    // If a common resource is added to the personal collection, update the search index in background. Return response early.
                    //// If this task fails, the WebJob will process everything.
                    //var queueTask = AzureStorageUtils.QueueMessage(
                    //    AzureStorageUtils.WebJobsConnectionStringName,
                    //    AzureStorageUtils.QueueNames.IndexPersonal,
                    //    userId.ToString() + " " + resourceId.ToString()
                    //    );
                    //await Task.WhenAll(dbTask, queueTask);
                    HostingEnvironment.QueueBackgroundWorkItem(ct => indexHelper.IndexUserResource(ct, userId, result.Id, true));
                }
            }
            else
            {
                throw new ArgumentException("Wrong web address.");
            }

            return(Ok(result));
        }