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

The type initializer for 'FastEndpoints.RequestBinder`1' threw an exception. #436

Closed
Miatrix opened this issue Apr 21, 2023 · 3 comments
Closed
Labels
enhancement New feature or request implemented requested feature has been implemented

Comments

@Miatrix
Copy link

Miatrix commented Apr 21, 2023

I have FastEndpoints working for requests with 1 item, however I'm trying to add an endpoint that will accept a list of items to add/update. Any idea what I'm doing wrong?

Request:

[
    {
        "setting": "TestSetting1234",
        "value": "TestValue9876"
    },
    {
        "setting": "TestSetting2345",
        "value": "TestValue98761"
    }
]

Endpoint code

public class MyEndpoint : Endpoint<MyEndpointCommand>
{
    public override void Configure()
    {
        Post("/settings/all2");
        Roles("Admin");
    }

    public override async Task HandleAsync(MyEndpointCommand req, CancellationToken ct)
    {
        var response = new List<Site>()
        {
            new() {Id = 1, Setting = "1234", UpdatedDate = DateTime.Now, Value = "abc"},
            new() {Id = 2, Setting = "2345", UpdatedDate = DateTime.Now, Value = "abcd"},
        };

        await SendAsync(response, 200, ct);
    }
}

public sealed class MyEndpointCommand : List<Site>
{
}

Error Message:

HTTP: POST /api/v1/settings/all2
TYPE: TypeInitializationException
REASON: The type initializer for 'FastEndpoints.RequestBinder`1' threw an exception.
---------------------------------
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
   at System.Reflection.ConstructorInvoker.Invoke(Object obj, IntPtr* args, BindingFlags invokeAttr)
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitConstructor(ConstructorCallSite constructorCallSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitRootCache(ServiceCallSite callSite, RuntimeResolverContext context)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSite(ServiceCallSite callSite, TArgument argument)
   at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.CreateServiceAccessor(Type serviceType)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
   at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
   at FastEndpoints.ServiceResolver.Resolve(Type typeOfService)
   at FastEndpoints.Endpoint`2.BindRequestAsync(EndpointDefinition def, HttpContext ctx, List`1 failures, CancellationToken ct)
   at FastEndpoints.Endpoint`2.ExecAsync(CancellationToken ct)
   at FastEndpoints.Endpoint`2.ExecAsync(CancellationToken ct)
   at NSwag.AspNetCore.Middlewares.SwaggerUiIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.RedirectToIndexMiddleware.Invoke(HttpContext context)
   at NSwag.AspNetCore.Middlewares.OpenApiDocumentMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddlewareImpl.<Invoke>g__Awaited|8_0(ExceptionHandlerMiddlewareImpl middleware, HttpContext context, Task task)
[04-21 08:12:49 ERR 127.0.0.1 PostmanRuntime/7.31.3] HTTP POST /api/v1/settings/all2 responded 500 in 17.2545 ms
@dj-nitehawk
Copy link
Member

just make List<Site> the TRequest of the endpoint like so:

public class MyEndpoint : Endpoint<List<Site>>
{
    public override async Task HandleAsync(List<Site> req, CancellationToken ct)
    {

    }
}

@dj-nitehawk dj-nitehawk added the question Further information is requested label Apr 21, 2023
@Miatrix
Copy link
Author

Miatrix commented Apr 21, 2023

List works but creating a class that inherits from List does not work.

This Works:

public class MyEndpoint : Endpoint<MyEndpointCommand>
{
    public override void Configure()
    {
        Post("/settings/all2");
        Roles("Admin");
    }

    public override async Task HandleAsync(MyEndpointCommand req, CancellationToken ct)
    {
        var response = new List<Site>()
        {
            new() {Id = 1, Setting = "1234", UpdatedDate = DateTime.Now, Value = "abc"},
            new() {Id = 2, Setting = "2345", UpdatedDate = DateTime.Now, Value = "abcd"},
        };

        await SendAsync(response, 200, ct);
    }
}

public sealed class MyEndpointCommand 
{
    public List<Site> Data { get; set; }
    public uint RequestUserId { get; set; }
    public bool RequestIsAdmin { get; set; }
    public string RequestUserName { get; set; }
}

Changing MyEndpointCommand to

public sealed class MyEndpointCommand : List<Site>
{
    public uint RequestUserId { get; set; }
    public bool RequestIsAdmin { get; set; }
    public string RequestUserName { get; set; } 
}

Does not work. However this also will work (Not with the list but with just 1):

public sealed class MyEndpointCommand : Site
{
    public uint RequestUserId { get; set; }
    public bool RequestIsAdmin { get; set; }
    public string RequestUserName { get; set; } 
}

I can add the Data but it seams like inheriting from List should work

@dj-nitehawk
Copy link
Member

added support for inherited IEnumerable<T> request DTO binding from a json array request body in 5.8.1.15-beta.
this is now supported:

public sealed class MyEndpointCommand : List<Site> { }

however this is not:

public sealed class MyEndpointCommand : List<Site>
{
    public uint RequestUserId { get; set; }
    public bool RequestIsAdmin { get; set; }
    public string RequestUserName { get; set; } 
}

this essentially makes it bindable as a json object and not a json array and the inheritance of List<Site> goes out the door from the perspective of binding a json array. it is also not supported by minimal endpoints, swagger nor STJ.

i.e. this cannot be done with app.MapPost("/", (MyEndpointCommand r) => Results.Ok(r)); either.

@dj-nitehawk dj-nitehawk added enhancement New feature or request implemented requested feature has been implemented and removed question Further information is requested labels Apr 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request implemented requested feature has been implemented
Development

No branches or pull requests

2 participants