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