Register Service in ASP.NET Core as part of a middleware registration - asp.net-core

Using ASP.NET Core 3.1 I am adding a SitemapMiddleware on Startup's Configure method:
public void Configure(IApplicationBuilder builder, IWebHostEnvironment environment) {
builder.UseSitemap();
}
Where the UseSitemap extension is:
public static class SitemapMiddlewareExtensions {
public static IApplicationBuilder UseSitemap(this IApplicationBuilder builder) {
return builder.MapWhen(x => x.Request.Path.StartsWithSegments("/sitemap.xml"),
x => x.UseMiddleware<SitemapMiddleware>(route));
}
}
But the middleware uses an ISitemapService which I need to register as:
services.AddScoped<ISitemapService, SitemapService>();
How can I do this inside the method UseSitemap?
Or maybe create an IServicesCollection extension to use in Startup's ConfigureServices that registers the SitemapService?

Related

starup file changes in Asp.net core

I am Upgrading .Net core web api solution 2.2 to 3.1
I have question what should i use in statrup.cs file for 3.1
// currently i am using this
public Startup(Microsoft.AspNetCore.Hosting.IHostingEnvironment env)
public Startup(Microsoft.Extensions.Hosting.IHostingEnvironment env)
I am Upgrading .Net core web api solution 2.2 to 3.1 I have question what should i use in statrup.cs file for 3.1
If you create a new ASP.NET Core 3.1 API project using the API template, you would find it uses below Startup class.
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.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Compare it with old one, you can find the following changes:
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) is changed to services.AddControllers()
IHostingEnvironment is obsolete, and it uses IWebHostEnvironment now
app.UseEndpoints, endpoint routing is used

Controller's action not invoked in ASPNETCORE console app running Kestrel

I'd like to have a console application running a standalone webserver accepting REST calls. My application is a .NET Core app with ASP .NET Core inside. I am completely new in this area. I found some examples and now I am struggling with controller route configuration. With the code below I always get "404 Not Found" error when using http://localhost:3354/api/Demo/Hello. Does anyone have an idea what am I doing wrong? Thank you for any suggestion!
I use VS2019 and ASPNETCORE 2.2.8.
class Program
{
static void Main(string[] args)
{
var builder = WebHost.CreateDefaultBuilder()
.ConfigureKestrel(options => options.ListenAnyIP(3354))
.UseStartup<Startup>();
builder.Build().Run();
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder builder, IHostingEnvironment env)
{
builder.UseMvc(delegate(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("default", "api/{controller}/{action}");
});
}
}
Here comes the DemoController class.
public class DemoController : Controller
{
public IActionResult Hello()
{
return Ok("Hello world");
}
}
Your example is working fine for me on .net core 2.2
You could try explicitly declare routes like
[ApiController]
[Route("api/[controller]")]
public class DemoController : Controller
{
[HttpGet("hello")]
public IActionResult Hello()
{
return Ok("Hello world");
}
}
Also you could consider using Visual studio built-in templates of api web applications
After some investigation and comparison of my project with the sample project of Roman Kalinchuk I found out that the problem is that mvc controller provider doesn't look for controller types in my application assembly. It is enought to add my application assembly to the application parts collection.
See the .AddApplicationPart(typeof(DemoController).Assembly); line.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services
.AddMvc()
.AddApplicationPart(typeof(DemoController).Assembly);
}
public void Configure(IApplicationBuilder builder, IHostingEnvironment env)
{
env.EnvironmentName = "Development";
builder.UseMvc(delegate(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("test", "api/{controller}/{action}");
});
}
}

'ConfigureServices returning an System.IServiceProvider isn't supported.' in .NET Core 3.1 using Autofac

