diff --git a/src/shortenerTools/Domain/StorageTableHelper.cs b/src/shortenerTools/Domain/StorageTableHelper.cs index 96e9f73d..559b9ced 100644 --- a/src/shortenerTools/Domain/StorageTableHelper.cs +++ b/src/shortenerTools/Domain/StorageTableHelper.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Azure.Cosmos.Table; @@ -34,7 +35,7 @@ private CloudTable GetTable(string tableName){ CloudStorageAccount storageAccount = this.CreateStorageAccountFromConnectionString(); CloudTableClient tableClient = storageAccount.CreateCloudTableClient(new TableClientConfiguration()); CloudTable table = tableClient.GetTableReference(tableName); - table.CreateIfNotExists(); + //table.CreateIfNotExists(); Removed to cut response time in half return table; } @@ -85,6 +86,22 @@ public async Task> GetAllStatsByVanity(string vanity) return lstShortUrl; } + /// + /// Returns the ShortUrlEntity of the + /// + /// + /// ShortUrlEntity + public async Task GetShortUrlEntityByVanity(string vanity) + { + var tempUrl = new ShortUrlEntity(string.Empty, vanity); + return await GetShortUrlEntity(tempUrl); + } + + public async Task IfShortUrlEntityExistByVanity(string vanity) + { + ShortUrlEntity shortUrlEntity = await GetShortUrlEntityByVanity(vanity); + return (shortUrlEntity != null); + } public async Task IfShortUrlEntityExist(ShortUrlEntity row) { diff --git a/src/shortenerTools/Domain/Utility.cs b/src/shortenerTools/Domain/Utility.cs index 2037cc6e..508534c1 100644 --- a/src/shortenerTools/Domain/Utility.cs +++ b/src/shortenerTools/Domain/Utility.cs @@ -1,20 +1,27 @@ using System.Linq; +using System.Security.Cryptography; using System.Threading.Tasks; namespace Cloud5mins.domain { public static class Utility { - private const string Alphabet = "abcdefghijklmnopqrstuvwxyz0123456789"; - private static readonly int Base = Alphabet.Length; + //reshuffled for randomisation, same unique characters just jumbled up, you can replace with your own version + private const string ConversionCode = "FjTG0s5dgWkbLf_8etOZqMzNhmp7u6lUJoXIDiQB9-wRxCKyrPcv4En3Y21aASHV"; + private static readonly int Base = ConversionCode.Length; + //sets the length of the unique code to add to vanity + private const int MinVanityCodeLength = 5; public static async Task GetValidEndUrl(string vanity, StorageTableHelper stgHelper) { - if(string.IsNullOrEmpty(vanity)) + if (string.IsNullOrEmpty(vanity)) { var newKey = await stgHelper.GetNextTableId(); - string getCode() => Encode(newKey); - return string.Join(string.Empty, getCode()); + string randomVanity = Encode(newKey); + if (await stgHelper.IfShortUrlEntityExistByVanity(randomVanity)) + return await GetValidEndUrl(null, stgHelper); + + return string.Join(string.Empty, randomVanity); } else { @@ -25,19 +32,37 @@ public static async Task GetValidEndUrl(string vanity, StorageTableHelpe public static string Encode(int i) { if (i == 0) - return Alphabet[0].ToString(); - var s = string.Empty; - while (i > 0) - { - s += Alphabet[i % Base]; - i = i / Base; - } + return ConversionCode[0].ToString(); - return string.Join(string.Empty, s.Reverse()); + return GenerateUniqueRandomToken(i); } public static string GetShortUrl(string host, string vanity){ return host + "/" + vanity; } + + // generates a unique, random, and alphanumeric token for the use as a url + //(not entirely secure but not sequential so generally not guessable) + public static string GenerateUniqueRandomToken(int uniqueId) + { + //Encode the unique id prefix (less characters and prevent displaying url count) + var s = string.Empty; + while (uniqueId > 0) + { + s += ConversionCode[uniqueId % Base]; + uniqueId = uniqueId / Base; + } + + using (var generator = new RNGCryptoServiceProvider()) + { + //minimum size I would suggest is 5, longer the better but we want short URLs! + var bytes = new byte[MinVanityCodeLength]; + generator.GetBytes(bytes); + var chars = bytes + .Select(b => ConversionCode[b % Base]); + var token = new string(chars.ToArray()); + return string.Join(string.Empty, s.Reverse().Concat(token.Reverse())); + } + } } } \ No newline at end of file diff --git a/src/shortenerTools/OpenApiConfigurationOptions.cs b/src/shortenerTools/OpenApiConfigurationOptions.cs new file mode 100644 index 00000000..e328b884 --- /dev/null +++ b/src/shortenerTools/OpenApiConfigurationOptions.cs @@ -0,0 +1,36 @@ +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Configurations; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; +using Microsoft.OpenApi.Models; +using System; +using System.Collections.Generic; +using System.Text; + +namespace BeaconServices.VINDecoderService.FunctionsApp +{ + public class OpenApiConfigurationOptions : DefaultOpenApiConfigurationOptions + { + public override OpenApiInfo Info { get; set; } = new OpenApiInfo() + { + Version = "1.0.0", + Title = "TRAXERO URL Shortener", + Description = @"### Overview +The TRAXERO URL Shortener API provides a simple way to turn a long url into a short one. View and test the API methods at the bottom of this page. + +An API key is required to use this API. Enter your API key in authorize/api key box to enable testing on this page. + +### URL Redirect + +A short url is provided as part of the response to the /UrlShortener endpoint. To manually reconstruct a short url, append the vanity to the domain name: `https://tows.at/{vanity}`. [Example short url](https://tows.at/TRAXERO) + +Custom domains names can be configured upon request." + }; + + public override List Servers { get; set; } = new List() + { + new OpenApiServer() { Url = "https://tows.at/api/", Description = "Production" }, + }; + + public override OpenApiVersionType OpenApiVersion { get; set; } = OpenApiVersionType.V3; + + } +} diff --git a/src/shortenerTools/UrlArchive/UrlArchive.cs b/src/shortenerTools/UrlArchive/UrlArchive.cs index 03dc0637..7ca451a1 100644 --- a/src/shortenerTools/UrlArchive/UrlArchive.cs +++ b/src/shortenerTools/UrlArchive/UrlArchive.cs @@ -1,14 +1,14 @@ -/* +/* ```c# Input: - { - // [Required] - "PartitionKey": "d", + { + // [Required] + "PartitionKey": "d", - // [Required] - "RowKey": "doc", + // [Required] + "RowKey": "doc", - } + } */ @@ -18,18 +18,18 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; -using System.Net; using System.Net.Http; using Cloud5mins.domain; using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Mvc; namespace Cloud5mins.Function { public static class UrlArchive { [FunctionName("UrlArchive")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req, ILogger log, ExecutionContext context) { @@ -38,13 +38,13 @@ public static async Task Run( // Validation of the inputs if (req == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } ShortUrlEntity input = await req.Content.ReadAsAsync(); if (input == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } ShortUrlEntity result; @@ -63,10 +63,10 @@ public static async Task Run( catch (Exception ex) { log.LogError(ex, "An unexpected error was encountered."); - return req.CreateResponse(HttpStatusCode.BadRequest, ex); + return new BadRequestObjectResult(ex); } - return req.CreateResponse(HttpStatusCode.OK, result); + return new OkObjectResult(result); } } } diff --git a/src/shortenerTools/UrlClickStats/UrlClickStats.cs b/src/shortenerTools/UrlClickStats/UrlClickStats.cs index 8ca98165..1333fb12 100644 --- a/src/shortenerTools/UrlClickStats/UrlClickStats.cs +++ b/src/shortenerTools/UrlClickStats/UrlClickStats.cs @@ -3,17 +3,25 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; -using System.Net; using System.Net.Http; using Cloud5mins.domain; using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; +using Microsoft.OpenApi.Models; +using System.Net; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; namespace Cloud5mins.Function { public static class UrlClickStats { + //[OpenApiOperation(operationId: "UrlClickStats", tags: new[] { "Urls" }, Summary = "Get short URL click stats", Description = "Returns statistics for a specific short URL.", Visibility = OpenApiVisibilityType.Important)] + //[OpenApiRequestBody(contentType: "application/json", bodyType: typeof(UrlClickStatsRequest), Required = true)] + //[OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)] + //[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ClickStatsEntityList))] [FunctionName("UrlClickStats")] - public static async Task Run( + public static async Task Run( [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, ILogger log, ExecutionContext context) @@ -23,13 +31,13 @@ public static async Task Run( // Validation of the inputs if (req == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } UrlClickStatsRequest input = await req.Content.ReadAsAsync(); if (input == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } var result = new ClickStatsEntityList(); @@ -48,10 +56,10 @@ public static async Task Run( catch (Exception ex) { log.LogError(ex, "An unexpected error was encountered."); - return req.CreateResponse(HttpStatusCode.BadRequest, ex); + return new BadRequestObjectResult(ex); } - return req.CreateResponse(HttpStatusCode.OK, result); + return new OkObjectResult(result); } } } diff --git a/src/shortenerTools/UrlList/UrlList.cs b/src/shortenerTools/UrlList/UrlList.cs index 53b46d41..3e4fefb3 100644 --- a/src/shortenerTools/UrlList/UrlList.cs +++ b/src/shortenerTools/UrlList/UrlList.cs @@ -20,20 +20,20 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; -using System.Net; using System.Net.Http; using Cloud5mins.domain; using Microsoft.Extensions.Configuration; using System.Linq; +using Microsoft.AspNetCore.Mvc; namespace Cloud5mins.Function { public static class UrlList { [FunctionName("UrlList")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)]HttpRequestMessage req, - ILogger log, + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "get", Route = null)] HttpRequestMessage req, + ILogger log, ExecutionContext context) { log.LogInformation($"C# HTTP trigger function processed this request: {req}"); @@ -45,24 +45,25 @@ public static async Task Run( .AddEnvironmentVariables() .Build(); - StorageTableHelper stgHelper = new StorageTableHelper(config["UlsDataStorage"]); + StorageTableHelper stgHelper = new StorageTableHelper(config["UlsDataStorage"]); try { - result.UrlList = await stgHelper.GetAllShortUrlEntities(); + result.UrlList = await stgHelper.GetAllShortUrlEntities(); result.UrlList = result.UrlList.Where(p => !(p.IsArchived ?? false)).ToList(); - var host = req.RequestUri.GetLeftPart(UriPartial.Authority); - foreach(ShortUrlEntity url in result.UrlList){ - url.ShortUrl = Utility.GetShortUrl(host, url.RowKey); - } + var host = req.RequestUri.GetLeftPart(UriPartial.Authority); + foreach (ShortUrlEntity url in result.UrlList) + { + url.ShortUrl = Utility.GetShortUrl(host, url.RowKey); + } } catch (Exception ex) { log.LogError(ex, "An unexpected error was encountered."); - return req.CreateResponse(HttpStatusCode.BadRequest, ex); + return new BadRequestObjectResult(ex); } - return req.CreateResponse(HttpStatusCode.OK, result); + return new OkObjectResult(result); } } } diff --git a/src/shortenerTools/UrlRedirect/UrlRedirect.cs b/src/shortenerTools/UrlRedirect/UrlRedirect.cs index a945abbc..9b4e3bac 100644 --- a/src/shortenerTools/UrlRedirect/UrlRedirect.cs +++ b/src/shortenerTools/UrlRedirect/UrlRedirect.cs @@ -3,20 +3,24 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; -using System.Net; using System.Net.Http; using Cloud5mins.domain; -using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; +using Microsoft.OpenApi.Models; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; namespace Cloud5mins.Function { public static class UrlRedirect { + //[OpenApiOperation(operationId: "UrlRedirect", tags: new[] { "Urls" }, Summary = "Redirect short url to long url", Description = "Creates the short version of a URL and returns the result. If no vanity is specified one will be automatically generated for you.", Visibility = OpenApiVisibilityType.Important)] + //[OpenApiParameter(name: "shortUrl", In = ParameterLocation.Path, Required = true, Type = typeof(string), Visibility = OpenApiVisibilityType.Important)] + //[OpenApiResponseWithoutBody(System.Net.HttpStatusCode.Redirect)] [FunctionName("UrlRedirect")] - public static async Task Run( + public static async Task Run( [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = "UrlRedirect/{shortUrl}")] HttpRequestMessage req, - string shortUrl, - ExecutionContext context, + string shortUrl, ILogger log) { log.LogInformation($"C# HTTP trigger function processed for Url: {shortUrl}"); @@ -25,27 +29,21 @@ public static async Task Run( if (!String.IsNullOrWhiteSpace(shortUrl)) { - var config = new ConfigurationBuilder() - .SetBasePath(context.FunctionAppDirectory) - .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) - .AddEnvironmentVariables() - .Build(); + redirectUrl = Environment.GetEnvironmentVariable("defaultRedirectUrl"); - redirectUrl = config["defaultRedirectUrl"]; - - StorageTableHelper stgHelper = new StorageTableHelper(config["UlsDataStorage"]); + StorageTableHelper stgHelper = new StorageTableHelper(Environment.GetEnvironmentVariable("UlsDataStorage")); var tempUrl = new ShortUrlEntity(string.Empty, shortUrl); - + var newUrl = await stgHelper.GetShortUrlEntity(tempUrl); if (newUrl != null) { - log.LogInformation($"Found it: {newUrl.Url}"); + //log.LogInformation($"Found it: {newUrl.Url}"); newUrl.Clicks++; stgHelper.SaveClickStatsEntity(new ClickStatsEntity(newUrl.RowKey)); await stgHelper.SaveShortUrlEntity(newUrl); - redirectUrl = WebUtility.UrlDecode(newUrl.Url); + redirectUrl = newUrl.Url; } } else @@ -53,9 +51,7 @@ public static async Task Run( log.LogInformation("Bad Link, resorting to fallback."); } - var res = req.CreateResponse(HttpStatusCode.Redirect); - res.Headers.Add("Location", redirectUrl); - return res; + return new RedirectResult(redirectUrl); } - } + } } diff --git a/src/shortenerTools/UrlShortener/UrlShortener.cs b/src/shortenerTools/UrlShortener/UrlShortener.cs index 2d4156f9..a16029b9 100644 --- a/src/shortenerTools/UrlShortener/UrlShortener.cs +++ b/src/shortenerTools/UrlShortener/UrlShortener.cs @@ -25,10 +25,15 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; -using System.Net; using System.Net.Http; using Cloud5mins.domain; -using Microsoft.Extensions.Configuration; +using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes; +using Microsoft.OpenApi.Models; +using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Enums; +using System.Net; namespace Cloud5mins.Function { @@ -36,47 +41,45 @@ namespace Cloud5mins.Function public static class UrlShortener { + [OpenApiOperation(operationId: "UrlShortener", tags: new[] { "Urls" }, Summary = "Shorten a URL", Description = "Creates the short version of a URL and returns the result. If no vanity is specified one will be automatically generated for you.", Visibility = OpenApiVisibilityType.Important)] + [OpenApiRequestBody(contentType: "application/json", bodyType: typeof(ShortRequest), Required = true)] + [OpenApiSecurity("function_key", SecuritySchemeType.ApiKey, Name = "code", In = OpenApiSecurityLocationType.Query)] + [OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "application/json", bodyType: typeof(ShortResponse))] [FunctionName("UrlShortener")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = null)]HttpRequestMessage req, - ILogger log, - ExecutionContext context) + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "post", "get", Route = null)] HttpRequestMessage req, + ILogger log) { log.LogInformation($"C# HTTP trigger function processed this request: {req}"); - + var x = req.RequestUri.GetLeftPart(UriPartial.Authority); // Validation of the inputs if (req == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } ShortRequest input = await req.Content.ReadAsAsync(); if (input == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } // If the Url parameter only contains whitespaces or is empty return with BadRequest. if (string.IsNullOrWhiteSpace(input.Url)) { - return req.CreateErrorResponse(HttpStatusCode.BadRequest, "The url parameter can not be empty."); + return new BadRequestObjectResult("The url parameter can not be empty."); } // Validates if input.url is a valid aboslute url, aka is a complete refrence to the resource, ex: http(s)://google.com if (!Uri.IsWellFormedUriString(input.Url, UriKind.Absolute)) { - return req.CreateErrorResponse(HttpStatusCode.BadRequest, $"{input.Url} is not a valid absolute Url. The Url parameter must start with 'http://' or 'http://'."); + return new BadRequestObjectResult($"{input.Url} is not a valid absolute Url. The Url parameter must start with 'http://' or 'http://'."); } - + var result = new ShortResponse(); - var config = new ConfigurationBuilder() - .SetBasePath(context.FunctionAppDirectory) - .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) - .AddEnvironmentVariables() - .Build(); - StorageTableHelper stgHelper = new StorageTableHelper(config["UlsDataStorage"]); + StorageTableHelper stgHelper = new StorageTableHelper(Environment.GetEnvironmentVariable("UlsDataStorage")); try { @@ -86,12 +89,12 @@ public static async Task Run( ShortUrlEntity newRow; - if(!string.IsNullOrEmpty(vanity)) + if (!string.IsNullOrEmpty(vanity)) { newRow = new ShortUrlEntity(longUrl, vanity, title); - if(await stgHelper.IfShortUrlEntityExist(newRow)) + if (await stgHelper.IfShortUrlEntityExist(newRow)) { - return req.CreateResponse(HttpStatusCode.Conflict, "This Short URL already exist."); + return new ConflictObjectResult("This Short URL already exist."); } } else @@ -101,19 +104,25 @@ public static async Task Run( await stgHelper.SaveShortUrlEntity(newRow); - var host = req.RequestUri.GetLeftPart(UriPartial.Authority); - log.LogInformation($"-> host = {host}"); + string host = null; + if (req.Headers.TryGetValues("X-Forwarded-Host", out IEnumerable hosts)) + { + var builder = new UriBuilder(req.RequestUri); + builder.Host = hosts.ToArray().First(); + host = builder.Uri.GetLeftPart(UriPartial.Authority); + } + if (string.IsNullOrEmpty(host)) { host = req.RequestUri.GetLeftPart(UriPartial.Authority); } result = new ShortResponse(host, newRow.Url, newRow.RowKey, newRow.Title); log.LogInformation("Short Url created."); - } + } catch (Exception ex) { log.LogError(ex, "An unexpected error was encountered."); - return req.CreateResponse(HttpStatusCode.BadRequest, ex); + return new BadRequestObjectResult(ex); } - return req.CreateResponse(HttpStatusCode.OK, result); + return new OkObjectResult(result); } } } diff --git a/src/shortenerTools/UrlUpdate/UrlUpdate.cs b/src/shortenerTools/UrlUpdate/UrlUpdate.cs index 848c4015..adec0f9b 100644 --- a/src/shortenerTools/UrlUpdate/UrlUpdate.cs +++ b/src/shortenerTools/UrlUpdate/UrlUpdate.cs @@ -33,19 +33,19 @@ using Microsoft.Azure.WebJobs; using Microsoft.Azure.WebJobs.Extensions.Http; using Microsoft.Extensions.Logging; -using System.Net; using System.Net.Http; using Cloud5mins.domain; using Microsoft.Extensions.Configuration; +using Microsoft.AspNetCore.Mvc; namespace Cloud5mins.Function { public static class UrlUpdate { [FunctionName("UrlUpdate")] - public static async Task Run( - [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)]HttpRequestMessage req, - ILogger log, + public static async Task Run( + [HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req, + ILogger log, ExecutionContext context) { log.LogInformation($"C# HTTP trigger function processed this request: {req}"); @@ -53,51 +53,46 @@ public static async Task Run( // Validation of the inputs if (req == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } ShortUrlEntity input = await req.Content.ReadAsAsync(); if (input == null) { - return req.CreateResponse(HttpStatusCode.NotFound); + return new NotFoundResult(); } // If the Url parameter only contains whitespaces or is empty return with BadRequest. if (string.IsNullOrWhiteSpace(input.Url)) { - return req.CreateErrorResponse(HttpStatusCode.BadRequest, "The url parameter can not be empty."); + return new BadRequestObjectResult("The url parameter can not be empty."); } // Validates if input.url is a valid aboslute url, aka is a complete refrence to the resource, ex: http(s)://google.com if (!Uri.IsWellFormedUriString(input.Url, UriKind.Absolute)) { - return req.CreateErrorResponse(HttpStatusCode.BadRequest, $"{input.Url} is not a valid absolute Url. The Url parameter must start with 'http://' or 'http://'."); + return new BadRequestObjectResult($"{input.Url} is not a valid absolute Url. The Url parameter must start with 'http://' or 'http://'."); } ShortUrlEntity result; - var config = new ConfigurationBuilder() - .SetBasePath(context.FunctionAppDirectory) - .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true) - .AddEnvironmentVariables() - .Build(); - StorageTableHelper stgHelper = new StorageTableHelper(config["UlsDataStorage"]); + StorageTableHelper stgHelper = new StorageTableHelper(Environment.GetEnvironmentVariable("UlsDataStorage")); try { result = await stgHelper.UpdateShortUrlEntity(input); - var host = req.RequestUri.GetLeftPart(UriPartial.Authority); + var host = req.RequestUri.GetLeftPart(UriPartial.Authority); result.ShortUrl = Utility.GetShortUrl(host, result.RowKey); } catch (Exception ex) { log.LogError(ex, "An unexpected error was encountered."); - return req.CreateResponse(HttpStatusCode.BadRequest, ex); + return new BadRequestObjectResult(ex); } - return req.CreateResponse(HttpStatusCode.OK, result); + return new OkObjectResult(result); } } } diff --git a/src/shortenerTools/proxies.json b/src/shortenerTools/proxies.json index 0ed42c1c..f8391524 100644 --- a/src/shortenerTools/proxies.json +++ b/src/shortenerTools/proxies.json @@ -1,6 +1,12 @@ { "$schema": "http://json.schemastore.org/proxies", "proxies": { + "legacy forward": { + "matchCondition": { + "route": "/UrlShortenerService/UrlShortenerService.svc" + }, + "backendUri": "http://legacy.beac.co/UrlShortenerService/UrlShortenerService.svc" + }, "Domain Redirect": { "matchCondition": { "route": "/{shortUrl}" @@ -8,7 +14,11 @@ "backendUri": "http://localhost/api/UrlRedirect/{shortUrl}" }, "Root": { + "disabled":true, "matchCondition": { + "methods": [ + "GET" + ], "route": "/" }, "responseOverrides": { @@ -18,4 +28,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/shortenerTools/settings.json b/src/shortenerTools/settings.json index d9a7606f..9dd2fa60 100644 --- a/src/shortenerTools/settings.json +++ b/src/shortenerTools/settings.json @@ -3,9 +3,7 @@ "Values": { "AzureWebJobsStorage": "", "FUNCTIONS_WORKER_RUNTIME": "dotnet", - "FUNCTIONS_V2_COMPATIBILITY_MODE":"true", "UlsDataStorage":"", "defaultRedirectUrl":"https://azure.com" - } } diff --git a/src/shortenerTools/shortenerTools.csproj b/src/shortenerTools/shortenerTools.csproj index b5968608..769dbacf 100644 --- a/src/shortenerTools/shortenerTools.csproj +++ b/src/shortenerTools/shortenerTools.csproj @@ -6,6 +6,7 @@ + @@ -16,9 +17,9 @@ PreserveNewest - + Always Always - + \ No newline at end of file