Skip to content

Instantly share code, notes, and snippets.

@tsvx
Last active July 19, 2018 15:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tsvx/7fdc2c55282859f70c327d2a3dbf9f3e to your computer and use it in GitHub Desktop.
Save tsvx/7fdc2c55282859f70c327d2a3dbf9f3e to your computer and use it in GitHub Desktop.
PoC of ASP.NET Core MVC App in LinqPAD
<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