-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from j4587698/feat-mvc
添加mvc
- Loading branch information
Showing
12 changed files
with
565 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ jobs: | |
- name: Setup .NET | ||
uses: actions/setup-dotnet@v2 | ||
with: | ||
dotnet-version: 6.0.x | ||
dotnet-version: 8.0.x | ||
- name: Restore dependencies | ||
run: dotnet restore | ||
- name: Build | ||
|
@@ -34,4 +34,9 @@ jobs: | |
PROJECT_FILE_PATH: Jx.Toolbox.HtmlTools/Jx.Toolbox.HtmlTools.csproj | ||
VERSION_REGEX: ^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$ | ||
NUGET_KEY: ${{secrets.NUGET_API_KEY}} | ||
|
||
- name: Publish Jx.Toolbox.Mvc | ||
uses: alirezanet/[email protected] | ||
with: | ||
PROJECT_FILE_PATH: Jx.Toolbox.HtmlTools/Jx.Toolbox.Mvc.csproj | ||
VERSION_REGEX: ^\s*<PackageVersion>(.*)<\/PackageVersion>\s*$ | ||
NUGET_KEY: ${{secrets.NUGET_API_KEY}} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
using System; | ||
using System.Diagnostics.CodeAnalysis; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
|
||
namespace Jx.Toolbox.Mvc; | ||
|
||
public class Application | ||
{ | ||
public static IServiceProvider? ServiceProvider { get; internal set; } | ||
|
||
[NotNull] | ||
public static IWebHostEnvironment? WebHostEnvironment { get; internal set; } | ||
|
||
[NotNull] | ||
public static ConfigurationManager? Configuration { get; internal set; } | ||
|
||
public static T? GetService<T>() where T: class | ||
{ | ||
var service = GetRequiredService<T>(); | ||
if (service != null) | ||
{ | ||
return service; | ||
} | ||
return ServiceProvider?.GetService<T>(); | ||
} | ||
|
||
public static T? GetRequiredService<T>() where T : class | ||
{ | ||
return ServiceProvider?.GetRequiredService<T>(); | ||
} | ||
|
||
public static string? GetValue(string key) | ||
{ | ||
return Configuration[key]; | ||
} | ||
|
||
public static T? GetValue<T>(string key) where T: class | ||
{ | ||
return Configuration.GetSection(key).Get<T>(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Jx.Toolbox.Mvc.Attributes; | ||
|
||
[AttributeUsage(AttributeTargets.Class)] | ||
public class ScopedAttribute : Attribute | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Jx.Toolbox.Mvc.Attributes; | ||
|
||
[AttributeUsage(AttributeTargets.Class)] | ||
public class SingletonAttribute : Attribute | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
namespace Jx.Toolbox.Mvc.Attributes; | ||
|
||
[AttributeUsage(AttributeTargets.Class)] | ||
public class TransientAttribute : Attribute | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
namespace Jx.Toolbox.Mvc.Attributes; | ||
|
||
[AttributeUsage(AttributeTargets.Property)] | ||
public class ValueAttribute : Attribute | ||
{ | ||
public ValueAttribute(string configPath) | ||
{ | ||
ConfigPath = configPath; | ||
} | ||
|
||
/// <summary> | ||
/// config文件中的路径,多层用:分隔,如:AppConfig:AppConfigOption:ConfigSearchFolder | ||
/// </summary> | ||
public string ConfigPath { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
using Microsoft.AspNetCore.Mvc; | ||
|
||
namespace Jx.Toolbox.Mvc; | ||
|
||
public abstract class DynamicControllerBase: ControllerBase | ||
{ | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
using System.Runtime.CompilerServices; | ||
using Jx.Toolbox.Mvc.Options; | ||
using Microsoft.AspNetCore.Mvc; | ||
using Microsoft.AspNetCore.Mvc.ActionConstraints; | ||
using Microsoft.AspNetCore.Mvc.ApplicationModels; | ||
using Microsoft.AspNetCore.Mvc.Routing; | ||
using Microsoft.AspNetCore.Routing; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Options; | ||
|
||
namespace Jx.Toolbox.Mvc.Extensions; | ||
|
||
public static class MvcExtension | ||
{ | ||
public static IMvcBuilder AddServiceController(this IServiceCollection collection, | ||
bool enableDynamicController = true) | ||
{ | ||
using var serviceProvider = collection.BuildServiceProvider(); | ||
var option = serviceProvider.GetService<IOptions<AppConfigOption>>()?.Value ?? new AppConfigOption(); | ||
var builder = collection.AddMvc(options => | ||
{ | ||
if (enableDynamicController) | ||
{ | ||
options.Conventions.Add(new DynamicControllerFeatureProvider(option)); | ||
} | ||
}).AddControllersAsServices(); | ||
|
||
return builder; | ||
} | ||
|
||
private class DynamicControllerFeatureProvider(AppConfigOption option) : IApplicationModelConvention | ||
{ | ||
|
||
public void Apply(ApplicationModel application) | ||
{ | ||
foreach (var controller in application.Controllers) | ||
{ | ||
// 检查是否是ControllerBase的派生类 | ||
if (controller.ControllerType.IsAssignableTo(typeof(DynamicControllerBase))) | ||
{ | ||
// 检查是否已经有RouteAttribute定义 | ||
var hasRouteAttribute = controller.Selectors.Any(selector => | ||
selector.AttributeRouteModel != null); | ||
|
||
if (!hasRouteAttribute) | ||
{ | ||
var routeAttribute = new Microsoft.AspNetCore.Mvc.RouteAttribute( | ||
$"{option.DynamicPrefix}{(option.DynamicPrefix?.EndsWith('/') == false ? "/" : "")}[controller]"); | ||
var selectors = controller.Selectors.First(); | ||
var nullableContext = selectors.EndpointMetadata | ||
.FirstOrDefault(x => x is NullableContextAttribute); | ||
if (nullableContext != null) | ||
{ | ||
selectors.EndpointMetadata.Remove(nullableContext); | ||
} | ||
// 没有RouteAttribute,所以添加一个 | ||
|
||
selectors.AttributeRouteModel = new AttributeRouteModel(routeAttribute); | ||
|
||
} | ||
|
||
foreach (var action in controller.Actions) | ||
{ | ||
// 检查动作是否已经有HTTP方法特性(HttpGet, HttpPost, 等等) | ||
var hasHttpMethodAttribute = action.Selectors.Any(selector => | ||
selector.EndpointMetadata.OfType<HttpMethodAttribute>().Any()); | ||
|
||
// 如果没有HTTP方法特性,则添加一个默认的HttpGet特性 | ||
if (!hasHttpMethodAttribute) | ||
{ | ||
var selectors = action.Selectors.First(); | ||
var nullableContext = selectors.EndpointMetadata | ||
.FirstOrDefault(x => x is NullableContextAttribute); | ||
if (nullableContext != null) | ||
{ | ||
selectors.EndpointMetadata.Remove(nullableContext); | ||
} | ||
|
||
var prefix = option.GetPrefix.FirstOrDefault(x => action.ActionName.StartsWith(x)); | ||
if (prefix != null) | ||
{ | ||
if (option.AutoRemoveDynamicPrefix) | ||
{ | ||
action.ActionName = action.ActionName[prefix.Length..]; | ||
} | ||
|
||
selectors.AttributeRouteModel = | ||
new AttributeRouteModel(new Microsoft.AspNetCore.Mvc.RouteAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpGetAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpMethodMetadata(["GET"])); | ||
|
||
selectors.ActionConstraints.Add(new HttpMethodActionConstraint(["GET"])); | ||
continue; | ||
} | ||
|
||
prefix = option.PutPrefix.FirstOrDefault(x => action.ActionName.StartsWith(x)); | ||
if (prefix != null) | ||
{ | ||
if (option.AutoRemoveDynamicPrefix) | ||
{ | ||
action.ActionName = action.ActionName[prefix.Length..]; | ||
} | ||
|
||
selectors.AttributeRouteModel = | ||
new AttributeRouteModel(new Microsoft.AspNetCore.Mvc.RouteAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpPutAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpMethodMetadata(["PUT"])); | ||
|
||
selectors.ActionConstraints.Add(new HttpMethodActionConstraint(["PUT"])); | ||
continue; | ||
} | ||
|
||
prefix = option.DeletePrefix.FirstOrDefault(x => action.ActionName.StartsWith(x)); | ||
if (prefix != null) | ||
{ | ||
if (option.AutoRemoveDynamicPrefix) | ||
{ | ||
action.ActionName = action.ActionName[prefix.Length..]; | ||
} | ||
|
||
selectors.AttributeRouteModel = | ||
new AttributeRouteModel(new Microsoft.AspNetCore.Mvc.RouteAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpDeleteAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpMethodMetadata(["DELETE"])); | ||
|
||
selectors.ActionConstraints.Add(new HttpMethodActionConstraint(["DELETE"])); | ||
continue; | ||
} | ||
|
||
prefix = option.PostPrefix.FirstOrDefault(x => action.ActionName.StartsWith(x)); | ||
if (option.AutoRemoveDynamicPrefix && prefix != null) | ||
{ | ||
action.ActionName = action.ActionName[prefix.Length..]; | ||
} | ||
|
||
selectors.AttributeRouteModel = | ||
new AttributeRouteModel(new Microsoft.AspNetCore.Mvc.RouteAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpPostAttribute("[action]")); | ||
selectors.EndpointMetadata.Add(new HttpMethodMetadata(["POST"])); | ||
|
||
selectors.ActionConstraints.Add(new HttpMethodActionConstraint(["POST"])); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.