I want to use autofac injection instead of default .net core solution.
Here is my startup file :
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc(option => option.EnableEndpointRouting = false) ;
var cb = new ContainerBuilder();
cb.RegisterModule<mydependecymodule>();
cb.Populate(services);
var container = cb.Build();
return new AutofacServiceProvider(container);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseDeveloperExceptionPage();
app.UseStatusCodePages();
app.UseStaticFiles();
app.UseMvc(routes=>routes.MapRoute("default","/{controller=home}/{action=index}"));
}
And here is my program.cs
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
}).UseServiceProviderFactory(new AutofacServiceProviderFactory());
But when I run my application I get this error in my main method:
System.NotSupportedException: 'ConfigureServices returning an System.IServiceProvider isn't supported.'
In ASP.NET Core 3.0 the ASP.NET Core hosting model changed and you can't return an IServiceProvider anymore. This is documented in the Autofac docs for integrating with ASP.NET Core 3.0+.
You have to switch your ConfigureServices to be void, and if you want to register stuff directly with Autofac you need to use ConfigureContainer. You also need to register the AutofacServiceProviderFactory in your Program.Main method when you construct the host. There are examples in the documentation showing how to do this.

Injecting repository in custom filter.net core mvc

I have app written in asp.net core MVC c#
I have written a custom filter as:
public class CustomFilter: IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//need to call my sqlrepository here
}
}
How can I call my SQL repository inside my custom filter?
I have my controller as:
public class HomeController
{
private IMySqlRepository _repo;
public HomeController(IMySqlRepository myRepo)
{
_repo= myRepo;
}
}
In my home controller, I can call this fine by above code.
Also just FYI I register this repo in my startup as:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IMySqlRepository , MySqlRepository >();
}

Conditionally use custom middleware

I created my custom authentication middleware in asp. net core project, and registered it as shown below:
public class MyAuthenticationMidleware
{
private readonly RequestDelegate _next;
public ConnectAuthenticationMidleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (!UserIsAuthenticated())
{
context.Response.StatusCode = 401;
return;
}
...
await _next.Invoke(context);
}
}
public static class MyAuthenticationMidlewareExtensions
{
public static IApplicationBuilder UseMyAuthentication(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyAuthenticationMidleware>();
}
}
In Startup:
public void Configure(...)
{
app.UseStaticFiles();
app.UseMyAuthentication();
app.UseMvc();
}
This works correctly - authentication middleware is run for each request. If user is not authenticated, 401 is returned. Otherwise specific mvc action is invoked.
What I tried to do was to prevent the authentication middleware from running for some specific actions. I used MapWhen method to create another extension method and used it as follows:
public static class MyAuthenticationMidlewareExtensions
{
public static IApplicationBuilder UseMyAuthentication(this IApplicationBuilder builder)
{
return builder.UseMiddleware<MyAuthenticationMidleware>();
}
public static IApplicationBuilder UseMyAuthenticationWhen(this IApplicationBuilder builder, Func<HttpContext, bool> predicate)
{
return builder.MapWhen(predicate, applicationBuilder => applicationBuilder.UseMyAuthentication());
}
}
public void Configure(...)
{
app.UseStaticFiles();
app.UseMyAuthenticationWhen(context => context.Request.Path != "xyz");
app.UseMvc();
}
Unfortunately, this doesn't work as expected. The middleware is invoked only when path is different than "xyz", but it seems that it short-circuts the whole chain - no mvc specific actions or filters are invoked.
Probably my understanding of MapWhen is incorrect. Is there any way to get the result I want?
MapWhen creates a new pipeline branch when the supplied predicate is true, and that branch does not rejoin with the main branch where you have UseMvc().
You can change your extension method to use UseWhen instead of MapWhen. UseWhen rejoins with the main pipeline so that your UseMvc() will still get called.
Note: While the above link references aspnet-contrib, the UseWhen extension method is now part of Microsoft.AspNetCore.Http.Abstractions.
This allows you to keep UseMvc() explicit in your Configure method instead of hidden away in your authentication extension method, where it really has no business being.
MapWhen is used to seperate middleware pipeline. If you want to use mvc for branced pipeline you need to add separetely. So you should use .UseMvc(); in extension method like below:
public static IApplicationBuilder UseMyAuthenticationWhen(this IApplicationBuilder builder, Func<HttpContext, bool> predicate)
{
return builder.MapWhen(predicate, applicationBuilder =>
{
applicationBuilder.UseMyAuthentication();
applicationBuilder.UseMvc();
});
}
However i wouldn't go with your way. For authentication middleware i would implement my own middleware like Simple token based authentication/authorization in asp.net core for Mongodb datastore and use Authorize attribute for authorization mvc actions.