@@ -9,6 +9,7 @@ namespace ServiceControl.Transports.RabbitMQ;
99using System . Net . Http ;
1010using System . Net . Http . Json ;
1111using System . Runtime . CompilerServices ;
12+ using System . Text ;
1213using System . Text . Json ;
1314using System . Text . Json . Nodes ;
1415using System . Threading ;
@@ -29,71 +30,118 @@ public class RabbitMQQuery : BrokerThroughputQuery
2930 readonly ILogger < RabbitMQQuery > logger ;
3031 readonly TimeProvider timeProvider ;
3132 readonly ConnectionConfiguration connectionConfiguration ;
33+ readonly string connectionString ;
3234
3335 public RabbitMQQuery ( ILogger < RabbitMQQuery > logger ,
3436 TimeProvider timeProvider ,
3537 TransportSettings transportSettings ) : base ( logger , "RabbitMQ" )
3638 {
3739 this . logger = logger ;
3840 this . timeProvider = timeProvider ;
41+ connectionString = transportSettings . ConnectionString ;
3942
40- connectionConfiguration = ConnectionConfiguration . Create ( transportSettings . ConnectionString , string . Empty ) ;
43+ connectionConfiguration = ConnectionConfiguration . Create ( connectionString , string . Empty ) ;
4144 }
4245
4346 protected override void InitializeCore ( ReadOnlyDictionary < string , string > settings )
4447 {
45- if ( ! settings . TryGetValue ( RabbitMQSettings . UserName , out string ? username ) ||
46- string . IsNullOrEmpty ( username ) )
48+ var mangementApiUrl = GetManagementApiUrl ( ) ;
49+
50+ var userName = GetSettingsValue ( settings , RabbitMQSettings . UserName , mangementApiUrl . UserName ) ;
51+ var password = GetSettingsValue ( settings , RabbitMQSettings . Password , mangementApiUrl . Password ) ;
52+ var apiUrl = GetSettingsValue ( settings , RabbitMQSettings . API , mangementApiUrl . Uri . AbsoluteUri ) ;
53+
54+ if ( userName != mangementApiUrl . UserName )
4755 {
48- logger . LogInformation ( "Using username from connectionstring" ) ;
49- username = connectionConfiguration . UserName ;
50- Diagnostics . AppendLine (
51- $ "Username not set, defaulted to using \" { username } \" username from the ConnectionString used by instance") ;
56+ _ = Diagnostics . AppendLine ( $ "UserName in settings is different from Management API URL: { userName } != { managementUserName } ") ;
5257 }
53- else
58+
59+ if ( password != mangementApiUrl . Password )
5460 {
55- Diagnostics . AppendLine ( $ "Username set to \" { username } \" ") ;
61+ _ = Diagnostics . AppendLine ( $ "Password in settings is different from Management API URL. ") ;
5662 }
5763
58- if ( ! settings . TryGetValue ( RabbitMQSettings . Password , out string ? password ) ||
59- string . IsNullOrEmpty ( password ) )
64+ if ( apiUrl != mangementApiUrl . Uri . AbsoluteUri )
6065 {
61- logger . LogInformation ( "Using password from connectionstring" ) ;
62- password = connectionConfiguration . Password ;
63- Diagnostics . AppendLine (
64- "Password not set, defaulted to using password from the ConnectionString used by instance" ) ;
66+ _ = Diagnostics . AppendLine ( $ "API URL in settings is different from Management API URL: { apiUrl } != { mangementApiUrl . Uri . AbsoluteUri } ") ;
6567 }
66- else
68+
69+ if ( ! Uri . TryCreate ( apiUrl , UriKind . Absolute , out _ ) )
6770 {
68- Diagnostics . AppendLine ( "Password set ") ;
71+ InitialiseErrors . Add ( "API url configured is invalid ") ;
6972 }
7073
71- var defaultCredential = new NetworkCredential ( username , password ) ;
74+ var defaultCredential = new NetworkCredential ( userName , password ) ;
75+
76+ if ( InitialiseErrors . Count == 0 )
77+ {
78+ // ideally we would use the HttpClientFactory, but it would be a bit more involved to set that up
79+ // so for now we are using a virtual method that can be overriden in tests
80+ // https://github.com/Particular/ServiceControl/issues/4493
81+ httpClient = CreateHttpClient ( defaultCredential , apiUrl ) ;
82+ }
83+ }
7284
73- if ( ! settings . TryGetValue ( RabbitMQSettings . API , out string ? apiUrl ) ||
74- string . IsNullOrEmpty ( apiUrl ) )
85+ string GetSettingsValue ( ReadOnlyDictionary < string , string > settings , string key , string defaultValue )
86+ {
87+ if ( ! settings . TryGetValue ( key , out string ? value ) ||
88+ string . IsNullOrEmpty ( value ) )
7589 {
76- apiUrl =
77- $ " { ( connectionConfiguration . UseTls ? $ "https:// { connectionConfiguration . Host } :15671" : $ "http:// { connectionConfiguration . Host } :15672" ) } " ;
78- Diagnostics . AppendLine (
79- $ "RabbitMQ API Url not set, defaulted to using \" { apiUrl } \" from the ConnectionString used by instance") ;
90+ logger . LogInformation ( $ "Using { key } from connection string" ) ;
91+ value = defaultValue ;
92+ _ = Diagnostics . AppendLine (
93+ $ "{ key } not set, defaulted to using { key } from the ConnectionString used by instance") ;
8094 }
8195 else
8296 {
83- Diagnostics . AppendLine ( $ "RabbitMQ API Url set to \" { apiUrl } \" ") ;
84- if ( ! Uri . TryCreate ( apiUrl , UriKind . Absolute , out _ ) )
97+ if ( key == RabbitMQSettings . Password )
8598 {
86- InitialiseErrors . Add ( "API url configured is invalid ") ;
99+ _ = Diagnostics . AppendLine ( $ " { key } set. ") ;
87100 }
101+
102+ _ = Diagnostics . AppendLine ( $ "{ key } set to { value } .") ;
88103 }
89104
90- if ( InitialiseErrors . Count == 0 )
105+ return value ;
106+ }
107+
108+ UriBuilder GetManagementApiUrl ( )
109+ {
110+ var dictionary = ConnectionConfiguration . ParseNServiceBusConnectionString ( connectionString , new StringBuilder ( ) ) ;
111+ UriBuilder uriBuilder ;
112+
113+ var managementApiUrl = GetValue ( dictionary , "ManagementApiUrl" , "" ) ;
114+
115+ if ( string . IsNullOrEmpty ( managementApiUrl ) )
91116 {
92- // ideally we would use the HttpClientFactory, but it would be a bit more involved to set that up
93- // so for now we are using a virtual method that can be overriden in tests
94- // https://github.com/Particular/ServiceControl/issues/4493
95- httpClient = CreateHttpClient ( defaultCredential , apiUrl ) ;
117+ _ = Diagnostics . AppendLine ( "ManagementApiUrl is empty. Setting credentials from the connectionString used by the instance." ) ;
118+ uriBuilder = new UriBuilder ( )
119+ {
120+ Scheme = connectionConfiguration . UseTls ? "https" : "http" ,
121+ Host = connectionConfiguration . Host ,
122+ } ;
96123 }
124+ else
125+ {
126+ uriBuilder = new UriBuilder ( managementApiUrl ) ;
127+ }
128+
129+ uriBuilder . UserName = string . IsNullOrEmpty ( uriBuilder . UserName ) ? connectionConfiguration . UserName : uriBuilder . UserName ;
130+ uriBuilder . Password = string . IsNullOrEmpty ( uriBuilder . Password ) ? connectionConfiguration . Password : uriBuilder . Password ;
131+
132+ // Check if port was defined in the connection string or if it's the default value from UriBuilder
133+ var isPortProvided = uriBuilder . Port != - 1
134+ && ( ! ( ( uriBuilder . Port == 80 || uriBuilder . Port == 443 )
135+ && ! managementApiUrl . Contains ( $ ":{ uriBuilder . Port } ") ) ) ;
136+
137+ uriBuilder . Port = isPortProvided ? uriBuilder . Port : uriBuilder . Scheme == "https" ? 15671 : 15672 ;
138+
139+ return uriBuilder ;
140+ }
141+
142+ static string GetValue ( Dictionary < string , string > dictionary , string key , string defaultValue )
143+ {
144+ return dictionary . TryGetValue ( key , out var value ) ? value : defaultValue ;
97145 }
98146
99147 protected virtual HttpClient CreateHttpClient ( NetworkCredential defaultCredential , string apiUrl ) =>
0 commit comments