You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When first using this library, we found it difficult to debug issues when a registration wasn't found that we expected. We use Refit and found that sometimes the mismatch was due to order of url params or encoding issues. We also have test infra to configure common calls like auth sequences for various integrations.
We ended up extending IntereceptingHttpMessageHandler to enrich the HttpRequestNotInterceptedException with a list of registered interceptions. Below is the handler we created. It's not perfect since it can't easily report custom matching, but it significantly improved our experience of troubleshooting missing registrations. I've been intending to offer this as a PR but I don't think I'll have time soon so wanted to offer this for anyone it might benefit or would like to use for a PR.
internalclassFriendlierErrorInterceptingHttpMessageHandler(HttpClientInterceptorOptions options):InterceptingHttpMessageHandler(options){internalreadonlyHttpClientInterceptorOptionsOptions= options;internalTask<HttpResponseMessage>SendAsyncInternal(HttpRequestMessagerequest,CancellationTokencancellationToken)=>
SendAsync(request, cancellationToken);protectedoverrideasyncTask<HttpResponseMessage>SendAsync(HttpRequestMessagerequest,CancellationTokencancellationToken){try{returnawaitbase.SendAsync(request, cancellationToken);}catch(HttpRequestNotInterceptedExceptione){varregisteredMappings= GetRegisteredMappings().ToOrderedDelimitedString(Environment.NewLine);varunescapedDataString= Uri.UnescapeDataString(request.RequestUri!.AbsoluteUri);varrecordableOptions= Options as RecordableHttpClientInterceptorOptions;varmsg=$"No HTTP response is configured for {recordableOptions?.TestFilePath}"+$"\n\n{request.Method.Method}{request.RequestUri!.AbsoluteUri}"+$"\n({unescapedDataString})";throw e.Request isnull?new HttpRequestNotInterceptedException($"{msg}\n\nRegistered Mappings:\n\n{registeredMappings}"):new HttpRequestNotInterceptedException($"{msg}\n\nRegistered Mappings:\n\n{registeredMappings}", e.Request);}}privateIEnumerable<string>GetRegisteredMappings(){varmappings=(IDictionary)typeof(HttpClientInterceptorOptions).GetField("_mappings", BindingFlags.Instance | BindingFlags.NonPublic)!.GetValue(Options)!;if(mappings.Count ==0)return Array.Empty<string>();// Keys prefixed with CUSTOM: will not show the query params of the URI.// We will append them at the end of the method.varregistrations= mappings.Values.Cast<object>().ToCollection();// sealed internal class: HttpInterceptionResponsevartype= registrations.First().GetType();Dictionary<string,PropertyInfo>propertyInfos= type
.GetProperties(BindingFlags.Instance|BindingFlags.NonPublic).ToDictionary(d => d.Name);string?GetValue(stringpropertyName,objecto)=> propertyInfos[propertyName].GetValue(o)?.ToString();string?IfExists(stringpropertyName,objecto,stringtext)=>
propertyInfos[propertyName].GetValue(o)!=null?$"{text}":null;string?IfTrue(stringpropertyName,objecto,stringtext)=>((bool?)propertyInfos[propertyName].GetValue(o)).GetValueOrDefault()?$"{text}":null;return registrations
.Select(o =>$"{GetValue("Method", o)}{GetValue("RequestUri", o)}"+$"{IfExists("ContentMatcher", o,"+content-matching")}"+$"{IfExists("UserMatcher", o,"+user-matching")}"+$"{IfTrue("IgnoreHost", o,"ignore-host")}"+$"{IfTrue("IgnorePath", o,"ignore-path")}"+$"{IfTrue("IgnoreQuery", o,"ignore-query")}").Concat(HttpRequestInterceptionBuilderExtensions.GetCurrentTestUnescapedQueries());}}
The text was updated successfully, but these errors were encountered:
I wonder if a better way to build this in at some point would be to add some APIs related to introspection (which would maybe fit with some one-day aim to improve logging/debugging), and then something like this could build on top of that.
This is definitely a hack and there are better ways to provide this if done from within the framework. Providing this level of detail is also probably not necessary for all consumers of the package. I could see making it an option and/or lazily resolved property on the exception.
When first using this library, we found it difficult to debug issues when a registration wasn't found that we expected. We use Refit and found that sometimes the mismatch was due to order of url params or encoding issues. We also have test infra to configure common calls like auth sequences for various integrations.
We ended up extending IntereceptingHttpMessageHandler to enrich the HttpRequestNotInterceptedException with a list of registered interceptions. Below is the handler we created. It's not perfect since it can't easily report custom matching, but it significantly improved our experience of troubleshooting missing registrations. I've been intending to offer this as a PR but I don't think I'll have time soon so wanted to offer this for anyone it might benefit or would like to use for a PR.
The text was updated successfully, but these errors were encountered: