Skip to content

Commit

Permalink
Add a sample for loading ASP.NET MVC controllers from plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
natemcmaster committed Oct 23, 2018
1 parent 8f5c28f commit abf20cd
Show file tree
Hide file tree
Showing 11 changed files with 228 additions and 0 deletions.
12 changes: 12 additions & 0 deletions samples/aspnetcore-mvc/MvcApp/Controllers/HomeController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Mvc;

namespace MvcWebApp.Controllers
{
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
24 changes: 24 additions & 0 deletions samples/aspnetcore-mvc/MvcApp/MvcApp.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" />

<!--
Required for the samples in this repo only.
Normally, you should replace this with a PackageReference to McMaster.NETCore.Plugins.
-->
<ProjectReference Include="$(RepoRoot)src\Plugins\McMaster.NETCore.Plugins.csproj" />
</ItemGroup>

<Target Name="BuildPlugin" AfterTargets="Build">
<MSBuild Projects="..\MvcAppPlugin1\MvcAppPlugin1.csproj"
Targets="Publish"
Properties="Configuration=$(Configuration);PublishDir=$(OutputPath)/plugins/MvcAppPlugin1/" />
</Target>

</Project>
24 changes: 24 additions & 0 deletions samples/aspnetcore-mvc/MvcApp/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;

namespace MvcWebApp
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}
60 changes: 60 additions & 0 deletions samples/aspnetcore-mvc/MvcApp/Startup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using McMaster.NETCore.Plugins;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace MvcWebApp
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
var mvcBuilder = services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

foreach (var dir in Directory.GetDirectories(Path.Combine(AppContext.BaseDirectory, "plugins")))
{
var pluginName = Path.GetFileName(dir);
var plugin = PluginLoader.CreateFromAssemblyFile(Path.Combine(dir, pluginName + ".dll"));
var pluginAssembly = plugin.LoadDefaultAssembly();
Console.WriteLine($"Loading application parts from plugin {pluginName}");

// This loads MVC application parts from plugin assemblies
var partFactory = ApplicationPartFactory.GetApplicationPartFactory(pluginAssembly);
foreach (var part in partFactory.GetApplicationParts(pluginAssembly))
{
Console.WriteLine($"* {part.Name}");
mvcBuilder.PartManager.ApplicationParts.Add(part);
}

// This piece finds and loads related parts, such as MvcAppPlugin1.Views.dll.
var relatedAssemblies = RelatedAssemblyAttribute.GetRelatedAssemblies(pluginAssembly, throwOnError: true);
foreach (var assembly in relatedAssemblies)
{
partFactory = ApplicationPartFactory.GetApplicationPartFactory(assembly);
foreach (var part in partFactory.GetApplicationParts(assembly))
{
Console.WriteLine($" * {part.Name}");
mvcBuilder.PartManager.ApplicationParts.Add(part);
}
}
}
}

public void Configure(IApplicationBuilder app)
{
app.UseMvcWithDefaultRoute();
}
}
}
9 changes: 9 additions & 0 deletions samples/aspnetcore-mvc/MvcApp/Views/Home/Index.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@{
ViewData["Title"] = "Home Page";
}

<p>Hello from the web app.</p>

<ul>
<li><a href="/myplugin">/myplugin</a></li>
</ul>
2 changes: 2 additions & 0 deletions samples/aspnetcore-mvc/MvcApp/Views/_ViewImports.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
@using MvcWebApp
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
12 changes: 12 additions & 0 deletions samples/aspnetcore-mvc/MvcAppPlugin1/MvcAppPlugin1.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Razor">

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="2.1.0" Publish="false" />
<PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" Publish="false" />
</ItemGroup>

</Project>
9 changes: 9 additions & 0 deletions samples/aspnetcore-mvc/MvcAppPlugin1/MyPluginController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Microsoft.AspNetCore.Mvc;

namespace MvcAppPlugin1
{
public class MyPluginController : Controller
{
public IActionResult Index() => View();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@{
ViewData["Title"] = "Plugin1";
}

<p>Hello world from Plugin1!</p>
23 changes: 23 additions & 0 deletions samples/aspnetcore-mvc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
ASP.NET Core MVC Sample
=======================

This sample contains 2 projects which demonstrate a simple plugin scenario.

1. 'MvcWebApp' is an ASP.NET Core application which scans for a 'plugins' folder in its base directory and attempts to load any plugins it finds
2. 'MvcAppPlugin1' which implements MVC controllers.

Normally, an ASP.NET Core MVC application must have a direct dependency on any assemblies
which provide controllers. However, as this sample demonstrates, an MVC application
can load controllers from a list of assemblies which is not known ahead of time when the
host app is built.

## Running the sample

Open a command line to this folder and run:

```
dotnet restore
dotnet run -p MvcApp/
```

Then open <http://localhost:5000>
48 changes: 48 additions & 0 deletions samples/aspnetcore-mvc/aspnetcore-mvc.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
MinimumVisualStudioVersion = 15.0.26124.0
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcApp", "MvcApp\MvcApp.csproj", "{4F363469-7783-4A40-B1B5-455187AF1C76}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MvcAppPlugin1", "MvcAppPlugin1\MvcAppPlugin1.csproj", "{B6316996-A470-470F-9CF1-475096A0510A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4F363469-7783-4A40-B1B5-455187AF1C76}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Debug|x64.ActiveCfg = Debug|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Debug|x64.Build.0 = Debug|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Debug|x86.ActiveCfg = Debug|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Debug|x86.Build.0 = Debug|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Release|Any CPU.Build.0 = Release|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Release|x64.ActiveCfg = Release|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Release|x64.Build.0 = Release|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Release|x86.ActiveCfg = Release|Any CPU
{4F363469-7783-4A40-B1B5-455187AF1C76}.Release|x86.Build.0 = Release|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Debug|x64.ActiveCfg = Debug|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Debug|x64.Build.0 = Debug|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Debug|x86.ActiveCfg = Debug|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Debug|x86.Build.0 = Debug|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Release|Any CPU.Build.0 = Release|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Release|x64.ActiveCfg = Release|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Release|x64.Build.0 = Release|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Release|x86.ActiveCfg = Release|Any CPU
{B6316996-A470-470F-9CF1-475096A0510A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

0 comments on commit abf20cd

Please sign in to comment.