CSS Only Dropdown Menu
As someone who basically gets by when it comes to writing Javascript, I tend to look at things from a “I bet I could do this with CSS” st...
CSS SCSS Mobile UX UI/UX frontendRead ASP.NET Core 2.2 First Look – Endpoint Routing and ASP.NET Core updates in .NET Core 3.0 Preview 2 to get a more-detailed picture on how routing is now exposed in relation to ASP.NET Core.
Routing has traditionally been a construct confined within the ASP.NET ecosystem. As long as your code executes within that construct, you can read route data. However, with the proliferation of middleware that run before and after ASP.NET, the desire/need for an app.-wide, exposed routing system increased.
using Microsoft.AspNetCore.Internal;
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app
.UseEndpointRouting() // Registering this prior to your middleware unlocks the ✨.
//.YourMiddleware()
.UseMvc();
}
}
using Microsoft.AspNetCore.Builder;
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app
.UseRouting() // Registering this prior to your middleware unlocks the ✨.
//.YourMiddleware()
.UseMvc();
}
}
Imagine you’re building a new blog engine… 🤔
💡 Maybe you want to pre-load a post via middleware so it’s available anywhere down the chain. This way, none of other middleware is concerned with how to retrieve the post and can instead focus on whatever it does to augment the response.
public class Post
{
public string Slug { get; set; }
public string Title { get; set; }
}
/// <summary>
/// We need a derivative class to support scenarios where we can't find a `Post`-record based on {slug}.
/// DI will throw an exception if we try to give it `null`.
/// </summary>
public class GenericPost : Post
{ }
@page "{slug}"
@model PostModel
<h1>@Model.Title</h1>
...
public class PostModel : BaseModel
{
public PostModel(Post post)
{
this.post = post;
}
public Post post { get; private set; }
public void OnGet()
{ }
}
public class PostMiddleware
{
public PostMiddleware(
RequestDelegate next,
IDatabase database)
)
{
this.next = next;
this.database = database;
}
private readonly IDatabase datbase;
private readonly RequestDelegate next;
public async Task InvokeAsync(HttpContext context)
{
var route = context.GetRouteData();
if (route.Values.TryGetValue("slug", out var routeSlug))
{
var slug = routeSlug.ToString();
var post = (await database.Fetch<Post>()).FirstOrDefault(x => x.Slug == slug);
if (post != null)
{
context.Items.Add(nameof(Post), post);
}
}
await next(context);
}
}
ℹ️ This could also be refactored into a separate extension-method.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<Post>(serviceProvider =>
{
var accessor = serviceProvider.GetRequiredService<IHttpContextAccessor>();
if (accessor.HttpContext.Items.TryGetValue(nameof(Post), out var post))
{
return post as Post;
}
else
{
return new GenericPost(); // we need to return something that is either a `Post` or derivative of `Post`.
}
});
}
Here are a couple source-links for both the 2.2 and 3.0-versions if you’re interested in what happens behind the scenes: