27
27
using System . Net . Security ;
28
28
using System . Reflection ;
29
29
using System . Security . Cryptography . X509Certificates ;
30
- using System . Security . Principal ;
31
30
using System . Text ;
32
31
using System . Text . RegularExpressions ;
33
32
using RestSharp . Serialization ;
34
33
using RestSharp . Serialization . Json ;
35
34
using RestSharp . Serialization . Xml ;
36
- using RestSharp . Serializers ;
37
35
38
36
namespace RestSharp
39
37
{
@@ -94,12 +92,8 @@ public RestClient(string baseUrl) : this()
94
92
/// <param name="serializer">The custom serializer instance</param>
95
93
/// <returns></returns>
96
94
[ Obsolete ( "Use the overload that accepts the delegate factory" ) ]
97
- public IRestClient UseSerializer ( IRestSerializer serializer )
98
- {
99
- UseSerializer ( ( ) => serializer ) ;
100
-
101
- return this ;
102
- }
95
+ public IRestClient UseSerializer ( IRestSerializer serializer ) =>
96
+ Fluent ( ( ) => UseSerializer ( ( ) => serializer ) ) ;
103
97
104
98
/// <summary>
105
99
/// Replace the default serializer with a custom one
@@ -130,15 +124,15 @@ public IRestClient UseSerializer(Func<IRestSerializer> serializerFactory)
130
124
/// <param name="encoder">A delegate to encode parameters</param>
131
125
/// <example>client.UseUrlEncoder(s => HttpUtility.UrlEncode(s));</example>
132
126
/// <returns></returns>
133
- public IRestClient UseUrlEncoder ( Func < string , string > encoder )
134
- {
135
- Encode = encoder ;
136
- return this ;
137
- }
127
+ public IRestClient UseUrlEncoder ( Func < string , string > encoder ) => Fluent ( ( ) => Encode = encoder ) ;
128
+
129
+ public IRestClient UseQueryEncoder ( Func < string , Encoding , string > queryEncoder ) =>
130
+ Fluent ( ( ) => EncodeQuery = queryEncoder ) ;
138
131
139
132
private IDictionary < string , Func < IDeserializer > > ContentHandlers { get ; }
140
133
internal IDictionary < DataFormat , IRestSerializer > Serializers { get ; }
141
134
private Func < string , string > Encode { get ; set ; } = s => s . UrlEncode ( ) ;
135
+ private Func < string , Encoding , string > EncodeQuery { get ; set ; } = ( s , encoding ) => s . UrlEncode ( encoding ) ;
142
136
143
137
private IList < string > AcceptTypes { get ; }
144
138
@@ -370,10 +364,9 @@ string IRestClient.BuildUriWithoutQueryParameters(IRestRequest request)
370
364
371
365
private void DoBuildUriValidations ( IRestRequest request )
372
366
{
373
- if ( BaseUrl == null )
374
- {
375
- throw new NullReferenceException ( "RestClient must contain a value for BaseUrl" ) ;
376
- }
367
+ if ( BaseUrl == null && ! request . Resource . ToLower ( ) . StartsWith ( "http" ) )
368
+ throw new ArgumentOutOfRangeException ( nameof ( request ) ,
369
+ "Request resource doesn't contain a valid scheme for an empty client base URL" ) ;
377
370
378
371
var nullValuedParams = request . Parameters
379
372
. Where ( p => p . Type == ParameterType . UrlSegment && p . Value == null )
@@ -390,21 +383,21 @@ private void DoBuildUriValidations(IRestRequest request)
390
383
391
384
private UrlSegmentParamsValues GetUrlSegmentParamsValues ( IRestRequest request )
392
385
{
393
- var assembled = request . Resource ;
394
- var hasResource = ! string . IsNullOrEmpty ( assembled ) ;
386
+ var assembled = BaseUrl == null ? "" : request . Resource ;
387
+ var baseUrl = BaseUrl ?? new Uri ( request . Resource ) ;
388
+
389
+ var hasResource = ! assembled . IsEmpty ( ) ;
395
390
var parameters = request . Parameters . Where ( p => p . Type == ParameterType . UrlSegment ) . ToList ( ) ;
396
391
parameters . AddRange ( DefaultParameters . Where ( p => p . Type == ParameterType . UrlSegment ) ) ;
397
- var builder = new UriBuilder ( BaseUrl ) ;
392
+ var builder = new UriBuilder ( baseUrl ) ;
398
393
399
394
foreach ( var parameter in parameters )
400
395
{
401
396
var paramPlaceHolder = $ "{{{parameter.Name}}}";
402
397
var paramValue = Encode ( parameter . Value . ToString ( ) ) ;
403
398
404
399
if ( hasResource )
405
- {
406
400
assembled = assembled . Replace ( paramPlaceHolder , paramValue ) ;
407
- }
408
401
409
402
builder . Path = builder . Path . UrlDecode ( ) . Replace ( paramPlaceHolder , paramValue ) ;
410
403
}
@@ -479,15 +472,15 @@ private Func<IDeserializer> GetHandler(string contentType)
479
472
if ( contentType . IsEmpty ( ) && ContentHandlers . ContainsKey ( "*" ) )
480
473
return ContentHandlers [ "*" ] ;
481
474
482
- if ( contentType . IsEmpty ( ) )
475
+ if ( contentType . IsEmpty ( ) )
483
476
return ContentHandlers . First ( ) . Value ;
484
477
485
478
int semicolonIndex = contentType . IndexOf ( ';' ) ;
486
479
487
480
if ( semicolonIndex > - 1 )
488
481
contentType = contentType . Substring ( 0 , semicolonIndex ) ;
489
482
490
- if ( ContentHandlers . TryGetValue ( contentType , out var contentHandler ) )
483
+ if ( ContentHandlers . TryGetValue ( contentType , out var contentHandler ) )
491
484
return contentHandler ;
492
485
493
486
// Avoid unnecessary use of regular expressions in checking for structured syntax suffix by looking for a '+' first
@@ -512,18 +505,18 @@ private Func<IDeserializer> GetHandler(string contentType)
512
505
private void AuthenticateIfNeeded ( RestClient client , IRestRequest request ) =>
513
506
Authenticator ? . Authenticate ( client , request ) ;
514
507
515
- private static string EncodeParameters ( IEnumerable < Parameter > parameters , Encoding encoding ) =>
508
+ private string EncodeParameters ( IEnumerable < Parameter > parameters , Encoding encoding ) =>
516
509
string . Join ( "&" , parameters . Select ( parameter => EncodeParameter ( parameter , encoding ) ) . ToArray ( ) ) ;
517
510
518
- private static string EncodeParameter ( Parameter parameter , Encoding encoding ) =>
519
- parameter . Value == null
520
- ? parameter . Type == ParameterType . QueryStringWithoutEncode
521
- ? string . Concat ( parameter . Name , "=" )
522
- : string . Concat ( parameter . Name . UrlEncode ( encoding ) , "=" )
523
- : parameter . Type == ParameterType . QueryStringWithoutEncode
524
- ? string . Concat ( parameter . Name , "=" , parameter . Value . ToString ( ) )
525
- : string . Concat ( parameter . Name . UrlEncode ( encoding ) , "=" ,
526
- parameter . Value . ToString ( ) . UrlEncode ( encoding ) ) ;
511
+ private string EncodeParameter ( Parameter parameter , Encoding encoding )
512
+ {
513
+ return
514
+ parameter . Type == ParameterType . QueryStringWithoutEncode
515
+ ? $ " { parameter . Name } = { StringOrEmpty ( parameter . Value ) } "
516
+ : $ " { EncodeQuery ( parameter . Name , encoding ) } = { EncodeQuery ( StringOrEmpty ( parameter . Value ) , encoding ) } " ;
517
+
518
+ string StringOrEmpty ( object value ) => value == null ? "" : value . ToString ( ) ;
519
+ }
527
520
528
521
private static readonly ParameterType [ ] MultiParameterTypes =
529
522
{ ParameterType . QueryString , ParameterType . GetOrPost } ;
@@ -550,8 +543,9 @@ internal IHttp ConfigureHttp(IRestRequest request)
550
543
foreach ( var defaultParameter in DefaultParameters )
551
544
{
552
545
var parameterExists =
553
- request . Parameters . Any ( p => p . Name . Equals ( defaultParameter . Name , StringComparison . InvariantCultureIgnoreCase )
554
- && p . Type == defaultParameter . Type ) ;
546
+ request . Parameters . Any ( p =>
547
+ p . Name . Equals ( defaultParameter . Name , StringComparison . InvariantCultureIgnoreCase )
548
+ && p . Type == defaultParameter . Type ) ;
555
549
556
550
if ( AllowMultipleDefaultParametersWithSameName )
557
551
{
@@ -563,7 +557,8 @@ internal IHttp ConfigureHttp(IRestRequest request)
563
557
}
564
558
565
559
// Add Accept header based on registered deserializers if none has been set by the caller.
566
- if ( requestParameters . All ( p => ! string . Equals ( p . Name , "accept" , StringComparison . InvariantCultureIgnoreCase ) ) )
560
+ if ( requestParameters . All (
561
+ p => ! string . Equals ( p . Name , "accept" , StringComparison . InvariantCultureIgnoreCase ) ) )
567
562
{
568
563
var accepts = string . Join ( ", " , AcceptTypes . ToArray ( ) ) ;
569
564
@@ -743,8 +738,8 @@ private IRestResponse<T> Deserialize<T>(IRestRequest request, IRestResponse raw)
743
738
catch ( Exception ex )
744
739
{
745
740
if ( FailOnDeserializationError )
746
- response . ResponseStatus = ResponseStatus . Error ;
747
-
741
+ response . ResponseStatus = ResponseStatus . Error ;
742
+
748
743
response . ErrorMessage = ex . Message ;
749
744
response . ErrorException = ex ;
750
745
}
@@ -773,6 +768,12 @@ private static bool IsWildcardStructuredSuffixSyntax(string contentType)
773
768
return StructuredSyntaxSuffixWildcardRegex . IsMatch ( contentType ) ;
774
769
}
775
770
771
+ private IRestClient Fluent ( Action action )
772
+ {
773
+ action ( ) ;
774
+ return this ;
775
+ }
776
+
776
777
private class UrlSegmentParamsValues
777
778
{
778
779
public UrlSegmentParamsValues ( Uri builderUri , string assembled )
0 commit comments