From 28e6420022a2100ee04b314edd1898d9d76ae8bd Mon Sep 17 00:00:00 2001 From: dmitryvhf Date: Wed, 11 Feb 2026 00:01:38 +0500 Subject: [PATCH] Added support PathBase for HttpRequest. Simple realization through UsePath method. --- .../Extensions/ContextExtensions.cs | 30 ++++++++++---- .../Extensions/ContextExtensionsTests.cs | 40 +++++++++++++++++++ 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/src/HttpContextMoq/Extensions/ContextExtensions.cs b/src/HttpContextMoq/Extensions/ContextExtensions.cs index 97b4258..57d694e 100644 --- a/src/HttpContextMoq/Extensions/ContextExtensions.cs +++ b/src/HttpContextMoq/Extensions/ContextExtensions.cs @@ -2,34 +2,50 @@ using System.Collections.Generic; using System.IO; using System.Net; + using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Primitives; + using Moq; namespace HttpContextMoq.Extensions; public static class ContextExtensions { - public static HttpContextMock SetupUrl(this HttpContextMock httpContextMock, string url) + public static HttpContextMock SetupUrl(this HttpContextMock httpContextMock, string url, string basePath = "") { var uri = new Uri(url); httpContextMock.RequestMock.Mock.Setup(x => x.Protocol).Returns("HTTP/1.1"); httpContextMock.RequestMock.Mock.Setup(x => x.IsHttps).Returns(uri.Scheme == "https"); httpContextMock.RequestMock.Mock.Setup(x => x.Scheme).Returns(uri.Scheme); - if ((uri.Scheme == "https" && uri.Port != 443) || (uri.Scheme == "http" && uri.Port != 80)) + if (uri.IsDefaultPort) { - httpContextMock.RequestMock.Mock.Setup(x => x.Host).Returns(new HostString(uri.Host, uri.Port)); + httpContextMock.RequestMock.Mock.Setup(x => x.Host).Returns(new HostString(uri.Host)); } else { - httpContextMock.RequestMock.Mock.Setup(x => x.Host).Returns(new HostString(uri.Host)); + httpContextMock.RequestMock.Mock.Setup(x => x.Host).Returns(new HostString(uri.Host, uri.Port)); + } + + // Updating Path with existed Basepath + string absolutePath = uri.AbsolutePath; + if (!String.IsNullOrWhiteSpace(basePath) && basePath != "/") + { + if (absolutePath.StartsWith(basePath)) + { + absolutePath = uri.AbsolutePath.Remove(0, basePath.Length); + if (absolutePath == String.Empty) + { + absolutePath = "/"; + } + } } - httpContextMock.RequestMock.Mock.Setup(x => x.PathBase).Returns(string.Empty); - httpContextMock.RequestMock.Mock.Setup(x => x.Path).Returns(uri.AbsolutePath); + httpContextMock.RequestMock.Mock.Setup(x => x.PathBase).Returns(basePath); + httpContextMock.RequestMock.Mock.Setup(x => x.Path).Returns(absolutePath); var queryString = QueryString.FromUriComponent(uri); httpContextMock.RequestMock.Mock.Setup(x => x.QueryString).Returns(queryString); @@ -38,7 +54,7 @@ public static HttpContextMock SetupUrl(this HttpContextMock httpContextMock, str httpContextMock.RequestMock.Query = new QueryCollectionFake(queryDictionary); var requestFeature = new Mock(); - requestFeature.Setup(x => x.RawTarget).Returns(uri.PathAndQuery); + requestFeature.Setup(x => x.RawTarget).Returns(absolutePath + queryString); httpContextMock.FeaturesMock.Mock.Setup(x => x.Get()).Returns(requestFeature.Object); return httpContextMock; diff --git a/tests/HttpContextMoq.Tests/Extensions/ContextExtensionsTests.cs b/tests/HttpContextMoq.Tests/Extensions/ContextExtensionsTests.cs index c5d2749..d1fc11c 100644 --- a/tests/HttpContextMoq.Tests/Extensions/ContextExtensionsTests.cs +++ b/tests/HttpContextMoq.Tests/Extensions/ContextExtensionsTests.cs @@ -3,12 +3,17 @@ using System.IO; using System.Linq; using System.Threading.Tasks; + using FluentAssertions; + using HttpContextMoq.Extensions; + using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Http.Features; using Microsoft.AspNetCore.WebUtilities; using Microsoft.Extensions.Primitives; + using Xunit; namespace HttpContextMoq.Tests.Extensions; @@ -83,6 +88,41 @@ public void SetupUrl_WhenUrlIsValid_RequestShouldBeMocked(string url, bool isHtt request.QueryString.ToString().Should().Be(queryString); request.Query.Should().BeEquivalentTo(queryDictionary); requestFeature.RawTarget.Should().Be(path + queryString); + + request.GetDisplayUrl().Should().Be(string.Concat(new string[] { scheme, Uri.SchemeDelimiter, host, String.Empty, path, queryString })); + } + + [Theory] + [InlineData("https://localhost/base", true, "https", "localhost", "/base", "/", "")] + [InlineData("http://localhost:80/base", false, "http", "localhost", "/base", "/", "")] + [InlineData("https://localhost:443/base", true, "https", "localhost", "/base", "/", "")] + [InlineData("https://localhost/base/path", true, "https", "localhost", "/base", "/path", "")] + [InlineData("https://localhost:123/base/path?query=asd", true, "https", "localhost:123", "/base", "/path", "?query=asd")] + [InlineData("https://localhost/base/?query", true, "https", "localhost", "/base", "/", "?query")] + public void SetupUrl_WithBasePath_WhenUrlIsValid_RequestShouldBeMocked(string url, bool isHttps, string scheme, string host, string basePath, string path, string queryString) + { + // Arrange + var context = new HttpContextMock(); + var queryDictionary = QueryHelpers.ParseQuery(queryString); + + // Act + context.SetupUrl(url, basePath); + + HttpRequestMock request = context.Request as HttpRequestMock; + var requestFeature = context.Features.Get(); + + // Assert + request.IsHttps.Should().Be(isHttps); + request.Scheme.Should().Be(scheme); + request.Host.ToString().Should().Be(host); + request.PathBase.ToString().Should().Be(basePath); + request.Path.ToString().Should().Be(path); + request.QueryString.ToString().Should().Be(queryString); + request.Query.Should().BeEquivalentTo(queryDictionary); + + requestFeature.RawTarget.Should().Be(path + queryString); + + request.GetDisplayUrl().Should().Be(string.Concat(new string[] { scheme, Uri.SchemeDelimiter, host, basePath, path, queryString })); } [Fact]