diff --git a/src/Configuration/AddAzureAppConfigExtensions.cs b/src/Configuration/AddAzureAppConfigExtensions.cs index 1acbaf03..a0089507 100644 --- a/src/Configuration/AddAzureAppConfigExtensions.cs +++ b/src/Configuration/AddAzureAppConfigExtensions.cs @@ -31,7 +31,7 @@ // /*** Add Azure AppConfig ***/ // // Retrieve the connection string // var connectionString = builder.Configuration[connectionStringKey]; -// if (connectionString.IsNullOrEmpty()) +// if (connectionIsNullOrEmpty()) // { // throw new ArgumentException( // $"The connection string for Azure App Configuration was not found. " diff --git a/src/MicrosoftGraph/Constants/MimeTypes.cs b/src/MicrosoftGraph/Constants/MimeTypes.cs index 1715ee3e..34621b39 100644 --- a/src/MicrosoftGraph/Constants/MimeTypes.cs +++ b/src/MicrosoftGraph/Constants/MimeTypes.cs @@ -1,19 +1,47 @@ namespace Dgmjr.Graph.Constants; + using Dgmjr.Mime; public static class MimeTypes { + /// msgraph private const string MsGraph = "msgraph"; + /// -extension-properties public const string MsGraphExtensionPropertiesList = $"{MsGraph}-extension-properties"; - public const string MsGraphExtensionPropertiesListJson = $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.Json.DisplayName}"; - public const string MsGraphExtensionPropertiesListXml = $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.Xml.DisplayName}"; - public const string MsGraphExtensionPropertiesListBson = $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.Bson.DisplayName}"; - public const string MsGraphExtensionPropertiesListMsgPack = $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.MessagePack.DisplayName}"; + /// / + public const string MsGraphExtensionPropertiesListJson = + $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.Json.DisplayName}"; + + /// / + public const string MsGraphExtensionPropertiesListXml = + $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.Xml.DisplayName}"; + + /// / + public const string MsGraphExtensionPropertiesListBson = + $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.Bson.DisplayName}"; + + /// / + public const string MsGraphExtensionPropertiesListMsgPack = + $"{Application.Base.DisplayName}/{MsGraphExtensionPropertiesList}{Suffixes.MessagePack.DisplayName}"; + + /// -user public const string MsGraphUser = $"{MsGraph}-user"; - public const string MsGraphUserJson = $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.Json.DisplayName}"; - public const string MsGraphUserXml = $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.Xml.DisplayName}"; - public const string MsGraphUserBson = $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.Bson.DisplayName}"; - public const string MsGraphUserMsgPack = $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.MessagePack.DisplayName}"; + + /// / + public const string MsGraphUserJson = + $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.Json.DisplayName}"; + + /// / + public const string MsGraphUserXml = + $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.Xml.DisplayName}"; + + /// / + public const string MsGraphUserBson = + $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.Bson.DisplayName}"; + + /// / + public const string MsGraphUserMsgPack = + $"{Application.Base.DisplayName}/{MsGraphUser}{Suffixes.MessagePack.DisplayName}"; } diff --git a/src/MicrosoftGraph/Constants/Uris.cs b/src/MicrosoftGraph/Constants/Uris.cs index 2cce190a..1ad41cbe 100644 --- a/src/MicrosoftGraph/Constants/Uris.cs +++ b/src/MicrosoftGraph/Constants/Uris.cs @@ -1,12 +1,14 @@ namespace Dgmjr.Graph.Constants; + using Dgmjr.Mime; public static class Uris { - public const string Api = "api"; - public const string MsGraph = "msgraph"; - public const string Users = "users"; - public const string MsGraphApi = $"{Api}/{MsGraph}"; - public const string Me = "me"; + public const string Api = "/api"; + public const string MsGraph = "/msgraph"; + public const string Users = "/users"; + public const string MsGraphApi = $"{Api}{MsGraph}"; + public const string Me = "/me"; + public const string DirectoryObjects = "/directoryObjects"; public const string ExtensionProperties = "extensionProperties"; } diff --git a/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs b/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs new file mode 100644 index 00000000..dcf6ad0e --- /dev/null +++ b/src/MicrosoftGraph/Controllers/DirectoryObjectsController.cs @@ -0,0 +1,37 @@ +/* + * DirectoryObjectsController.cs + * + * Created: 2024-55-16T14:55:21-05:00 + * Modified: 2024-55-16T14:55:21-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.Graph.Controllers; + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; + +[Route($"{MsGraphApi}{DirectoryObjects}")] +public class DirectoryObjectsController( + ILogger logger, + IServiceProvider services +) : MsGraphController(logger, services) +{ + private IDirectoryObjectsService DirectoryObjectsService => + services.GetRequiredService(); + + [HttpGet(Uris.ExtensionProperties)] + public async Task GetExtensionPropertiesAsync() + { + Logger.PageVisited(Http.Get, Request.Path); + return Ok( + ( + await DirectoryObjectsService.GetExtensionPropertiesAsync(default) + ).Cast() + ); + } +} diff --git a/src/MicrosoftGraph/Controllers/MeController.cs b/src/MicrosoftGraph/Controllers/MeController.cs index 8f0453eb..f4c99346 100644 --- a/src/MicrosoftGraph/Controllers/MeController.cs +++ b/src/MicrosoftGraph/Controllers/MeController.cs @@ -3,13 +3,15 @@ namespace Dgmjr.Graph.Controllers; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Application = Dgmjr.Mime.Application; +using Dgmjr.Abstractions; +using Microsoft.Extensions.Logging; +using Microsoft.Identity.Web.Resource; -[Route($"{MsGraphApi}/{Me}")] -[AuthorizeForScopes(Scopes = [MsGraphScopes.User.ReadWrite.All])] -public class MeController(ILogger logger, IServiceProvider services) : ControllerBase, ILog, IHaveAGraphClient +[AuthorizeForScopes(Scopes = [MsGraphScopes.User.Read.Base])] +[RequiredScope([MsGraphScopes.User.Read.Base])] +[Route($"{MsGraphApi}{Me}")] +public class MeController(ILogger logger, IServiceProvider services) : MsGraphController(logger, services) { - public ILogger Logger => logger; - public GraphServiceClient Graph => services.GetRequiredService(); private readonly IUsersService _users = services.GetRequiredService(); [HttpGet] @@ -28,7 +30,7 @@ public async Task Get() [ProducesResponseType(typeof(long), Status200OK)] public async Task Get([FromRoute] string property) { - Logger.PageVisited(Http.Get, $"{Me}/{property}"); + Logger.PageVisited(Http.Get, Request.Path); var propertyFullName = new DGraphExtensionProperty(property).Name; var result = await Graph.Me.Request().Select(u => u.AdditionalData[propertyFullName]).GetAsync(); var value = result.AdditionalData[new DGraphExtensionProperty(property).Name]; @@ -39,7 +41,7 @@ public async Task Get([FromRoute] string property) [Produces(MsGraphUserJson, MsGraphUserXml, MsGraphUserBson, MsGraphUserMsgPack)] public async Task Post([FromRoute] string property, [FromQuery] string value) { - Logger.PageVisited(Http.Post, $"{Me}/{property}"); + Logger.PageVisited(Http.Post, Request.Path); var me = await Graph.Me.Request().GetAsync(); me.AdditionalData[property] = value; return Ok(await Graph.Me.Request().UpdateAsync(me)); diff --git a/src/MicrosoftGraph/Controllers/MsGraphController.cs b/src/MicrosoftGraph/Controllers/MsGraphController.cs new file mode 100644 index 00000000..375ce749 --- /dev/null +++ b/src/MicrosoftGraph/Controllers/MsGraphController.cs @@ -0,0 +1,25 @@ +/* + * MsGraphController.cs + * + * Created: 2024-55-16T14:55:53-05:00 + * Modified: 2024-55-16T14:55:54-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.Graph.Controllers; + +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; + +[Route(MsGraphApi)] +public abstract class MsGraphController(ILogger logger, IServiceProvider services) + : ControllerBase, + IHaveAGraphClient +{ + public ILogger Logger => logger; + public GraphServiceClient Graph => services.GetRequiredService(); +} diff --git a/src/MicrosoftGraph/Controllers/UsersController.cs b/src/MicrosoftGraph/Controllers/UsersController.cs index 88a1a83a..7c084642 100644 --- a/src/MicrosoftGraph/Controllers/UsersController.cs +++ b/src/MicrosoftGraph/Controllers/UsersController.cs @@ -1,14 +1,16 @@ namespace Dgmjr.Graph.Controllers; + using Dgmjr.Graph.Abstractions; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Application = Dgmjr.Mime.Application; +using Dgmjr.Abstractions; -[Route($"{MsGraphApi}/{Users}")] [AuthorizeForScopes(ScopeKeySection = DownstreamApis_MicrosoftGraph_Scopes)] -public class UsersController(ILogger logger, IServiceProvider services) : ControllerBase, ILog +[Route($"{MsGraphApi}{Users}")] +public class UsersController(ILogger logger, IServiceProvider services) + : MsGraphController(logger, services) { - public ILogger Logger => logger; private readonly IUsersService _users = services.GetRequiredService(); [HttpGet("{userId:guid}")] @@ -16,18 +18,24 @@ public class UsersController(ILogger logger, IServiceProvider s [Produces(MsGraphUserJson, MsGraphUserXml, MsGraphUserBson, MsGraphUserMsgPack)] public async Task Get([FromRoute] guid userId) { - Logger.PageVisited(Http.Get, $"{Users}/{userId}"); + Logger.PageVisited(Http.Get, Request.Path); return Ok(await _users.GetAsync(userId.ToString())); } [HttpGet("{property}")] - [Produces(Text.Plain.DisplayName, Application.Json.DisplayName, Application.Xml.DisplayName, Application.Bson.DisplayName, Application.MessagePack.DisplayName)] + [Produces( + Text.Plain.DisplayName, + Application.Json.DisplayName, + Application.Xml.DisplayName, + Application.Bson.DisplayName, + Application.MessagePack.DisplayName + )] [ProducesResponseType(typeof(string), Status200OK)] [ProducesResponseType(typeof(int), Status200OK)] [ProducesResponseType(typeof(long), Status200OK)] public async Task Get([FromRoute] string property) { - Logger.PageVisited(Http.Get, $"{Users}/{property}"); + Logger.PageVisited(Http.Get, Request.Path); var result = await _users.GetAsync((await _users.GetMyIdAsync()).ToString(), property); var value = result.AdditionalData[new DGraphExtensionProperty(property).Name]; return Ok(value); @@ -35,19 +43,30 @@ public async Task Get([FromRoute] string property) [HttpPost("{userId}/{property}")] [Produces(MsGraphUserJson, MsGraphUserXml, MsGraphUserBson, MsGraphUserMsgPack)] - public async Task Post([FromRoute] guid userId, [FromRoute] string property, [FromQuery] string value) + public async Task Post( + [FromRoute] guid userId, + [FromRoute] string property, + [FromQuery] string value + ) { - Logger.PageVisited(Http.Post, $"{Users}/{userId}/{property}"); + Logger.PageVisited(Http.Post, Request.Path); var user = await _users.UpdateAsync(userId.ToString(), property, value); return Ok(user); } [HttpGet(Uris.ExtensionProperties)] [ProducesResponseType(typeof(DGraphExtensionProperty[]), Status200OK)] - [Produces(MsGraphExtensionPropertiesListJson, MsGraphExtensionPropertiesListXml, MsGraphExtensionPropertiesListBson, MsGraphExtensionPropertiesListMsgPack)] + [Produces( + MsGraphExtensionPropertiesListJson, + MsGraphExtensionPropertiesListXml, + MsGraphExtensionPropertiesListBson, + MsGraphExtensionPropertiesListMsgPack + )] public async Task GetExtensionProperties() { - Logger.PageVisited(Http.Get, $"{Users}/{Uris.ExtensionProperties}"); - return Ok((await _users.GetExtensionPropertiesAsync(default)).Cast()); + Logger.PageVisited(Http.Get, Request.Path); + return Ok( + (await _users.GetExtensionPropertiesAsync(default)).Cast() + ); } } diff --git a/src/MicrosoftGraph/Dgmjr.Graph.csproj b/src/MicrosoftGraph/Dgmjr.Graph.csproj index 1a712776..6ea36ced 100644 --- a/src/MicrosoftGraph/Dgmjr.Graph.csproj +++ b/src/MicrosoftGraph/Dgmjr.Graph.csproj @@ -8,6 +8,7 @@ + @@ -15,6 +16,7 @@ + diff --git a/src/MicrosoftGraph/Dgmjr.Graph.sln b/src/MicrosoftGraph/Dgmjr.Graph.sln index 071b83f4..7e98e5e5 100644 --- a/src/MicrosoftGraph/Dgmjr.Graph.sln +++ b/src/MicrosoftGraph/Dgmjr.Graph.sln @@ -10,7 +10,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Web.DownstreamApis", "..\DownstreamApis\Dgmjr.Web.DownstreamApis.csproj", "{0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Graph", "Dgmjr.Graph.csproj", "{29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Dgmjr.Graph", "Dgmjr.Graph.csproj", "{D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -34,18 +34,18 @@ Global {0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}.Production|Any CPU.Build.0 = Local|Any CPU {0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}.Release|Any CPU.ActiveCfg = Release|Any CPU {0EB63FC8-4D68-471C-BF25-FF7FBE57A33F}.Release|Any CPU.Build.0 = Release|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Local|Any CPU.ActiveCfg = Local|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Local|Any CPU.Build.0 = Local|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Debug|Any CPU.Build.0 = Debug|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Testing|Any CPU.ActiveCfg = Testing|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Testing|Any CPU.Build.0 = Testing|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Staging|Any CPU.ActiveCfg = Staging|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Staging|Any CPU.Build.0 = Staging|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Production|Any CPU.ActiveCfg = Local|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Production|Any CPU.Build.0 = Local|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Release|Any CPU.ActiveCfg = Release|Any CPU - {29B1DE18-9B2F-4B4A-8B52-48D59A1FF395}.Release|Any CPU.Build.0 = Release|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Local|Any CPU.ActiveCfg = Local|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Local|Any CPU.Build.0 = Local|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Testing|Any CPU.ActiveCfg = Testing|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Testing|Any CPU.Build.0 = Testing|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Staging|Any CPU.ActiveCfg = Staging|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Staging|Any CPU.Build.0 = Staging|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Production|Any CPU.ActiveCfg = Local|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Production|Any CPU.Build.0 = Local|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D6E3A1A7-6CE2-4CB6-AB20-AD3C525E5E23}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/src/MicrosoftGraph/Extensions/LoggingExtensions.cs b/src/MicrosoftGraph/Extensions/LoggingExtensions.cs index 237e0c78..86036235 100644 --- a/src/MicrosoftGraph/Extensions/LoggingExtensions.cs +++ b/src/MicrosoftGraph/Extensions/LoggingExtensions.cs @@ -1,9 +1,24 @@ namespace Dgmjr.Graph; -public static partial class LoggingExtensions +internal static partial class LoggingExtensions { - [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "{Method} {Path}", EventName = nameof(PageVisited))] - public static partial void PageVisited(this ILogger logger, System.Net.Http.HttpMethod method, string path); - [LoggerMessage(EventId = 1, Level = LogLevel.Information, Message = "{Method} {Path}", EventName = nameof(PageVisited))] + [LoggerMessage( + EventId = 1, + Level = LogLevel.Information, + Message = "{Method} {Path}", + EventName = nameof(PageVisited) + )] + public static partial void PageVisited( + this ILogger logger, + System.Net.Http.HttpMethod method, + string path + ); + + [LoggerMessage( + EventId = 1, + Level = LogLevel.Information, + Message = "{Method} {Path}", + EventName = nameof(PageVisited) + )] public static partial void PageVisited(this ILogger logger, string method, string path); } diff --git a/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs b/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs index 8c68358f..1ebb9da2 100644 --- a/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs +++ b/src/MicrosoftGraph/Extensions/MicrosoftGraphServiceCollectionExtensions.cs @@ -2,24 +2,31 @@ namespace Microsoft.Extensions.DependencyInjection; public static class MicrosoftGraphServiceCollectionExtensions { - public static IServiceCollection AddMicrosoftGraph(this IServiceCollection services, IConfiguration config) + public static IServiceCollection AddMicrosoftGraph( + this IServiceCollection services, + IConfiguration config + ) { - services.AddMicrosoftGraph(options => config.Bind(options)) + var configSection = config.GetSection(DownstreamApis_MicrosoftGraph); + services + .AddMicrosoftGraph(options => config.Bind(options)) .AddMicrosoftIdentityConsentHandler() - .ConfigureDownstreamApi( - MicrosoftGraph, - config.GetSection(DownstreamApis_MicrosoftGraph) - ); + .ConfigureDownstreamApi(MicrosoftGraph, configSection); services.AddScoped(); - services.Configure(config.GetSection(DownstreamApis_MicrosoftGraph)); + services.Configure(configSection); services.AddScoped(); services.AddSingleton(); return services; } - public static IServiceCollection AddPassphraseGenerator(this IServiceCollection services, IConfiguration config) + public static IServiceCollection AddPassphraseGenerator( + this IServiceCollection services, + IConfiguration config + ) { - services.Configure(config.GetSection(PassphraseGeneratorOptions.AppSettingsKey)); + services.Configure( + config.GetSection(PassphraseGeneratorOptions.AppSettingsKey) + ); services.AddSingleton(); return services; } diff --git a/src/MicrosoftGraph/Services/MsGraphService.cs b/src/MicrosoftGraph/Services/MsGraphService.cs index c086b691..a42ea2e0 100644 --- a/src/MicrosoftGraph/Services/MsGraphService.cs +++ b/src/MicrosoftGraph/Services/MsGraphService.cs @@ -1,6 +1,7 @@ namespace Dgmjr.Graph.Services; +using global::Dgmjr.Abstractions; -public interface IMsGraphService : ILog, IHaveAGraphClient +public interface IMsGraphService : IHaveAGraphClient { /// The client ID of the extensions application guid ExtensionsAppClientId { get; } @@ -21,7 +22,7 @@ public interface IMsGraphService : ILog, IHaveAGraphClient Task GetExtensionsApplicationAsync(); } -public class MsGraphService(GraphServiceClient graph, ILogger logger, IOptionsMonitor options, IOptionsMonitor msidOptions, IDistributedCache cache) : ILog, IMsGraphService +public class MsGraphService(GraphServiceClient graph, ILogger logger, IOptionsMonitor options, IOptionsMonitor msidOptions, IDistributedCache cache) : IMsGraphService { private static readonly duration CacheDuration = duration.FromDays(1000); private static readonly DateTimeOffset CacheExpiration = DateTimeOffset.UtcNow.Add(CacheDuration); diff --git a/src/Mvc/ApiControllerBase.cs b/src/Mvc/ApiControllerBase.cs new file mode 100644 index 00000000..0e16889e --- /dev/null +++ b/src/Mvc/ApiControllerBase.cs @@ -0,0 +1,21 @@ +/* + * ControllerBase.cs + * + * Created: 2024-10-16T04:10:42-05:00 + * Modified: 2024-10-16T04:10:42-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.AspNetCore.Mvc; + +using Microsoft.AspNetCore.Mvc; + +public class ApiControllerBase : ControllerBase +{ + public IActionResult Result(T value, string contentType) => + ControllerExtensions.Result(this, value, contentType); +} diff --git a/src/Mvc/ControllerExtensions.cs b/src/Mvc/ControllerExtensions.cs new file mode 100644 index 00000000..f27d8e04 --- /dev/null +++ b/src/Mvc/ControllerExtensions.cs @@ -0,0 +1,22 @@ +/* + * ControllerExtensions.cs + * + * Created: 2024-13-16T04:13:05-05:00 + * Modified: 2024-13-16T04:13:05-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Microsoft.AspNetCore.Mvc; + +public static class ControllerExtensions +{ + public static IActionResult Result( + this ControllerBase controller, + T value, + string contentType + ) => new Result(value, contentType).Convert(); +} diff --git a/src/Mvc/Result.cs b/src/Mvc/Result.cs new file mode 100644 index 00000000..ab017492 --- /dev/null +++ b/src/Mvc/Result.cs @@ -0,0 +1,43 @@ +/* + * Result.cs + * + * Created: 2024-48-16T04:48:01-05:00 + * Modified: 2024-48-16T04:48:01-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.AspNetCore.Mvc; + +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Infrastructure; + +using OneOf; + +public class Result : OneOfBase, IConvertToActionResult +{ + public Result(T value, string contentType) + : base(value is string ? new ContentResult { Content = value as string, ContentType = contentType, StatusCode = Status200OK } : + new ObjectResult(value) { ContentTypes = [contentType], StatusCode = Status200OK, DeclaredType = typeof(T) }) { } + + protected Result(ContentResult contentResult) : base(contentResult) { } + protected Result(ObjectResult contentResult) : base(contentResult) { } + + public IActionResult Convert() => IsT0 ? AsT0 : AsT1; + + public static implicit operator Result(ContentResult contentResult) => new(contentResult); + + public static implicit operator Result(ObjectResult objectResult) => new(objectResult); + + public static implicit operator ActionResult(Result result) => result.Convert() as ActionResult; +} + +public class Result : Result +{ + public Result(object value, string contentType) : base(value, contentType) { } + public Result(ContentResult contentResult) : base(contentResult) { } + public Result(ObjectResult contentResult) : base(contentResult) { } +} diff --git a/src/Mvc/ViewControllerBase.cs b/src/Mvc/ViewControllerBase.cs new file mode 100644 index 00000000..4f4fac32 --- /dev/null +++ b/src/Mvc/ViewControllerBase.cs @@ -0,0 +1,21 @@ +/* + * ViewControllerBase.cs + * + * Created: 2024-12-16T04:12:28-05:00 + * Modified: 2024-12-16T04:12:28-05:00 + * + * Author: David G. Moore, Jr. + * + * Copyright © 2024 David G. Moore, Jr., All Rights Reserved + * License: MIT (https://opensource.org/licenses/MIT) + */ + +namespace Dgmjr.AspNetCore.Mvc; + +using Microsoft.AspNetCore.Mvc; + +public class ViewControllerBase : Controller +{ + public IActionResult Result(T value, string contentType) => + ControllerExtensions.Result(this, value, contentType); +} diff --git a/src/Swagger/Filters/EnumsAsStringsSchemaFilter.cs b/src/Swagger/Filters/EnumsAsStringsSchemaFilter.cs index 86e845cf..fee7f7a7 100644 --- a/src/Swagger/Filters/EnumsAsStringsSchemaFilter.cs +++ b/src/Swagger/Filters/EnumsAsStringsSchemaFilter.cs @@ -26,8 +26,7 @@ public void Apply(OpenApiSchema model, SchemaFilterContext context) .OfType() .FirstOrDefault(); string label = - enumMemberAttribute == null - || string.IsNullOrWhiteSpace(enumMemberAttribute.Value) + enumMemberAttribute == null || IsNullOrWhiteSpace(enumMemberAttribute.Value) ? enumName : enumMemberAttribute.Value; model.Enum.Add(new OpenApiString(label)); diff --git a/src/Swagger/SwaggerAutoConfigurator.cs b/src/Swagger/SwaggerAutoConfigurator.cs index 99ca40f8..6caddff6 100644 --- a/src/Swagger/SwaggerAutoConfigurator.cs +++ b/src/Swagger/SwaggerAutoConfigurator.cs @@ -1,10 +1,12 @@ -using Microsoft.AspNetCore.Builder; +namespace Microsoft.Extensions.DependencyInjection; -namespace Dgmjr.AspNetCore.Swagger; +using Microsoft.AspNetCore.Builder; -public class SwaggerAutoConfigurator : IConfigureIHostApplicationBuilder, IConfigureIApplicationBuilder +public class SwaggerAutoConfigurator + : IConfigureIHostApplicationBuilder, + IConfigureIApplicationBuilder { - public ConfigurationOrder Order => throw new NotImplementedException(); + public ConfigurationOrder Order => ConfigurationOrder.AnyTime; public void Configure(IHostApplicationBuilder builder) { diff --git a/src/Swagger/SwaggerExtensions/UseSwaggerUI.cs b/src/Swagger/SwaggerExtensions/UseSwaggerUI.cs index 9d512022..a481326d 100644 --- a/src/Swagger/SwaggerExtensions/UseSwaggerUI.cs +++ b/src/Swagger/SwaggerExtensions/UseSwaggerUI.cs @@ -26,7 +26,7 @@ namespace Microsoft.Extensions.DependencyInjection; -public static partial class UseSwaggerUIExtensions +internal static partial class UseSwaggerUIExtensions { private static readonly Assembly Assembly = typeof(UseSwaggerUIExtensions).Assembly;