C#
C#

help

Root Question Message

El Grande Padre
El Grande Padre1/16/2023
Not able to locate web api controllers in a class library

Hello,

I'm having some issues with trying to load web api controllers from a class library. I did try explicitly adding the assembly with AddControllers().AddApplicationPart, but no luck there. I'm thinking it has to do with the pattern I'm using for registering services in separate assemblies.
El Grande Padre
El Grande Padre1/16/2023
This is what my main project startup looks like:
namespace Core
{
    public class Startup
    {
        private readonly IConfiguration _config;

        public Startup(IConfiguration config)
        {
            _config = config;
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApiServices(_config);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app)
        {
            app.ConfigureApi(_config);
        }
    }
}
El Grande Padre
El Grande Padre1/16/2023
This is the extension pattern I'm using to piggy back off the startup of the main project inside of the class library
namespace Api.Extensions
{
    public static class ApiStartupExt
    {
        public static void AddApiServices(this IServiceCollection builder, IConfiguration config)
        {
        builder.AddControllers().AddApplicationPart(typeof(ApiStartupExt).Assembly);
            builder.AddSwaggerGen(c => c.SwaggerDoc("v0", new OpenApiInfo
            {
                Title = "test_service",
                Version = "v0"
            }));
        }
        public static void ConfigureApi(this IApplicationBuilder app, IConfiguration config)
        {
            if (!config["Environment"]!.Equals("Production"))
            {
                app.UseSwagger();
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/v1/swagger.json", "test_service v0");
                    c.RoutePrefix = string.Empty;
                });
            }

            // Map rest services to port 43000
            // In my actual application I also have GRPC endpoints on the same host
            // so I need to use the UseWhen method to avoid some issues there
            app.UseWhen(context => context.Connection.LocalPort == config.GetValue<int>("Rest:Port"),
              builder =>
              {
                  builder.UsePathBase(new PathString("/api"));
                  builder.UseRouting();
                  builder.UseEndpoints(endpoints => endpoints.MapControllers());
              }
            );
        }
    }
}
El Grande Padre
El Grande Padre1/16/2023
Here's the output I get when making a request:
info: Microsoft.AspNetCore.Hosting.Diagnostics[1]
      Request starting HTTP/1.1 POST http://localhost:43000/api/WeatherForecast - 0
dbug: Microsoft.AspNetCore.HostFiltering.HostFilteringMiddleware[0]
      Wildcard detected, all requests with hosts will be allowed.
dbug: Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware[1]
      POST requests are not supported
dbug: Microsoft.AspNetCore.Server.Kestrel.Connections[9]
      Connection id "0HMNNSN1PNNGU" completed keep alive response.
info: Microsoft.AspNetCore.Hosting.Diagnostics[2]
      Request finished HTTP/1.1 POST http://localhost:43000/api/WeatherForecast - 0 - 404 0 - 11.6784ms
El Grande Padre
El Grande Padre1/16/2023
tebeco
tebeco1/16/2023
if (!config["Environment"]!.Equals("Production"))
tebeco
tebeco1/16/2023
if(env.IsProduction()) and variation like !env.IsProduction() or IsDevelopment()
tebeco
tebeco1/16/2023
but never a double magic string array inside with ["foo"]!. operator
tebeco
tebeco1/16/2023
IIRC the dotnet new webapi have a boiler plate with a clean if as an example
tebeco
tebeco1/16/2023
TLDR:
if you open a term and dotnet new webapi -n PleaseDeleteMeLater
you'll have an example to re-use and delete later
El Grande Padre
El Grande Padre1/16/2023
I understand the issues with magic string constants, but I don't think thats relevant to the question. The repo this issue is actually happening uses options configs. I just didn't want to copy over all the configuration
tebeco
tebeco1/16/2023
it's not related
tebeco
tebeco1/16/2023
it's a huge code smell
El Grande Padre
El Grande Padre1/16/2023
unless im completely misunderstanding and thats preventing controllers from being discovered
tebeco
tebeco1/16/2023
like a very very huge one
tebeco
tebeco1/16/2023
i'm reading through your code to see what could cause the 404
tebeco
tebeco1/16/2023
and that catch me so bad that I ping you there one that
tebeco
tebeco1/16/2023
as ... default code is clean / worked, replaced by something else that have several flaw
tebeco
tebeco1/16/2023
your code does not show where your controller is
tebeco
tebeco1/16/2023
you're adding ApiStartupExt as an ApplicationPart
tebeco
tebeco1/16/2023
but nothing about WeatherForecastController
tebeco
tebeco1/16/2023
which MIGHT OR NOT be in the same assembly
tebeco
tebeco1/16/2023
impossible to tell
El Grande Padre
El Grande Padre1/16/2023
thats why i included the repo because i realized it was too much for just copy and pasting files
tebeco
tebeco1/16/2023
good point
El Grande Padre
El Grande Padre1/16/2023
its in the same assembly as the extention
tebeco
tebeco1/16/2023
did you tried with a typeof(...).Assembly ?
El Grande Padre
El Grande Padre1/16/2023
No i did not. what does ... do?
tebeco
tebeco1/16/2023
me being lazy to type the controller name
El Grande Padre
El Grande Padre1/16/2023
oh then yes I did specify the controller class
El Grande Padre
El Grande Padre1/16/2023
same result and same assembly
tebeco
tebeco1/16/2023
<PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.9" /> is that normal ?
tebeco
tebeco1/16/2023
tebeco
tebeco1/16/2023
was restored using '.NETFramework,Version=v4.6.1
tebeco
tebeco1/16/2023
oof
tebeco
tebeco1/16/2023
you're missing a FrameworkReference
tebeco
tebeco1/16/2023
that's probably why you get both that shit load of warning
tebeco
tebeco1/16/2023
which turns into error
tebeco
tebeco1/16/2023
and probably break the thing
tebeco
tebeco1/16/2023
and also why app part is broken
El Grande Padre
El Grande Padre1/16/2023
i think i accidentally added that when adding <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
tebeco
tebeco1/16/2023
most of the thing with .Mvc in package name / code needs to be checked
tebeco
tebeco1/16/2023
a chunk of it got depracated in 3.0
tebeco
tebeco1/16/2023
   <ItemGroup>
-    <PackageReference Include="Microsoft.AspNet.Mvc" Version="5.2.9" />
+    <FrameworkReference Include="Microsoft.AspNetCore.App" />
   </ItemGroup>
tebeco
tebeco1/16/2023
in your lib
tebeco
tebeco1/16/2023
as a hint
tebeco
tebeco1/16/2023
you should stop leaking IConfiguration
tebeco
tebeco1/16/2023
especially like it's done in AddApiServices and ConfigureApi
tebeco
tebeco1/16/2023
your ConfigureApi is basically POST DI container build
tebeco
tebeco1/16/2023
meaning all the config is fully built
tebeco
tebeco1/16/2023
and so are the IOptions
ContactFrequently Asked QuestionsJoin The DiscordBugs & Feature RequestsTerms & Privacy