22// The .NET Foundation licenses this file to you under the MIT license.
33// See the LICENSE file in the project root for more information.
44
5+ using CommunityToolkit . Datasync . Client . Http ;
56using CommunityToolkit . Datasync . Client . Paging ;
67using CommunityToolkit . Datasync . Client . Query ;
78using CommunityToolkit . Datasync . Client . Query . Linq ;
@@ -23,6 +24,31 @@ namespace CommunityToolkit.Datasync.Client;
2324/// <typeparam name="TEntity">The type of entity being processed by this service client.</typeparam>
2425internal class DatasyncServiceClient < TEntity > : IDatasyncServiceClient < TEntity > where TEntity : class
2526{
27+ /// <summary>
28+ /// Creates a new <see cref="DatasyncServiceClient{TEntity}"/> using default information based on
29+ /// the <see cref="HttpClientOptions"/> provided.
30+ /// </summary>
31+ /// <remarks>
32+ /// The default path is /tables/entityName as a relative URI to the Endpoint in the options.
33+ /// </remarks>
34+ /// <param name="options">The <see cref="HttpClientOptions"/> to use.</param>
35+ public DatasyncServiceClient ( HttpClientOptions options )
36+ : this ( new Uri ( $ "/tables/{ typeof ( TEntity ) . Name . ToLowerInvariant ( ) } ", UriKind . Relative ) , new HttpClientFactory ( options ) . CreateClient ( ) )
37+ {
38+ }
39+
40+ /// <summary>
41+ /// Creates a new <see cref="DatasyncServiceClient{TEntity}"/> with the normal information required for
42+ /// communicating with a datasync service, using the default JSON Serializer Options.
43+ /// </summary>
44+ /// <param name="endpoint">The endpoint of the table controller that processes the entity.</param>
45+ /// <param name="client">The <see cref="HttpClient"/> to use for communication.</param>
46+ /// <exception cref="UriFormatException">Thrown if the endpoint is not valid.</exception>
47+ public DatasyncServiceClient ( Uri endpoint , HttpClient client )
48+ : this ( endpoint , client , DatasyncSerializer . JsonSerializerOptions )
49+ {
50+ }
51+
2652 /// <summary>
2753 /// Creates a new <see cref="DatasyncServiceClient{TEntity}"/> with the normal information required for
2854 /// communicating with a datasync service.
@@ -33,6 +59,7 @@ internal class DatasyncServiceClient<TEntity> : IDatasyncServiceClient<TEntity>
3359 /// <exception cref="UriFormatException">Thrown if the endpoint is not valid.</exception>
3460 public DatasyncServiceClient ( Uri endpoint , HttpClient client , JsonSerializerOptions serializerOptions )
3561 {
62+ endpoint = MakeAbsoluteUri ( client . BaseAddress , endpoint ) ;
3663 ThrowIf . IsNotValidEndpoint ( endpoint , nameof ( endpoint ) ) ;
3764 ArgumentNullException . ThrowIfNull ( client , nameof ( client ) ) ;
3865 ArgumentNullException . ThrowIfNull ( serializerOptions , nameof ( serializerOptions ) ) ;
@@ -493,4 +520,28 @@ internal async ValueTask<Page<TEntity>> GetNextPageAsync(string queryOrContinuat
493520 result . ThrowIfNotSuccessful ( requireContent : true ) ;
494521 return result . Value ! ;
495522 }
523+
524+ /// <summary>
525+ /// Converts a base address + relative/absolute URI into the appropriate URI for the datasync service.
526+ /// </summary>
527+ /// <param name="baseAddress">The base address from the client.</param>
528+ /// <param name="relativeOrAbsoluteUri">A relative or absolute URI</param>
529+ /// <returns></returns>
530+ internal static Uri MakeAbsoluteUri ( Uri ? baseAddress , Uri relativeOrAbsoluteUri )
531+ {
532+ if ( relativeOrAbsoluteUri . IsAbsoluteUri )
533+ {
534+ return new Uri ( $ "{ relativeOrAbsoluteUri . ToString ( ) . TrimEnd ( '/' ) } /") ;
535+ }
536+
537+ if ( baseAddress != null )
538+ {
539+ if ( baseAddress . IsAbsoluteUri )
540+ {
541+ return new Uri ( $ "{ new Uri ( baseAddress , relativeOrAbsoluteUri ) . ToString ( ) . TrimEnd ( '/' ) } /") ;
542+ }
543+ }
544+
545+ throw new UriFormatException ( "Invalid combination of baseAddress and relativeUri" ) ;
546+ }
496547}
0 commit comments