For the sake of modularity, I have created some controllers in different assemblies. Each assembly represents a bounded context (a module, a sub-system, a division, etc.) of
There is nothing wrong with the above answers, I just use a 1 liners as I know the class that is included in the external assembly that I'd like to load.
The bellow sample comes from the ASP-WAF firewall and is used to load reporting endpoints and dashboard web pages in an existing web application in .net Core 3.1.
services.AddMvc(options =>
{
options.Filters.Add<Walter.Web.FireWall.Filters.FireWallFilter>();
options.Filters.Add<Walter.Web.FireWall.Filters.PrivacyPreferencesFilter>();
}).AddApplicationPart(Assembly.GetAssembly(typeof(Walter.Web.FireWall.DefaultEndpoints.ReportingController)));
so to answer your question, let's assume that the TeacherController is in namespace Contoso.School.UserService your implementation would be:
services.AddMvc(options =>
{
//any option }).AddApplicationPart(Assembly.GetAssembly(typeof(Contoso.School.UserService.TeacherController )));
or, if you do not have any options then just ignore them and use this:
services.AddMvc() .AddApplicationPart(Assembly.GetAssembly(typeof(Contoso.School.UserService.TeacherController)));
If you are not sure about the class in the assembly then us intelisence in your code starting with the namespace and look for a type to use or open object browser in visual studio
Let me know if you have any issues.
Martin above has the answer, thanks. However it is not immediately obvious how you pass an assembly to Startup.ConfigureServices. How I achieved this was... in the code where I create and start the webHost I call IWebHostBuilder.ConfigureServices and give it something containing the assembly (in my case a custom interface called IOutputProcess)
_webHost = CreateWebHostBuilder().ConfigureServices(e => e.AddSingleton(_outputProcess)).Build();
_webHost.Start();
then in my Startup.ConfigureServices I pull that instance back out of the IServiceCollection with...
public void ConfigureServices(IServiceCollection services)
{
var sp = services.BuildServiceProvider();
var outputProcess = sp.GetService<IOutputProcess>();
services.AddMvc().AddApplicationPart(outputProcess.ControllerAssembly).AddControllersAsServices();
}
I doubt instantiating a service provider purely for this purpose is the cleanest way to do things, but it does work. (I'm open to better ideas)
I'm trying to resolve the controllers while migrating legacy unit tests from .NET Framework to aspnet core 3.1, this is the only way I got it working:
var startupAssembly = typeof(Startup).Assembly;
var services = new ServiceCollection();
// Add services
...
// Add Controllers
services
.AddControllers()
.AddApplicationPart(startupAssembly)
.AddControllersAsServices();
If I change the order of the three last lines it does not work.
Avoid doing this for unit testing unless you really have to, i.e. for legacy reasons. If you are not working with legacy code you are probably looking for integration tests.
For .NET Core 3.0 the API has been slightly changed and the easiest way to register controllers from external assembly in Startup.cs
looks like:
public void ConfigureServices(IServiceCollection services)
{
var assembly = typeof(**AnyTypeFromRequiredAssembly**).Assembly;
services.AddControllers()
.PartManager.ApplicationParts.Add(new AssemblyPart(assembly));
}
Inside the ConfigureServices
method of the Startup
class you have to call the following:
services.AddMvc().AddApplicationPart(assembly).AddControllersAsServices();
Where assembly
is the instance Assembly
representing Contoso.School.UserService.dll
.
You can load it either getting it from any included type or like this:
var assembly = Assembly.Load("Contoso.School.UserService");