Last active
July 19, 2018 15:07
-
-
Save tsvx/7fdc2c55282859f70c327d2a3dbf9f3e to your computer and use it in GitHub Desktop.
PoC of ASP.NET Core MVC App in LinqPAD
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Query Kind="Program"> | |
<NuGetReference>Microsoft.AspNetCore</NuGetReference> | |
<NuGetReference>Microsoft.AspNetCore.Hosting</NuGetReference> | |
<NuGetReference>Microsoft.AspNetCore.Mvc</NuGetReference> | |
<NuGetReference>Microsoft.AspNetCore.Routing</NuGetReference> | |
<NuGetReference>Microsoft.AspNetCore.StaticFiles</NuGetReference> | |
<NuGetReference>Swashbuckle.AspNetCore</NuGetReference> | |
<NuGetReference>Swashbuckle.AspNetCore.SwaggerGen</NuGetReference> | |
<Namespace>Microsoft.AspNetCore</Namespace> | |
<Namespace>Microsoft.AspNetCore.Builder</Namespace> | |
<Namespace>Microsoft.AspNetCore.Hosting</Namespace> | |
<Namespace>Microsoft.AspNetCore.Mvc</Namespace> | |
<Namespace>Microsoft.AspNetCore.Mvc.Controllers</Namespace> | |
<Namespace>Microsoft.AspNetCore.Mvc.Infrastructure</Namespace> | |
<Namespace>Microsoft.Extensions.Configuration</Namespace> | |
<Namespace>Microsoft.Extensions.DependencyInjection</Namespace> | |
<Namespace>Microsoft.Extensions.Logging</Namespace> | |
<Namespace>Swashbuckle.AspNetCore.Swagger</Namespace> | |
</Query> | |
// Didn't work. Because a controller here is a nested class in the UserQuery. | |
// And the standard method ControllerFeatureProvider.IsController don't treat it as a controller: | |
// https://github.com/aspnet/Mvc/blob/0d0aad41f501243f250b77613c015b4267e8c78d/src/Microsoft.AspNetCore.Mvc.Core/Controllers/ControllerFeatureProvider.cs#L53 | |
// > | |
// > IsPublic returns false for nested classes, regardless of visibility modifiers | |
// :( | |
// Apparently, it's possible to supply a custom IsController, now it works. | |
// https://stackoverflow.com/questions/36680933/discovering-generic-controllers-in-asp-net-core | |
// It seems we can provide controllers dynamically: | |
// https://stackoverflow.com/questions/46156649/asp-net-core-register-controller-at-runtime | |
// https://docs.microsoft.com/en-us/aspnet/core/mvc/advanced/app-parts?view=aspnetcore-2.1 | |
// https://andrewlock.net/controller-activation-and-dependency-injection-in-asp-net-core-mvc/ | |
// but IMO it's getting too complicated for a simple LINQPad script. | |
// Also there was a problem with Swagger UI: | |
// System.MissingMethodException: Method not found: 'Void Microsoft.Net.Http.Headers.EntityTagHeaderValue..ctor(System.String)'. | |
// https://github.com/pmilet/playback/issues/3 | |
// > To solve this problem: install Microsoft.AspNetCore.StaticFiles v2.0.0.0 nuget package | |
public static void Main(string[] args) | |
{ | |
var host = BuildWebHost(args); | |
host.Run(); | |
} | |
public static IWebHost BuildWebHost(string[] args) => | |
WebHost.CreateDefaultBuilder(args) | |
.UseStartup<Startup>() | |
.Build(); | |
// Define other methods and classes here | |
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
Configuration = configuration; | |
} | |
public IConfiguration Configuration { get; } | |
// This method gets called by the runtime. Use this method to add services to the container. | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddMvc() | |
.ConfigureApplicationPartManager(manager => | |
{ | |
manager.FeatureProviders.Add(new MyControllerFeatureProvider()); | |
}); | |
services.AddSwaggerGen(opts => | |
{ | |
opts.SwaggerDoc("v1", new Info { Title = "Test App", Version = "v1" }); | |
}); | |
services.AddLogging(lb => lb.AddDebug().AddConsole().SetMinimumLevel(LogLevel.Trace)); | |
} | |
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |
public void Configure(IApplicationBuilder app, IHostingEnvironment env) | |
{ | |
app.UseMvc(); | |
app.UseSwagger(); | |
app.UseSwaggerUI(opts => | |
{ | |
opts.SwaggerEndpoint("/swagger/v1/swagger.json", "TEST APP V1"); | |
}); | |
} | |
} | |
public class MyControllerFeatureProvider : ControllerFeatureProvider | |
{ | |
protected override bool IsController(TypeInfo typeInfo) | |
{ | |
var isController = base.IsController(typeInfo); | |
if (!isController) | |
{ | |
if (typeInfo.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase) || | |
typeInfo.IsDefined(typeof(ControllerAttribute))) | |
{ | |
isController = true; | |
Console.WriteLine("Found an extra Controller: " + typeInfo.FullName); | |
} | |
} | |
return isController; | |
} | |
} | |
[Route("api/[controller]")] | |
public class TodoController : Controller | |
{ | |
string[] nums = { "zero", "one", "two", "three" }; | |
[HttpGet] | |
public string[] GetAll() | |
{ | |
return nums; | |
} | |
[HttpGet("{id}", Name = "GetTodo")] | |
public ActionResult<string> GetById(int id) | |
{ | |
if (id < 0 || nums.Length <= id) | |
{ | |
return NotFound(); | |
} | |
return nums[id]; | |
} | |
} | |
[Route("monitor")] | |
[Controller] | |
public class MonitorController : Controller | |
{ | |
private readonly IActionDescriptorCollectionProvider _provider; | |
public MonitorController(IActionDescriptorCollectionProvider provider) | |
{ | |
_provider = provider; | |
} | |
[HttpGet("routes")] | |
public IActionResult GetRoutes() | |
{ | |
var routes = _provider.ActionDescriptors.Items.Select(x => new | |
{ | |
Action = x.RouteValues["Action"], | |
Controller = x.RouteValues["Controller"], | |
Name = x.AttributeRouteInfo.Name, | |
Template = x.AttributeRouteInfo.Template | |
}).ToList(); | |
return Ok(routes); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment