1
1
using System ;
2
2
using System . Collections . Generic ;
3
3
using System . Globalization ;
4
+ using Microsoft . Extensions . DependencyInjection ;
4
5
using Microsoft . Extensions . Logging ;
5
6
using Microsoft . Extensions . Options ;
6
7
using Umbraco . Cms . Core . Configuration . Models ;
7
8
using Umbraco . Cms . Core . Models . PublishedContent ;
9
+ using Umbraco . Cms . Core . Services ;
8
10
using Umbraco . Cms . Core . Web ;
11
+ using Umbraco . Cms . Web . Common . DependencyInjection ;
9
12
using Umbraco . Extensions ;
10
13
11
14
namespace Umbraco . Cms . Core . Routing
12
15
{
13
16
/// <summary>
14
- /// Provides urls.
17
+ /// Provides urls.
15
18
/// </summary>
16
19
public class DefaultUrlProvider : IUrlProvider
17
20
{
18
- private readonly RequestHandlerSettings _requestSettings ;
21
+ private readonly ILocalizationService _localizationService ;
22
+ private readonly ILocalizedTextService _localizedTextService ;
19
23
private readonly ILogger < DefaultUrlProvider > _logger ;
24
+ private readonly RequestHandlerSettings _requestSettings ;
20
25
private readonly ISiteDomainMapper _siteDomainMapper ;
21
26
private readonly IUmbracoContextAccessor _umbracoContextAccessor ;
22
27
private readonly UriUtility _uriUtility ;
23
28
24
- public DefaultUrlProvider ( IOptions < RequestHandlerSettings > requestSettings , ILogger < DefaultUrlProvider > logger , ISiteDomainMapper siteDomainMapper , IUmbracoContextAccessor umbracoContextAccessor , UriUtility uriUtility )
29
+ [ Obsolete ( "Use ctor with all parameters" ) ]
30
+ public DefaultUrlProvider ( IOptions < RequestHandlerSettings > requestSettings , ILogger < DefaultUrlProvider > logger ,
31
+ ISiteDomainMapper siteDomainMapper , IUmbracoContextAccessor umbracoContextAccessor , UriUtility uriUtility )
32
+ : this ( requestSettings , logger , siteDomainMapper , umbracoContextAccessor , uriUtility ,
33
+ StaticServiceProvider . Instance . GetRequiredService < ILocalizationService > ( ) )
34
+ {
35
+ }
36
+
37
+ public DefaultUrlProvider (
38
+ IOptions < RequestHandlerSettings > requestSettings ,
39
+ ILogger < DefaultUrlProvider > logger ,
40
+ ISiteDomainMapper siteDomainMapper ,
41
+ IUmbracoContextAccessor umbracoContextAccessor ,
42
+ UriUtility uriUtility ,
43
+ ILocalizationService localizationService )
25
44
{
26
45
_requestSettings = requestSettings . Value ;
27
46
_logger = logger ;
28
47
_siteDomainMapper = siteDomainMapper ;
29
- _uriUtility = uriUtility ;
30
48
_umbracoContextAccessor = umbracoContextAccessor ;
49
+ _uriUtility = uriUtility ;
50
+ _localizationService = localizationService ;
31
51
}
32
52
33
- #region GetUrl
34
-
35
- /// <inheritdoc />
36
- public virtual UrlInfo GetUrl ( IPublishedContent content , UrlMode mode , string culture , Uri current )
37
- {
38
- if ( ! current . IsAbsoluteUri ) throw new ArgumentException ( "Current URL must be absolute." , nameof ( current ) ) ;
39
- var umbracoContext = _umbracoContextAccessor . GetRequiredUmbracoContext ( ) ;
40
- // will not use cache if previewing
41
- var route = umbracoContext . Content . GetRouteById ( content . Id , culture ) ;
42
-
43
- return GetUrlFromRoute ( route , umbracoContext , content . Id , current , mode , culture ) ;
44
- }
45
-
46
- internal UrlInfo GetUrlFromRoute ( string route , IUmbracoContext umbracoContext , int id , Uri current , UrlMode mode , string culture )
47
- {
48
- if ( string . IsNullOrWhiteSpace ( route ) )
49
- {
50
- _logger . LogDebug ( "Couldn't find any page with nodeId={NodeId}. This is most likely caused by the page not being published." , id ) ;
51
- return null ;
52
- }
53
-
54
- // extract domainUri and path
55
- // route is /<path> or <domainRootId>/<path>
56
- var pos = route . IndexOf ( '/' ) ;
57
- var path = pos == 0 ? route : route . Substring ( pos ) ;
58
- var domainUri = pos == 0
59
- ? null
60
- : DomainUtilities . DomainForNode ( umbracoContext . PublishedSnapshot . Domains , _siteDomainMapper , int . Parse ( route . Substring ( 0 , pos ) , CultureInfo . InvariantCulture ) , current , culture ) ;
61
-
62
- // assemble the URL from domainUri (maybe null) and path
63
- var url = AssembleUrl ( domainUri , path , current , mode ) . ToString ( ) ;
64
-
65
- return UrlInfo . Url ( url , culture ) ;
66
- }
67
-
68
- #endregion
69
-
70
53
#region GetOtherUrls
71
54
72
55
/// <summary>
73
- /// Gets the other URLs of a published content.
56
+ /// Gets the other URLs of a published content.
74
57
/// </summary>
75
58
/// <param name="umbracoContextAccessor">The Umbraco context.</param>
76
59
/// <param name="id">The published content id.</param>
77
60
/// <param name="current">The current absolute URL.</param>
78
61
/// <returns>The other URLs for the published content.</returns>
79
62
/// <remarks>
80
- /// <para>Other URLs are those that <c>GetUrl</c> would not return in the current context, but would be valid
81
- /// URLs for the node in other contexts (different domain for current request, umbracoUrlAlias...).</para>
63
+ /// <para>
64
+ /// Other URLs are those that <c>GetUrl</c> would not return in the current context, but would be valid
65
+ /// URLs for the node in other contexts (different domain for current request, umbracoUrlAlias...).
66
+ /// </para>
82
67
/// </remarks>
83
68
public virtual IEnumerable < UrlInfo > GetOtherUrls ( int id , Uri current )
84
69
{
85
- var umbracoContext = _umbracoContextAccessor . GetRequiredUmbracoContext ( ) ;
86
- var node = umbracoContext . Content . GetById ( id ) ;
70
+ IUmbracoContext umbracoContext = _umbracoContextAccessor . GetRequiredUmbracoContext ( ) ;
71
+ IPublishedContent node = umbracoContext . Content . GetById ( id ) ;
87
72
if ( node == null )
88
73
{
89
74
yield break ;
90
75
}
91
76
92
77
// look for domains, walking up the tree
93
- var n = node ;
94
- var domainUris = DomainUtilities . DomainsForNode ( umbracoContext . PublishedSnapshot . Domains , _siteDomainMapper , n . Id , current , false ) ;
78
+ IPublishedContent n = node ;
79
+ IEnumerable < DomainAndUri > domainUris =
80
+ DomainUtilities . DomainsForNode ( umbracoContext . PublishedSnapshot . Domains , _siteDomainMapper , n . Id ,
81
+ current , false ) ;
95
82
while ( domainUris == null && n != null ) // n is null at root
96
83
{
97
84
n = n . Parent ; // move to parent node
98
- domainUris = n == null ? null : DomainUtilities . DomainsForNode ( umbracoContext . PublishedSnapshot . Domains , _siteDomainMapper , n . Id , current , excludeDefault : true ) ;
85
+ domainUris = n == null
86
+ ? null
87
+ : DomainUtilities . DomainsForNode ( umbracoContext . PublishedSnapshot . Domains , _siteDomainMapper , n . Id ,
88
+ current ) ;
99
89
}
100
90
101
91
// no domains = exit
102
- if ( domainUris == null )
92
+ if ( domainUris == null )
103
93
{
104
94
yield break ;
105
95
}
106
96
107
- foreach ( var d in domainUris )
97
+ foreach ( DomainAndUri d in domainUris )
108
98
{
109
99
var culture = d ? . Culture ;
110
100
111
101
// although we are passing in culture here, if any node in this path is invariant, it ignores the culture anyways so this is ok
112
102
var route = umbracoContext . Content . GetRouteById ( id , culture ) ;
113
- if ( route == null ) continue ;
103
+ if ( route == null )
104
+ {
105
+ continue ;
106
+ }
114
107
115
108
// need to strip off the leading ID for the route if it exists (occurs if the route is for a node with a domain assigned)
116
109
var pos = route . IndexOf ( '/' ) ;
@@ -124,9 +117,57 @@ public virtual IEnumerable<UrlInfo> GetOtherUrls(int id, Uri current)
124
117
125
118
#endregion
126
119
120
+ #region GetUrl
121
+
122
+ /// <inheritdoc />
123
+ public virtual UrlInfo GetUrl ( IPublishedContent content , UrlMode mode , string culture , Uri current )
124
+ {
125
+ if ( ! current . IsAbsoluteUri )
126
+ {
127
+ throw new ArgumentException ( "Current URL must be absolute." , nameof ( current ) ) ;
128
+ }
129
+
130
+ IUmbracoContext umbracoContext = _umbracoContextAccessor . GetRequiredUmbracoContext ( ) ;
131
+ // will not use cache if previewing
132
+ var route = umbracoContext . Content . GetRouteById ( content . Id , culture ) ;
133
+
134
+ return GetUrlFromRoute ( route , umbracoContext , content . Id , current , mode , culture ) ;
135
+ }
136
+
137
+ internal UrlInfo GetUrlFromRoute ( string route , IUmbracoContext umbracoContext , int id , Uri current ,
138
+ UrlMode mode , string culture )
139
+ {
140
+ if ( string . IsNullOrWhiteSpace ( route ) )
141
+ {
142
+ _logger . LogDebug (
143
+ "Couldn't find any page with nodeId={NodeId}. This is most likely caused by the page not being published." ,
144
+ id ) ;
145
+ return null ;
146
+ }
147
+
148
+ // extract domainUri and path
149
+ // route is /<path> or <domainRootId>/<path>
150
+ var pos = route . IndexOf ( '/' ) ;
151
+ var path = pos == 0 ? route : route . Substring ( pos ) ;
152
+ var domainUri = pos == 0
153
+ ? null
154
+ : DomainUtilities . DomainForNode ( umbracoContext . PublishedSnapshot . Domains , _siteDomainMapper , int . Parse ( route . Substring ( 0 , pos ) , CultureInfo . InvariantCulture ) , current , culture ) ;
155
+
156
+ var defaultCulture = _localizationService . GetDefaultLanguageIsoCode ( ) ;
157
+ if ( domainUri is not null || culture == defaultCulture || culture is null )
158
+ {
159
+ var url = AssembleUrl ( domainUri , path , current , mode ) . ToString ( ) ;
160
+ return UrlInfo . Url ( url , culture ) ;
161
+ }
162
+
163
+ return null ;
164
+ }
165
+
166
+ #endregion
167
+
127
168
#region Utilities
128
169
129
- Uri AssembleUrl ( DomainAndUri domainUri , string path , Uri current , UrlMode mode )
170
+ private Uri AssembleUrl ( DomainAndUri domainUri , string path , Uri current , UrlMode mode )
130
171
{
131
172
Uri uri ;
132
173
@@ -135,7 +176,9 @@ Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode)
135
176
if ( domainUri == null ) // no domain was found
136
177
{
137
178
if ( current == null )
179
+ {
138
180
mode = UrlMode . Relative ; // best we can do
181
+ }
139
182
140
183
switch ( mode )
141
184
{
@@ -155,10 +198,15 @@ Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode)
155
198
if ( mode == UrlMode . Auto )
156
199
{
157
200
//this check is a little tricky, we can't just compare domains
158
- if ( current != null && domainUri . Uri . GetLeftPart ( UriPartial . Authority ) == current . GetLeftPart ( UriPartial . Authority ) )
201
+ if ( current != null && domainUri . Uri . GetLeftPart ( UriPartial . Authority ) ==
202
+ current . GetLeftPart ( UriPartial . Authority ) )
203
+ {
159
204
mode = UrlMode . Relative ;
205
+ }
160
206
else
207
+ {
161
208
mode = UrlMode . Absolute ;
209
+ }
162
210
}
163
211
164
212
switch ( mode )
@@ -179,9 +227,9 @@ Uri AssembleUrl(DomainAndUri domainUri, string path, Uri current, UrlMode mode)
179
227
return _uriUtility . UriFromUmbraco ( uri , _requestSettings ) ;
180
228
}
181
229
182
- string CombinePaths ( string path1 , string path2 )
230
+ private string CombinePaths ( string path1 , string path2 )
183
231
{
184
- string path = path1 . TrimEnd ( Constants . CharArrays . ForwardSlash ) + path2 ;
232
+ var path = path1 . TrimEnd ( Constants . CharArrays . ForwardSlash ) + path2 ;
185
233
return path == "/" ? path : path . TrimEnd ( Constants . CharArrays . ForwardSlash ) ;
186
234
}
187
235
0 commit comments