elsa-workflows / elsa-core

A .NET workflows library
https://v3.elsaworkflows.io/
MIT License
6.5k stars 1.2k forks source link

Elsa API is hiding my endpoints in swagger #4790

Open hsnsalhi opened 10 months ago

hsnsalhi commented 10 months ago

Hello, It seems like Elsa is hiding my own endpoints: I created a simple Minimal API with .Net8. I integrated Elsa 3 API with my own endpoints. Here is my code:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    builder.Services.SwaggerDocument(o =>
    {
        o.DocumentSettings = s =>
        {
            s.DocumentName = "My API";
            s.Title = "My API";
            s.Version = "v1";
        };
    });

    builder.Services.AddElsa(elsa =>
    {
        elsa.UseWorkflowsApi();
        elsa.AddSwagger();
    });

    var app = builder.Build();

    app.UseWorkflowsApi();
    app.UseSwaggerUI();

    app.Run();
}

I use FastEndpoints to create my own endpoints

public class FastEndpointsV1 : Endpoint<MyRequest, MyResponse>
{
    public override void Configure()
    {
        Get("orch/aaa");
        AllowAnonymous();
        Version(1);
    }

    public override async Task HandleAsync(MyRequest req, CancellationToken ct)
    {
        await SendAsync(new MyResponse
        {
            Name = Guid.NewGuid().ToString(),
        });
    }
}

My question is: Is this possible ? My second question: Is it possible to integrate Elsa endpoints without FastEndpoints ? just by using MinimalAPI's mapping ?

IsaacHayes1995 commented 10 months ago

Try change your config to this:


public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    builder.Services.SwaggerDocument(o =>
    {
        o.DocumentSettings = s =>
        {
            s.DocumentName = "My API";
            s.Title = "My API";
            s.Version = "v1";
        };
    });

    builder.Services.AddElsa(elsa =>
    {
            elsa.UseWorkflowsApi(x =>
            {
                var module = x.Module;
                module.AddFastEndpointsAssembly<Program>();
            });
        elsa.AddSwagger();
    });

    var app = builder.Build();

    app.UseWorkflowsApi();
    app.UseSwaggerUI();

    app.Run();
}
goodsxx commented 7 months ago

I am developing using FastEndpoints

I would like to add the following configuration:

app.UseFastEndpoints(c =>
{
    c.Endpoints.Configurator = ep =>
    {
        ep.PostProcessor<MyGlobalPreProcessor>(Order.Before);
    };
});

But there is already a default UseFastEndpoints() in UseWorkflowsApi

public static IApplicationBuilder UseWorkflowsApi(this IApplicationBuilder app, string routePrefix = "elsa/api")
{
    string routePrefix2 = routePrefix;
    return app.UseFastEndpoints(delegate (Config config)
    {
        config.Endpoints.RoutePrefix = routePrefix2;
        config.Serializer.RequestDeserializer = DeserializeRequestAsync;
        config.Serializer.ResponseSerializer = SerializeRequestAsync;
    });
}

What should I do to add a PostProcessor?

ax75974 commented 4 months ago

@goodsxx I use FastEndpoints too,Have you solved this problem yet?And the Swagger Error🥲

IsaacHayes1995 commented 4 months ago

@goodsxx I use FastEndpoints too,Have you solved this problem yet?And the Swagger Error🥲

Not the guy you're responding to, but I personally ended up separating out the "workflow server" to a seperate project/app to avoid conflicts.

If that's not an option I'd recommend digging into the code of the Elsa extension methods and simply reinplementing them with your required changes.

IsaacHayes1995 commented 4 months ago

@goodsxx I use FastEndpoints too,Have you solved this problem yet?And the Swagger Error🥲

If you can post a minimal repro I can post an example fix pr in the morning.

ax75974 commented 4 months ago

@goodsxx I use FastEndpoints too,Have you solved this problem yet?And the Swagger Error🥲

Not the guy you're responding to, but I personally ended up separating out the "workflow server" to a seperate project/app to avoid conflicts.

If that's not an option I'd recommend digging into the code of the Elsa extension methods and simply reinplementing them with your required changes.

