-
Notifications
You must be signed in to change notification settings - Fork 2
Make RestClientContext a record and move logic to RestClientBuilder
#129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using System; | ||
| using System.Net.Http; | ||
|
|
||
| namespace Activout.RestClient.Implementation; | ||
|
|
||
| internal sealed class DummyRequestLogger : IRequestLogger, IDisposable | ||
| { | ||
| public static IRequestLogger Instance { get; } = new DummyRequestLogger(); | ||
|
|
||
| public IDisposable TimeOperation(HttpRequestMessage httpRequestMessage) | ||
| { | ||
| return this; | ||
| } | ||
|
|
||
| public void Dispose() | ||
| { | ||
| // Do nothing | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,76 +1,47 @@ | ||||||||||
| #nullable disable | ||||||||||
| using System; | ||||||||||
| using System.Collections.Concurrent; | ||||||||||
| using System.Collections.Generic; | ||||||||||
| using System.Dynamic; | ||||||||||
| using System.Linq; | ||||||||||
| using System.Reflection; | ||||||||||
| using Activout.RestClient.DomainExceptions; | ||||||||||
|
|
||||||||||
| namespace Activout.RestClient.Implementation | ||||||||||
| namespace Activout.RestClient.Implementation; | ||||||||||
|
|
||||||||||
| internal class RestClient : DynamicObject | ||||||||||
| { | ||||||||||
| internal class RestClient<T> : DynamicObject where T : class | ||||||||||
| { | ||||||||||
| private readonly RestClientContext _context; | ||||||||||
| private readonly Type _type; | ||||||||||
| private readonly RestClientContext _context; | ||||||||||
| private readonly Type _type; | ||||||||||
|
|
||||||||||
| private readonly IDictionary<MethodInfo, RequestHandler> _requestHandlers = | ||||||||||
| new ConcurrentDictionary<MethodInfo, RequestHandler>(); | ||||||||||
| private readonly IDictionary<MethodInfo, RequestHandler> _requestHandlers = | ||||||||||
| new ConcurrentDictionary<MethodInfo, RequestHandler>(); | ||||||||||
|
|
||||||||||
| public RestClient(RestClientContext context) | ||||||||||
| { | ||||||||||
| _type = typeof(T); | ||||||||||
| _context = context; | ||||||||||
| HandleAttributes(); | ||||||||||
| _context.DefaultSerializer = _context.SerializationManager.GetSerializer(_context.DefaultContentType); | ||||||||||
| } | ||||||||||
| public RestClient(Type type, RestClientContext context) | ||||||||||
| { | ||||||||||
| _type = type; | ||||||||||
| _context = context; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| private void HandleAttributes() | ||||||||||
| { | ||||||||||
| var attributes = _type.GetCustomAttributes(); | ||||||||||
| foreach (var attribute in attributes) | ||||||||||
| switch (attribute) | ||||||||||
| { | ||||||||||
| case ContentTypeAttribute contentTypeAttribute: | ||||||||||
| _context.DefaultContentType = MediaType.ValueOf(contentTypeAttribute.ContentType); | ||||||||||
| break; | ||||||||||
| case DomainExceptionAttribute domainExceptionAttribute: | ||||||||||
| _context.DomainExceptionType = domainExceptionAttribute.Type; | ||||||||||
| break; | ||||||||||
| case ErrorResponseAttribute errorResponseAttribute: | ||||||||||
| _context.ErrorResponseType = errorResponseAttribute.Type; | ||||||||||
| break; | ||||||||||
| case HeaderAttribute headerAttribute: | ||||||||||
| _context.DefaultHeaders.AddOrReplaceHeader(headerAttribute.Name, headerAttribute.Value, headerAttribute.Replace); | ||||||||||
| break; | ||||||||||
| case PathAttribute pathAttribute: | ||||||||||
| _context.BaseTemplate = pathAttribute.Template; | ||||||||||
| break; | ||||||||||
| } | ||||||||||
| } | ||||||||||
| public override IEnumerable<string> GetDynamicMemberNames() | ||||||||||
| { | ||||||||||
| return _type.GetMembers().Select(x => x.Name); | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public override IEnumerable<string> GetDynamicMemberNames() | ||||||||||
| public override bool TryInvokeMember(InvokeMemberBinder binder, object?[]? args, out object? result) | ||||||||||
| { | ||||||||||
| var method = _type.GetMethod(binder.Name); | ||||||||||
| if (method == null) | ||||||||||
| { | ||||||||||
| return _type.GetMembers().Select(x => x.Name); | ||||||||||
| result = null; | ||||||||||
| return false; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) | ||||||||||
| if (!_requestHandlers.TryGetValue(method, out var requestHandler)) | ||||||||||
| { | ||||||||||
| var method = _type.GetMethod(binder.Name); | ||||||||||
| if (method == null) | ||||||||||
| { | ||||||||||
| result = null; | ||||||||||
| return false; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| if (!_requestHandlers.TryGetValue(method, out var requestHandler)) | ||||||||||
| { | ||||||||||
| requestHandler = new RequestHandler(method, _context); | ||||||||||
| _requestHandlers[method] = requestHandler; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| result = requestHandler.Send(args); | ||||||||||
| return true; | ||||||||||
| requestHandler = new RequestHandler(method, _context); | ||||||||||
| _requestHandlers[method] = requestHandler; | ||||||||||
| } | ||||||||||
|
|
||||||||||
| result = requestHandler.Send(args); | ||||||||||
| return true; | ||||||||||
|
Comment on lines
+44
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Null-safe handoff of args to RequestHandler.Send(object[])
- result = requestHandler.Send(args);
+ result = requestHandler.Send((args as object[]) ?? Array.Empty<object>());
return true;📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| } | ||||||||||
| } | ||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix overload resolution to avoid AmbiguousMatchException and wrong method dispatch
_type.GetMethod(binder.Name)throws for overloaded methods and ignores argument shapes. Resolve by selecting the best candidate using argument count/types (and allowing a trailing CancellationToken).Apply this diff to use a resolver:
Add this helper inside the class:
And add the needed using:
using System.Reflection; +using System.Threading;🤖 Prompt for AI Agents