Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev update version 0.0.24 #54

Merged
merged 8 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions Sharkable.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sharkable.Sample", "src\Sha
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sharkable.AotSample", "src\Sharkable.AotSample\Sharkable.AotSample.csproj", "{DC065E0E-EE8A-4686-88FC-A765ED61992F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{24376B7D-8162-4BB6-9283-6EA550141155}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharkable.NativeTest", "src\Sharkable.NativeTest\Sharkable.NativeTest.csproj", "{DF89E5C3-2577-4903-BCC4-8BAC7D498855}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -29,6 +36,10 @@ Global
{DC065E0E-EE8A-4686-88FC-A765ED61992F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC065E0E-EE8A-4686-88FC-A765ED61992F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC065E0E-EE8A-4686-88FC-A765ED61992F}.Release|Any CPU.Build.0 = Release|Any CPU
{DF89E5C3-2577-4903-BCC4-8BAC7D498855}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF89E5C3-2577-4903-BCC4-8BAC7D498855}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF89E5C3-2577-4903-BCC4-8BAC7D498855}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF89E5C3-2577-4903-BCC4-8BAC7D498855}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -37,6 +48,7 @@ Global
{BE7F819E-A863-4035-8BA8-3F2013123EAB} = {E048E613-D35B-4F9F-A634-CC07D2265518}
{4143F0A0-A3CE-4057-A2F4-4BB871F68FB4} = {E048E613-D35B-4F9F-A634-CC07D2265518}
{DC065E0E-EE8A-4686-88FC-A765ED61992F} = {E048E613-D35B-4F9F-A634-CC07D2265518}
{DF89E5C3-2577-4903-BCC4-8BAC7D498855} = {E048E613-D35B-4F9F-A634-CC07D2265518}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {20F9D998-C896-4902-84C0-E54A8E4BA915}
Expand Down
1 change: 0 additions & 1 deletion src/Sharkable.AotSample/TestEndpoint.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("/lover", () =>
{

return TypedResults.Ok("lover");
})
.WithName("GetLover")
Expand Down
23 changes: 23 additions & 0 deletions src/Sharkable.NativeTest/AttrTestEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.AspNetCore.Mvc;

namespace Sharkable.NativeTest;

[SharkEndpoint]
public class AttrTestEndpoint(ILogger<AttrTestEndpoint> logger)
{
[SharkMethod("test/{age}")]
public async Task<Todo[]?> Lobster([FromQuery]string? name,
string? age,
[FromHeader]string? lover,
[FromBody]Todo[]? todo)
{
await Task.Delay(100);
logger.LogInformation("{a}.{b},{c}",name,age?.ToString(),lover);
return todo;
}
public async void LetGo()
{
await Task.Delay(3000);
logger.LogInformation("Let Go");
}
}
56 changes: 56 additions & 0 deletions src/Sharkable.NativeTest/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System.Text.Json.Serialization;
using Sharkable;

var builder = WebApplication.CreateSlimBuilder(args);


builder.Services.AddShark(opt =>
{
opt.Format = EndpointFormat.Tolower;
});
builder.Services.ConfigureHttpJsonOptions(options =>
{
options.SerializerOptions.TypeInfoResolverChain.Insert(1, AppJsonSerializerContext.Default);
options.SerializerOptions.TypeInfoResolverChain.Insert(2, AppJsonSerializerContext2.Default);
options.SerializerOptions.TypeInfoResolverChain.Insert(3, MyUnifiedResultContext.Default);
});
var app = builder.Build();
app.UseShark();
var sampleTodos = new Todo[]
{
new(1, "Walk the dog"),
new(2, "Do the dishes", DateOnly.FromDateTime(DateTime.Now)),
new(3, "Do the laundry", DateOnly.FromDateTime(DateTime.Now.AddDays(1))),
new(4, "Clean the bathroom"),
new(5, "Clean the car", DateOnly.FromDateTime(DateTime.Now.AddDays(2)))
};

