From af84871d108d7825013ff8f323383a6b425c2161 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Sat, 16 May 2026 01:14:19 +0330 Subject: [PATCH] Preparing xPushService ... --- Base/XBaseDtoProvider.cs | 11 +- Base/XBaseEntityProvider.cs | 17 +- .../XBaseRepositoryProviderController.cs | 568 +++++++++++++++++ Controllers/XBaseServiceProviderController.cs | 572 ++++++++++++++++++ DI/XDIHelperExtension.cs | 47 +- Interfaces/IXBaseDtoProvider.cs | 5 +- Interfaces/IXBaseEntityProvider.cs | 5 +- .../IXBaseRepositoryProviderController.cs | 200 ++++++ Interfaces/IXBaseServiceProviderController.cs | 201 ++++++ Interfaces/IXHubContextFactory.cs | 9 + Providers/XHubContextFactory.cs | 23 + 11 files changed, 1625 insertions(+), 33 deletions(-) create mode 100644 Controllers/XBaseRepositoryProviderController.cs create mode 100644 Controllers/XBaseServiceProviderController.cs create mode 100644 Interfaces/IXBaseRepositoryProviderController.cs create mode 100644 Interfaces/IXBaseServiceProviderController.cs create mode 100644 Interfaces/IXHubContextFactory.cs create mode 100644 Providers/XHubContextFactory.cs diff --git a/Base/XBaseDtoProvider.cs b/Base/XBaseDtoProvider.cs index 61175ae..de2c6b5 100644 --- a/Base/XBaseDtoProvider.cs +++ b/Base/XBaseDtoProvider.cs @@ -17,25 +17,26 @@ using xPushService.Interfaces; namespace xPushService.Base { - public abstract class XBaseDtoProvider : IXBaseDtoProvider + public abstract class XBaseDtoProvider : IXBaseDtoProvider where TEntity : XBaseEntity where TDto : XBaseEntityDto + where THub : XBaseDtoHub { // #region Properties ... + public IHubContext Hub { get; } public IXIdentityProvider IdentityProvider { get; } public XDataServiceConfiguration DataConfiguration { get; } - public IHubContext> Hub { get; } public IXBaseRepositoryService Service { get; } #endregion // #region Constructor ... protected XBaseDtoProvider( - IXIdentityProvider identityProvider, + IHubContext hub, XDataServiceConfiguration dataConfiguration, - IHubContext> hub, - IXBaseRepositoryService service + IXBaseRepositoryService service, + IXIdentityProvider identityProvider = null ) { // diff --git a/Base/XBaseEntityProvider.cs b/Base/XBaseEntityProvider.cs index 78f80f1..bc66968 100644 --- a/Base/XBaseEntityProvider.cs +++ b/Base/XBaseEntityProvider.cs @@ -17,24 +17,25 @@ using xPushService.Interfaces; namespace xPushService.Base { - public abstract class XBaseEntityProvider : IXBaseEntityProviderr + public abstract class XBaseEntityProvider : IXBaseEntityProviderr where TEntity : XBaseEntity + where THub : XBaseEntityHub { // #region Properties ... + public IHubContext Hub { get; } public IXIdentityProvider IdentityProvider { get; } public IXBaseRepository Repository { get; } public XDataServiceConfiguration DataConfiguration { get; } - public IHubContext> Hub { get; } #endregion // #region Constructor ... protected XBaseEntityProvider( - IXIdentityProvider identityProvider, + IHubContext hub, IXBaseRepository repository, XDataServiceConfiguration dataConfiguration, - IHubContext> hub + IXIdentityProvider identityProvider = null ) { // @@ -411,11 +412,11 @@ namespace xPushService.Base // await clients.SendAsync( - action, - payLoad, - connectionId, + action, + payLoad, + connectionId, cancellationToken - ); + ); } #endregion } diff --git a/Controllers/XBaseRepositoryProviderController.cs b/Controllers/XBaseRepositoryProviderController.cs new file mode 100644 index 0000000..2524bea --- /dev/null +++ b/Controllers/XBaseRepositoryProviderController.cs @@ -0,0 +1,568 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Logging; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xDataService.Extensions; +using xExceptions.Constants; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Interfaces; + +namespace xPushService.Controllers +{ + public abstract class XBaseRepositoryProviderController : XBaseIdentityApiV1Controller, IXBaseRepositoryProviderController + where TEntity : XBaseEntity + where THub : XBaseEntityHub + { + // + #region Properties ... + public IXBaseEntityProviderr Provider { get; } + public Func, IOrderedQueryable> DefaultOrderBuilder { get; } + public Func, IIncludableQueryable> DefaultIncludeBuilder { get; } + #endregion + + protected XBaseRepositoryProviderController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXBaseEntityProviderr provider, + Func, IOrderedQueryable> defaultOrderBuilder, + Func, IIncludableQueryable> defaultIncludeBuilder + ) : base( + logger: logger, + appConfiguration: appConfiguration, + identityProvider: identityProvider, + validationProvider: validationProvider + ) + { + // + Provider = provider; + DefaultOrderBuilder = defaultOrderBuilder; + DefaultIncludeBuilder = defaultIncludeBuilder; + } + + // + #region Actions ... + /// + /// add a new Item ... + /// + /// + /// + /// + /// + [HttpPost] + public virtual async Task> Add( + [FromBody] TEntity item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotNull(item); + + // + var connectionId = GetConnectionId(); + + // + var result = await Provider.AddAsync( + item: item, + saveChanges: saveChanges, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Update an Item values ... + /// + /// + /// + /// + /// + /// + [HttpPut("{id}")] + public virtual async Task> Update( + [FromRoute] TKey id, + [FromBody] TEntity item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotNull(item); + + // + var connectionId = GetConnectionId(); + + // + var result = await Provider.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// remove an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpDelete("{id}")] + public virtual async Task> Remove( + [FromRoute] TKey id, + [FromQuery] bool softDelete = true, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var connectionId = GetConnectionId(); + + // + var result = await Provider.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + /// + [HttpGet("{id}/[action]")] + public virtual async Task> IsExists( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.IsExistsAsync( + id: id, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// count all exists Items ... + /// + /// + /// + /// + [HttpGet("Count")] + public virtual async Task> Count( + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.CountAsync( + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// retrieve an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpGet("{id}")] + public virtual async Task> Get( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.GetAsync( + id: id, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// retrieve all exists Items ... + /// + /// + /// + /// + /// + /// + [HttpGet] + public virtual async Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.GetAllAsync( + orderBuilder: !useDefaultOrders + ? null + : DefaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// find an Item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public virtual async Task> FindOne( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotEmpty(query); + + // + Expression> predicate = x => x.PropValuesContains(query); + var result = await Provider.FindOneAsync( + predicate: predicate, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task>> FindMany( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotEmpty(query); + + // + Expression> predicate = x => x.PropValuesContains(query); + var result = await Provider.FindManyAsync( + predicate: predicate, + orderBuilder: !useDefaultOrders + ? null + : DefaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task>> Query( + [FromQuery] XQuery query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + if (query.IsNullOrDefault()) + { + query = query.NormalizeQuery(Provider.DataConfiguration); + } + + // + var result = await Provider.QueryAsync( + query: query, + predicate: null, + orderBuilder: !useDefaultOrders + ? null + : DefaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + + // + #region NonActions ... + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + [NonAction] + public virtual async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + await Provider.SendPush( + action: action, + payLoad: payLoad, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + #endregion + } +} \ No newline at end of file diff --git a/Controllers/XBaseServiceProviderController.cs b/Controllers/XBaseServiceProviderController.cs new file mode 100644 index 0000000..d169dbe --- /dev/null +++ b/Controllers/XBaseServiceProviderController.cs @@ -0,0 +1,572 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.Extensions.Logging; +using xCommons.Configurations; +using xCommons.Extensions; +using xCommons.Providers; +using xDataService.Extensions; +using xExceptions.Constants; +using xIdentityService.Controllers; +using xIdentityService.Interfaces; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; +using xPushService.Interfaces; + +namespace xPushService.Controllers +{ + public abstract class XBaseServiceProviderController : XBaseIdentityApiV1Controller, IXBaseServiceProviderController + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + // + #region Properties ... + public IXBaseDtoProvider Provider { get; } + public Func, IOrderedQueryable> DefaultOrderBuilder { get; } + public Func, IIncludableQueryable> DefaultIncludeBuilder { get; } + #endregion + + // + #region Constructor ... + public XBaseServiceProviderController( + ILogger logger, + XAppConfiguration appConfiguration, + IXIdentityProvider identityProvider, + XValidationProvider validationProvider, + IXBaseDtoProvider provider, + Func, IOrderedQueryable> defaultOrderBuilder, + Func, IIncludableQueryable> defaultIncludeBuilder + ) : base( + logger, + appConfiguration, + identityProvider, + validationProvider + ) + { + // + Provider = provider; + DefaultOrderBuilder = defaultOrderBuilder; + DefaultIncludeBuilder = defaultIncludeBuilder; + } + #endregion + + // + #region Actions ... + /// + /// add a new Item ... + /// + /// + /// + /// + /// + [HttpPost] + public virtual async Task> Add( + [FromBody] TDto item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotNull(item); + + // + var connectionId = GetConnectionId(); + + // + var result = await Provider.AddAsync( + item: item, + saveChanges: saveChanges, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Update an Item values ... + /// + /// + /// + /// + /// + /// + [HttpPut("{id}")] + public virtual async Task> Update( + [FromRoute] TKey id, + [FromBody] TDto item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotNull(item); + + // + var connectionId = GetConnectionId(); + + // + var result = await Provider.UpdateAsync( + id: id, + item: item, + saveChanges: saveChanges, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// remove an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpDelete("{id}")] + public virtual async Task> Remove( + [FromRoute] TKey id, + [FromQuery] bool softDelete = true, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var connectionId = GetConnectionId(); + + // + var result = await Provider.RemoveAsync( + id: id, + softDelete: softDelete, + saveChanges: saveChanges, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + /// + [HttpGet("{id}/[action]")] + public virtual async Task> IsExists( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.IsExistsAsync( + id: id, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// count all exists Items ... + /// + /// + /// + /// + [HttpGet("Count")] + public virtual async Task> Count( + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.CountAsync( + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// retrieve an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpGet("{id}")] + public virtual async Task> Get( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.GetAsync( + id: id, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// retrieve all exists Items ... + /// + /// + /// + /// + /// + /// + [HttpGet] + public virtual async Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + var result = await Provider.GetAllAsync( + orderBuilder: !useDefaultOrders + ? null + : DefaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// find an Item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + public virtual async Task> FindOne( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotEmpty(query); + + // + Expression> predicate = x => x.PropValuesContains(query); + var result = await Provider.FindOneAsync( + predicate: predicate, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task>> FindMany( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + ValidationProvider.NotEmpty(query); + + // + Expression> predicate = x => x.PropValuesContains(query); + var result = await Provider.FindManyAsync( + predicate: predicate, + orderBuilder: !useDefaultOrders + ? null + : DefaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + + /// + /// retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + public virtual async Task>> Query( + [FromQuery] XQuery query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ) + { + // + try + { + // + // Validate ... + if (!ModelState.IsValid) + { + XException.InvalidArgs.Throw(); + } + + // + // Normalize ... + if (query.IsNullOrDefault()) + { + query = query.NormalizeQuery(Provider.DataConfiguration); + } + + // + var result = await Provider.QueryAsync( + query: query, + predicate: null, + orderBuilder: !useDefaultOrders + ? null + : DefaultOrderBuilder, + includeBuilder: !useDefaultIncludes + ? null + : DefaultIncludeBuilder, + cancellationToken: cancellationToken, + ignoreSoftDeleteds: ignoreSoftDeleteds + ); + + // + return Ok(result.ToDynamicObject()); + } + catch (Exception ex) + { + // + var result = GetExceptionActionResult(ex); + return result; + } + } + #endregion + + // + #region NonActions ... + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + [NonAction] + public virtual async Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ) + { + // + await Provider.SendPush( + action: action, + payLoad: payLoad, + connectionId: connectionId, + cancellationToken: cancellationToken + ); + } + #endregion + } +} \ No newline at end of file diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index ce4fd75..f3973c0 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -14,6 +14,7 @@ using xExceptions.Constants; using xPushService.Configurations; using xPushService.Constants; using xPushService.Helpers; +using xPushService.Interfaces; using xPushService.Providers; namespace xPushService.DI @@ -160,25 +161,35 @@ namespace xPushService.DI // var hubRoute = config.BaseRoute + "/" + hubDescriptor.Route; hubRoutes.Add(hubRoute); - Console.WriteLine($"XPushService HubRoute: {hubRoute}"); // - Type routesType = routes.GetType(); - MethodInfo mapHubMethod = routesType - .GetMethods() - .SingleOrDefault(m => - m.Name == "MapHub" && - m.GetParameters().Length == 1 - ); - if (mapHubMethod.IsNull()) + try { - throw XException.ActionFailed.ToException(); - } + // + Type routesType = routes.GetType(); + MethodInfo mapHubMethod = routesType + .GetMethods() + .SingleOrDefault(m => + m.Name == "MapHub" && + m.GetParameters().Length == 1 + ); + if (mapHubMethod.IsNull()) + { + throw XException.ActionFailed.ToException(); + } - // - object[] genericMapHubMethodArgs = { new PathString(hubRoute) }; - MethodInfo genericMapHubMethod = mapHubMethod.MakeGenericMethod(hubDescriptor.Hub); - genericMapHubMethod.Invoke(routes, genericMapHubMethodArgs); + // + object[] genericMapHubMethodArgs = { new PathString(hubRoute) }; + MethodInfo genericMapHubMethod = mapHubMethod.MakeGenericMethod(hubDescriptor.Hub); + genericMapHubMethod.Invoke(routes, genericMapHubMethodArgs); + + // + Log($"Register {hubDescriptor.Hub} Hub: {hubRoute}"); + } + catch + { + throw; + } }); }); } @@ -250,7 +261,7 @@ namespace xPushService.DI // // Register XPushService Configuration ... - services.AddSingleton(config); + services.AddSingleton(config); // // Register SignalR ... @@ -267,6 +278,10 @@ namespace xPushService.DI x.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; x.PayloadSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); }); + + // + // Register HubContext Factory ... + services.AddSingleton(); // // Register XPushServiceUserNameProvider ... diff --git a/Interfaces/IXBaseDtoProvider.cs b/Interfaces/IXBaseDtoProvider.cs index 51fff89..4ceda24 100644 --- a/Interfaces/IXBaseDtoProvider.cs +++ b/Interfaces/IXBaseDtoProvider.cs @@ -15,15 +15,16 @@ using xPushService.Base; namespace xPushService.Interfaces { - public interface IXBaseDtoProvider + public interface IXBaseDtoProvider where TEntity : XBaseEntity where TDto : XBaseEntityDto + where THub : XBaseDtoHub { // #region Props ... + IHubContext Hub { get; } IXIdentityProvider IdentityProvider { get; } XDataServiceConfiguration DataConfiguration { get; } - IHubContext> Hub { get; } IXBaseRepositoryService Service { get; } #endregion diff --git a/Interfaces/IXBaseEntityProvider.cs b/Interfaces/IXBaseEntityProvider.cs index f538fe6..eaca198 100644 --- a/Interfaces/IXBaseEntityProvider.cs +++ b/Interfaces/IXBaseEntityProvider.cs @@ -21,15 +21,16 @@ namespace xPushService.Interfaces /// /// /// - public interface IXBaseEntityProviderr + public interface IXBaseEntityProviderr where TEntity : XBaseEntity + where THub : XBaseEntityHub { // #region Props ... + IHubContext Hub { get; } IXIdentityProvider IdentityProvider { get; } IXBaseRepository Repository { get; } XDataServiceConfiguration DataConfiguration { get; } - IHubContext> Hub { get; } #endregion // diff --git a/Interfaces/IXBaseRepositoryProviderController.cs b/Interfaces/IXBaseRepositoryProviderController.cs new file mode 100644 index 0000000..b525eaa --- /dev/null +++ b/Interfaces/IXBaseRepositoryProviderController.cs @@ -0,0 +1,200 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Query; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; + +namespace xPushService.Interfaces +{ + public interface IXBaseRepositoryProviderController + where TEntity : XBaseEntity + where THub : XBaseEntityHub + { + // + #region Properties ... + IXBaseEntityProviderr Provider { get; } + Func, IOrderedQueryable> DefaultOrderBuilder { get; } + Func, IIncludableQueryable> DefaultIncludeBuilder { get; } + #endregion + + // + #region Actions ... + /// + /// add a new Item ... + /// + /// + /// + /// + /// + [HttpPost] + Task> Add( + [FromBody] TEntity item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ); + + /// + /// Update an Item values ... + /// + /// + /// + /// + /// + /// + [HttpPut("{id}")] + Task> Update( + [FromRoute] TKey id, + [FromBody] TEntity item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpDelete("{id}")] + Task> Remove( + [FromRoute] TKey id, + [FromQuery] bool softDelete = true, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ); + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + /// + [HttpGet("{id}/[action]")] + Task> IsExists( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ); + + /// + /// count all exists Items ... + /// + /// + /// + /// + [HttpGet("Count")] + Task> Count( + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpGet("{id}")] + Task> Get( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Items ... + /// + /// + /// + /// + /// + /// + [HttpGet] + Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// find an Item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + Task> FindOne( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + Task>> FindMany( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + Task>> Query( + [FromQuery] XQuery query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Non Actions ... + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + [NonAction] + Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/IXBaseServiceProviderController.cs b/Interfaces/IXBaseServiceProviderController.cs new file mode 100644 index 0000000..e4bb498 --- /dev/null +++ b/Interfaces/IXBaseServiceProviderController.cs @@ -0,0 +1,201 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Mvc; +using Microsoft.EntityFrameworkCore.Query; +using xModels.Base; +using xModels.Dtos; +using xPushService.Base; + +namespace xPushService.Interfaces +{ + public interface IXBaseServiceProviderController + where TEntity : XBaseEntity + where TDto : XBaseEntityDto + where THub : XBaseDtoHub + { + // + #region Properties ... + IXBaseDtoProvider Provider { get; } + Func, IOrderedQueryable> DefaultOrderBuilder { get; } + Func, IIncludableQueryable> DefaultIncludeBuilder { get; } + #endregion + + // + #region Actions ... + /// + /// add a new Item ... + /// + /// + /// + /// + /// + [HttpPost] + Task> Add( + [FromBody] TDto item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ); + + /// + /// Update an Item values ... + /// + /// + /// + /// + /// + /// + [HttpPut("{id}")] + Task> Update( + [FromRoute] TKey id, + [FromBody] TDto item, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ); + + /// + /// remove an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpDelete("{id}")] + Task> Remove( + [FromRoute] TKey id, + [FromQuery] bool softDelete = true, + [FromQuery] bool saveChanges = true, + CancellationToken cancellationToken = default + ); + + /// + /// Check an Item exists or not ... + /// + /// + /// + /// + /// + [HttpGet("{id}/[action]")] + Task> IsExists( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ); + + /// + /// count all exists Items ... + /// + /// + /// + /// + [HttpGet("Count")] + Task> Count( + [FromQuery] bool ignoreSoftDeleteds = true, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve an Item by it's Id ... + /// + /// + /// + /// + /// + /// + [HttpGet("{id}")] + Task> Get( + [FromRoute] TKey id, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve all exists Items ... + /// + /// + /// + /// + /// + /// + [HttpGet] + Task>> GetAll( + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// find an Item by providing a Conditional Expression ... + /// + /// + /// + /// + /// + /// + Task> FindOne( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// find a collection of Items by proving a Conditional Expression ... + /// + /// + /// + /// + /// + /// + /// + Task>> FindMany( + [FromRoute] string query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + + /// + /// retrieve Items based on XQuery Pagination structure ... + /// + /// + /// + /// + /// + /// + /// + Task>> Query( + [FromQuery] XQuery query, + [FromQuery] bool ignoreSoftDeleteds = true, + [FromQuery] bool useDefaultOrders = false, + [FromQuery] bool useDefaultIncludes = false, + CancellationToken cancellationToken = default + ); + #endregion + + // + #region Non Actions ... + /// + /// Send Custom Push Message ... + /// + /// + /// + /// + /// + /// + [NonAction] + Task SendPush( + string action, + string payLoad, + string connectionId = null, + CancellationToken cancellationToken = default + ); + #endregion + } +} \ No newline at end of file diff --git a/Interfaces/IXHubContextFactory.cs b/Interfaces/IXHubContextFactory.cs new file mode 100644 index 0000000..d89f495 --- /dev/null +++ b/Interfaces/IXHubContextFactory.cs @@ -0,0 +1,9 @@ +using Microsoft.AspNetCore.SignalR; + +namespace xPushService.Interfaces +{ + public interface IXHubContextFactory + { + IHubContext Create() where THub : Hub; + } +} \ No newline at end of file diff --git a/Providers/XHubContextFactory.cs b/Providers/XHubContextFactory.cs new file mode 100644 index 0000000..fa34835 --- /dev/null +++ b/Providers/XHubContextFactory.cs @@ -0,0 +1,23 @@ +using System; +using Microsoft.AspNetCore.SignalR; +using Microsoft.Extensions.DependencyInjection; +using xPushService.Interfaces; + +namespace xPushService.Providers +{ + public class XHubContextFactory : IXHubContextFactory + { + private readonly IServiceProvider services; + + public XHubContextFactory(IServiceProvider services) + { + this.services = services; + } + + public IHubContext Create() + where THub : Hub + { + return services.GetRequiredService>(); + } + } +} \ No newline at end of file