@IsaacHayes1995 I agree with your opinion, Im a student,and this is my study course ,I will continue to delve deeper into relevant knowledge, but I still want to resolve conflicts as much as possible😁plz help me and give me some advice,thx🥺, about the error detail:

System.InvalidOperationException:“Unable to resolve service for type 'Elsa.Identity.Contracts.ISecretGenerator' while attempting to activate 'Elsa.Identity.Endpoints.Users.Create.Create'.”


        builder.Services.AddElsa(s =>
        {
            s.UseMongoDb(configuration.GetConnectionString("Mongodb"));
            s.UseWorkflowManagement(m => m.UseMongoDb());

            s.UseWorkflowsApi(x =>
            {
                var module = x.Module;
                module.AddFastEndpointsAssembly<Program>();
            });
            s.AddActivitiesFrom<Program>();
            s.AddWorkflowsFrom<Program>();
        });
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
app.UseResponseCaching();
app.UseFastEndpoints();
app.UseSwaggerGen();
}

The error appears on “UseFastEndpoints()”,Plz teach me how to solve it🥺thx

ax75974 commented 4 months ago

The error appears on “UseFastEndpoints()”,Plz teach me how to solve it🥺thx

@IsaacHayes1995 I saw this error while I use Package"Elsa.MongoDb",could u teach how to resolve it?And I cant see Elsa API in swagger ,How should I do?

goodsxx commented 4 months ago

在 Fast Endpoints 中集成 Elsa 3.0 时,可以修改以下配置,让 自定义 API 和 Elsa API 在 Swagger 中正确的展示:

builder.Services.AddElsa(elsa =>
{
    //  可根据自己项目情况修改
    elsa.UseWorkflowsApi(x =>
    {
        var module = x.Module;
        module.AddFastEndpointsAssembly<Program>();
    });
    elsa.Services.SwaggerDocument(delegate (DocumentOptions o)
    {
        o.EndpointFilter = ep =>
        {
            return ep.OverriddenRoutePrefix == null;
        };
        o.EnableJWTBearerAuth = true;
        o.DocumentSettings = delegate (AspNetCoreOpenApiDocumentGeneratorSettings s)
        {
            s.DocumentName = $"Elsa3.0 API";
            s.Title = "Elsa3.0 API";
            //s.Version = $"v3";
        };
        o.AutoTagPathSegmentIndex = 1;
    });
}

// app.UseWorkflowsApi() //注释这一行,使用下面的配置
app.UseFastEndpoints(c =>
{
    c.Endpoints.RoutePrefix = "api"
    c.Serializer.RequestDeserializer = DeserializeRequestAsync;
    c.Serializer.ResponseSerializer = SerializeRequestAsync;
});

// 以下代码来自 Elsa 源码
static ValueTask<object?> DeserializeRequestAsync(HttpRequest httpRequest, Type modelType, JsonSerializerContext? serializerContext, CancellationToken cancellationToken)
{
    JsonSerializerOptions options = httpRequest.HttpContext.RequestServices.GetRequiredService<IApiSerializer>().CreateOptions();
    if (serializerContext != null)
    {
        return JsonSerializer.DeserializeAsync(httpRequest.Body, modelType, serializerContext, cancellationToken);
    }

    return JsonSerializer.DeserializeAsync(httpRequest.Body, modelType, options, cancellationToken);
}

static Task SerializeRequestAsync(HttpResponse httpResponse, object? dto, string contentType, JsonSerializerContext? serializerContext, CancellationToken cancellationToken)
{
    JsonSerializerOptions options = httpResponse.HttpContext.RequestServices.GetRequiredService<IApiSerializer>().CreateOptions();
    httpResponse.ContentType = contentType;
    options.DefaultIgnoreCondition = JsonIgnoreCondition.Never;
    if (serializerContext != null)
    {
        return JsonSerializer.SerializeAsync(httpResponse.Body, dto, dto?.GetType() ?? typeof(object), serializerContext, cancellationToken);
    }

    return JsonSerializer.SerializeAsync(httpResponse.Body, dto, dto?.GetType() ?? typeof(object), options, cancellationToken);
}