Try your search with a different keyword or use * as a wildcard.
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Routing;
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.AspNetCore.WebUtilities;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Primitives;
using Microsoft.Net.Http.Headers;
using Nop.Core.Http;
namespace Nop.Core;
///
/// Represents a web helper
///
public partial class WebHelper : IWebHelper
{
#region Fields
protected readonly IActionContextAccessor _actionContextAccessor;
protected readonly IHostApplicationLifetime _hostApplicationLifetime;
protected readonly IHttpContextAccessor _httpContextAccessor;
protected readonly IUrlHelperFactory _urlHelperFactory;
protected readonly Lazy _storeContext;
#endregion
#region Ctor
public WebHelper(IActionContextAccessor actionContextAccessor,
IHostApplicationLifetime hostApplicationLifetime,
IHttpContextAccessor httpContextAccessor,
IUrlHelperFactory urlHelperFactory,
Lazy storeContext)
{
_actionContextAccessor = actionContextAccessor;
_hostApplicationLifetime = hostApplicationLifetime;
_httpContextAccessor = httpContextAccessor;
_urlHelperFactory = urlHelperFactory;
_storeContext = storeContext;
}
#endregion
#region Utilities
///
/// Check whether current HTTP request is available
///
/// True if available; otherwise false
protected virtual bool IsRequestAvailable()
{
if (_httpContextAccessor?.HttpContext == null)
return false;
try
{
if (_httpContextAccessor.HttpContext?.Request == null)
return false;
}
catch (Exception)
{
return false;
}
return true;
}
///
/// Is IP address specified
///
/// IP address
/// Result
protected virtual bool IsIpAddressSet(IPAddress address)
{
var rez = address != null && address.ToString() != IPAddress.IPv6Loopback.ToString();
return rez;
}
#endregion
#region Methods
///
/// Get URL referrer if exists
///
/// URL referrer
public virtual string GetUrlReferrer()
{
if (!IsRequestAvailable())
return string.Empty;
//URL referrer is null in some case (for example, in IE 8)
return _httpContextAccessor.HttpContext.Request.Headers[HeaderNames.Referer];
}
///
/// Get IP address from HTTP context
///
/// String of IP address
public virtual string GetCurrentIpAddress()
{
if (!IsRequestAvailable() || _httpContextAccessor.HttpContext!.Connection.RemoteIpAddress is not { } remoteIp)
return string.Empty;
return (remoteIp.Equals(IPAddress.IPv6Loopback) ? IPAddress.Loopback : remoteIp).ToString();
}
///
/// Gets this page URL
///
/// Value indicating whether to include query strings
/// Value indicating whether to get SSL secured page URL. Pass null to determine automatically
/// Value indicating whether to lowercase URL
/// Page URL
public virtual string GetThisPageUrl(bool includeQueryString, bool? useSsl = null, bool lowercaseUrl = false)
{
if (!IsRequestAvailable())
return string.Empty;
//get store location
var storeLocation = GetStoreLocation(useSsl ?? IsCurrentConnectionSecured());
//add local path to the URL
var pageUrl = $"{storeLocation.TrimEnd('/')}{_httpContextAccessor.HttpContext.Request.Path}";
//add query string to the URL
if (includeQueryString)
pageUrl = $"{pageUrl}{_httpContextAccessor.HttpContext.Request.QueryString}";
//whether to convert the URL to lower case
if (lowercaseUrl)
pageUrl = pageUrl.ToLowerInvariant();
return pageUrl;
}
///
/// Gets a value indicating whether current connection is secured
///
/// True if it's secured, otherwise false
public virtual bool IsCurrentConnectionSecured()
{
if (!IsRequestAvailable())
return false;
return _httpContextAccessor.HttpContext.Request.IsHttps;
}
///
/// Gets store host location
///
/// Whether to get SSL secured URL
/// Store host location
public virtual string GetStoreHost(bool useSsl)
{
if (!IsRequestAvailable())
return string.Empty;
//try to get host from the request HOST header
var hostHeader = _httpContextAccessor.HttpContext.Request.Headers[HeaderNames.Host];
if (StringValues.IsNullOrEmpty(hostHeader))
return string.Empty;
//add scheme to the URL
var storeHost = $"{(useSsl ? Uri.UriSchemeHttps : Uri.UriSchemeHttp)}{Uri.SchemeDelimiter}{hostHeader.FirstOrDefault()}";
//ensure that host is ended with slash
storeHost = $"{storeHost.TrimEnd('/')}/";
return storeHost;
}
///
/// Gets store location
///
/// Whether to get SSL secured URL; pass null to determine automatically
/// Store location
public virtual string GetStoreLocation(bool? useSsl = null)
{
var storeLocation = string.Empty;
//get store host
var storeHost = GetStoreHost(useSsl ?? IsCurrentConnectionSecured());
if (!string.IsNullOrEmpty(storeHost))
{
//add application path base if exists
storeLocation = IsRequestAvailable() ? $"{storeHost.TrimEnd('/')}{_httpContextAccessor.HttpContext.Request.PathBase}" : storeHost;
}
//if host is empty (it is possible only when HttpContext is not available), use URL of a store entity configured in admin area
if (string.IsNullOrEmpty(storeHost))
storeLocation = _storeContext.Value.GetCurrentStore()?.Url
?? throw new Exception("Current store cannot be loaded");
//ensure that URL is ended with slash
storeLocation = $"{storeLocation.TrimEnd('/')}/";
return storeLocation;
}
///
/// Returns true if the requested resource is one of the typical resources that needn't be processed by the cms engine.
///
/// True if the request targets a static resource file.
public virtual bool IsStaticResource()
{
if (!IsRequestAvailable())
return false;
string path = _httpContextAccessor.HttpContext.Request.Path;
//a little workaround. FileExtensionContentTypeProvider contains most of static file extensions. So we can use it
//source: https://github.com/aspnet/StaticFiles/blob/dev/src/Microsoft.AspNetCore.StaticFiles/FileExtensionContentTypeProvider.cs
//if it can return content type, then it's a static file
var contentTypeProvider = new FileExtensionContentTypeProvider();
return contentTypeProvider.TryGetContentType(path, out var _);
}
///
/// Modify query string of the URL
///
/// Url to modify
/// Query parameter key to add
/// Query parameter values to add
/// New URL with passed query parameter
public virtual string ModifyQueryString(string url, string key, params string[] values)
{
if (string.IsNullOrEmpty(url))
return string.Empty;
if (string.IsNullOrEmpty(key))
return url;
//prepare URI object
var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);
var isLocalUrl = urlHelper.IsLocalUrl(url);
var uriStr = url;
if (isLocalUrl)
{
var pathBase = _httpContextAccessor.HttpContext.Request.PathBase;
uriStr = $"{GetStoreLocation().TrimEnd('/')}{(url.StartsWith(pathBase) ? url.Replace(pathBase, "") : url)}";
}
var uri = new Uri(uriStr, UriKind.Absolute);
//get current query parameters
var queryParameters = QueryHelpers.ParseQuery(uri.Query);
//and add passed one
queryParameters[key] = string.Join(",", values);
//add only first value
//two the same query parameters? theoretically it's not possible.
//but MVC has some ugly implementation for checkboxes and we can have two values
//find more info here: http://www.mindstorminteractive.com/topics/jquery-fix-asp-net-mvc-checkbox-truefalse-value/
//we do this validation just to ensure that the first one is not overridden
var queryBuilder = new QueryBuilder(queryParameters
.ToDictionary(parameter => parameter.Key, parameter => parameter.Value.FirstOrDefault()?.ToString() ?? string.Empty));
//create new URL with passed query parameters
url = $"{(isLocalUrl ? uri.LocalPath : uri.GetLeftPart(UriPartial.Path))}{queryBuilder.ToQueryString()}{uri.Fragment}";
return url;
}
///
/// Remove query parameter from the URL
///
/// Url to modify
/// Query parameter key to remove
/// Query parameter value to remove; pass null to remove all query parameters with the specified key
/// New URL without passed query parameter
public virtual string RemoveQueryString(string url, string key, string value = null)
{
if (string.IsNullOrEmpty(url))
return string.Empty;
if (string.IsNullOrEmpty(key))
return url;
//prepare URI object
var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContextAccessor.ActionContext);
var isLocalUrl = urlHelper.IsLocalUrl(url);
var uri = new Uri(isLocalUrl ? $"{GetStoreLocation().TrimEnd('/')}{url}" : url, UriKind.Absolute);
//get current query parameters
var queryParameters = QueryHelpers.ParseQuery(uri.Query)
.SelectMany(parameter => parameter.Value, (parameter, queryValue) => new KeyValuePair(parameter.Key, queryValue))
.ToList();
if (!string.IsNullOrEmpty(value))
{
//remove a specific query parameter value if it's passed
queryParameters.RemoveAll(parameter => parameter.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase)
&& parameter.Value.Equals(value, StringComparison.InvariantCultureIgnoreCase));
}
else
{
//or remove query parameter by the key
queryParameters.RemoveAll(parameter => parameter.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase));
}
var queryBuilder = new QueryBuilder(queryParameters);
//create new URL without passed query parameters
url = $"{(isLocalUrl ? uri.LocalPath : uri.GetLeftPart(UriPartial.Path))}{queryBuilder.ToQueryString()}{uri.Fragment}";
return url;
}
///
/// Gets query string value by name
///
/// Returned value type
/// Query parameter name
/// Query string value
public virtual T QueryString(string name)
{
if (!IsRequestAvailable())
return default;
if (StringValues.IsNullOrEmpty(_httpContextAccessor.HttpContext.Request.Query[name]))
return default;
return CommonHelper.To(_httpContextAccessor.HttpContext.Request.Query[name].ToString());
}
///
/// Restart application domain
///
public virtual void RestartAppDomain()
{
_hostApplicationLifetime.StopApplication();
}
///
/// Gets a value that indicates whether the client is being redirected to a new location
///
public virtual bool IsRequestBeingRedirected
{
get
{
var response = _httpContextAccessor.HttpContext.Response;
//ASP.NET 4 style - return response.IsRequestBeingRedirected;
int[] redirectionStatusCodes = [StatusCodes.Status301MovedPermanently, StatusCodes.Status302Found];
return redirectionStatusCodes.Contains(response.StatusCode);
}
}
///
/// Gets or sets a value that indicates whether the client is being redirected to a new location using POST
///
public virtual bool IsPostBeingDone
{
get
{
if (_httpContextAccessor.HttpContext.Items[NopHttpDefaults.IsPostBeingDoneRequestItem] == null)
return false;
return Convert.ToBoolean(_httpContextAccessor.HttpContext.Items[NopHttpDefaults.IsPostBeingDoneRequestItem]);
}
set => _httpContextAccessor.HttpContext.Items[NopHttpDefaults.IsPostBeingDoneRequestItem] = value;
}
///
/// Gets current HTTP request protocol
///
public virtual string GetCurrentRequestProtocol()
{
return IsCurrentConnectionSecured() ? Uri.UriSchemeHttps : Uri.UriSchemeHttp;
}
///
/// Gets whether the specified HTTP request URI references the local host.
///
/// HTTP request
/// True, if HTTP request URI references to the local host
public virtual bool IsLocalRequest(HttpRequest req)
{
//source: https://stackoverflow.com/a/41242493/7860424
var connection = req.HttpContext.Connection;
if (IsIpAddressSet(connection.RemoteIpAddress))
{
//We have a remote address set up
return IsIpAddressSet(connection.LocalIpAddress)
//Is local is same as remote, then we are local
? connection.RemoteIpAddress.Equals(connection.LocalIpAddress)
//else we are remote if the remote IP address is not a loopback address
: IPAddress.IsLoopback(connection.RemoteIpAddress);
}
return true;
}
///
/// Get the raw path and full query of request
///
/// HTTP request
/// Raw URL
public virtual string GetRawUrl(HttpRequest request)
{
//first try to get the raw target from request feature
//note: value has not been UrlDecoded
var rawUrl = request.HttpContext.Features.Get()?.RawTarget;
//or compose raw URL manually
if (string.IsNullOrEmpty(rawUrl))
rawUrl = $"{request.PathBase}{request.Path}{request.QueryString}";
return rawUrl;
}
///
/// Gets whether the request is made with AJAX
///
/// HTTP request
/// Result
public virtual bool IsAjaxRequest(HttpRequest request)
{
ArgumentNullException.ThrowIfNull(request);
if (request.Headers == null)
return false;
return request.Headers.XRequestedWith == "XMLHttpRequest";
}
#endregion
}