var todosApi = app.MapGroup("/todos");
todosApi.MapGet("/", () => sampleTodos);
todosApi.MapGet("/{id}", (int id) =>
sampleTodos.FirstOrDefault(a => a.Id == id) is { } todo
? Results.Ok(todo)
: Results.NotFound());

app.Run();


public record Todo(int Id, string? Title, DateOnly? DueBy = null, bool IsComplete = false);

[JsonSerializable(typeof(Todo[]))]
[JsonSerializable(typeof(Task<Todo[]>))]
[JsonSerializable(typeof(string))]
internal partial class AppJsonSerializerContext : JsonSerializerContext
{
}
[JsonSerializable(typeof(Todo))]
internal partial class AppJsonSerializerContext2 : JsonSerializerContext
{
}

[JsonSerializable(typeof(UnifiedResult<Todo[]>))]
[JsonSerializable(typeof(UnifiedResult<Todo>))]
public partial class MyUnifiedResultContext : JsonSerializerContext
{

}
15 changes: 15 additions & 0 deletions src/Sharkable.NativeTest/Properties/launchSettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5245",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
25 changes: 25 additions & 0 deletions src/Sharkable.NativeTest/Sharkable.NativeTest.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Sharkable\Sharkable.csproj" />
</ItemGroup>
<ItemGroup>
<RdXmlFile Include="rd.xml" />
</ItemGroup>
<ItemGroup>
<None Remove="rd.xml" />
</ItemGroup>

<ItemGroup>
<Content Include="rd.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
</Project>
11 changes: 11 additions & 0 deletions src/Sharkable.NativeTest/Sharkable.NativeTest.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@Sharkable.NativeTest_HostAddress = http://localhost:5245

GET {{Sharkable.NativeTest_HostAddress}}/todos/
Accept: application/json

###

GET {{Sharkable.NativeTest_HostAddress}}/todos/1
Accept: application/json

###
12 changes: 12 additions & 0 deletions src/Sharkable.NativeTest/TestEndpoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;

namespace Sharkable.NativeTest;

public class TestEndpoint : ISharkEndpoint
{
public void AddRoutes(IEndpointRouteBuilder app)
{
app.MapGet("lost", () => Results.Ok("lost and found"));
app.MapPost("lost", ([FromBody]Todo[] todos) => Results.Ok((object?)todos));
}
}
8 changes: 8 additions & 0 deletions src/Sharkable.NativeTest/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
9 changes: 9 additions & 0 deletions src/Sharkable.NativeTest/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
7 changes: 7 additions & 0 deletions src/Sharkable.NativeTest/rd.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8" ?>
<Directives>
<Application>
<Assembly Name="Sharkable.NativeTest" Dynamic="Required All">
</Assembly>
</Application>
</Directives>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

namespace Sharkable;

internal static class DependencyInjectionExtension
{
internal static void AddDIFactory(this IServiceCollection services)
{
services.AddSingleton<IDependencyReflectorFactory, DependencyReflectorFactory>();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
using Microsoft.Extensions.Logging;

namespace Sharkable;

/// <summary>
/// A factory that can create objects with DI
/// </summary>
public class DependencyReflectorFactory : IDependencyReflectorFactory
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<DependencyReflectorFactory> _logger;

/// <summary>
///
/// </summary>
/// <param name="serviceProvider"></param>
/// <param name="logger"></param>
public DependencyReflectorFactory(IServiceProvider serviceProvider, ILogger<DependencyReflectorFactory> logger)
{
_serviceProvider = serviceProvider;
_logger = logger;
}

/// <summary>
/// get constructor for dependency injection
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
/// <exception cref="InvalidOperationException"></exception>
public object?[] GetConstructorParameters(Type type)
{
var constructor = type.GetConstructors().FirstOrDefault();
if (constructor == null)
{
_logger.LogDebug("No constructor found for {type}", type);
throw new InvalidOperationException("No constructor found for type" + type);
}
var parameters = constructor.GetParameters()
.Select(p=>_serviceProvider.GetService(p.ParameterType))
.ToArray();
return parameters;
}

public object CreateInstance(Type type)
{
var p = GetConstructorParameters(type);
return Activator.CreateInstance(type, p) ?? throw new InvalidOperationException($"No constructor found for {type}");
}
public T GetReflectedType<T>(Type typeToReflect, object[]? constructorRequiredParamerters)
where T : class
{
var propertyTypeAssemblyQualifiedName = typeToReflect?.AssemblyQualifiedName;
var constructors = typeToReflect?.GetConstructors();
if (constructors?.Length == 0)
{
LogConstructorError(typeToReflect, constructorRequiredParamerters);
return null!;
}
var parameters = GetConstructor(constructors, constructorRequiredParamerters)?.GetParameters();
if (parameters == null)
{
LogConstructorError(typeToReflect, constructorRequiredParamerters);
return null!;
}
object?[]? injectedParamerters = null;
if (constructorRequiredParamerters == null)
{
injectedParamerters = parameters?.Select(parameter => _serviceProvider.GetService(parameter.ParameterType)).ToArray();
}
else
{
injectedParamerters = constructorRequiredParamerters
.Concat(parameters.Skip(constructorRequiredParamerters.Length).Select(parameter => _serviceProvider.GetService(parameter.ParameterType)))
.ToArray();
}
if (propertyTypeAssemblyQualifiedName == null)
return null!;

return (T)Activator.CreateInstance(Type.GetType(propertyTypeAssemblyQualifiedName)!, injectedParamerters)!;
}

/// <summary>
/// Logs a constructor error
/// </summary>
/// <param name="typeToReflect"></param>
/// <param name="constructorRequiredParamerters"></param>
private void LogConstructorError(Type? typeToReflect, object[]? constructorRequiredParamerters)
{
var constructorNames = string.Join(", ", constructorRequiredParamerters?.Select(item => item?.GetType()?.Name) ?? Array.Empty<string?>());
var message = $"Unable to create instance of {typeToReflect?.Name}. " +
$"Could not find a constructor with {constructorNames} as first argument(s)";
_logger.LogError(message);
}

/// <summary>
/// Takes the required paramters from a constructor
/// </summary>
/// <param name="constructor"></param>
/// <param name="constructorRequiredParamertersLength"></param>
/// <returns></returns>
private ParameterInfo[]? TakeConstructorRequiredParamters(ConstructorInfo constructor, int constructorRequiredParamertersLength)
{
var parameters = constructor.GetParameters();
return parameters.Length < constructorRequiredParamertersLength ? parameters : parameters?.Take(constructorRequiredParamertersLength).ToArray();
}

/// <summary>
/// Validates the required parameters from a constructor
/// </summary>
/// <param name="constructor"></param>
/// <param name="constructorRequiredParameters"></param>
/// <returns></returns>
private bool ValidateConstructorRequiredParameters(ConstructorInfo constructor, object[]? constructorRequiredParameters)
{
if (constructorRequiredParameters == null)
{
return true;
}
var parameters = TakeConstructorRequiredParamters(constructor, constructorRequiredParameters.Length);
for (int i = 0; i < parameters?.Length; i++)
{
var requiredParameter = constructorRequiredParameters[i].GetType();
if (parameters[i].ParameterType != requiredParameter)
{
return false;
}
}
return true;
}

/// <summary>
/// Gets a constructor
/// </summary>
/// <param name="constructors"></param>
/// <param name="constructorRequiredParameters"></param>
/// <returns></returns>
private ConstructorInfo? GetConstructor(ConstructorInfo[]? constructors, object[]? constructorRequiredParameters)
{
return constructors?.FirstOrDefault(constructor =>
ValidateConstructorRequiredParameters(constructor, constructorRequiredParameters));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

namespace Sharkable;

/// <summary>
/// A factory that can create objects with DI
/// </summary>
public interface IDependencyReflectorFactory
{
/// <summary>
/// Gets the reflected type with DI
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="typeToReflect">The type to create</param>
/// <param name="constructorRequiredParamerters">The required parameters on the constructor</param>
/// <returns></returns>
T GetReflectedType<T>(Type typeToReflect, object[]? constructorRequiredParamerters) where T : class;
object? CreateInstance(Type type);
object?[]? GetConstructorParameters(Type type);
}
Loading