Injecting repository in custom filter.net core mvc - asp.net-core

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 >();
}

Related

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}");
});
}
}

How to start an ASP.NET Core BackgroundService on demand?

I want to be able to start fire-and-forget jobs in ASP.NET Core 2.2. I have tried the following:
services.AddHostedService<TestHostedService>();
public class TestHostedService : BackgroundService
{
private readonly ILogger _logger;
public TestHostedService(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<TestHostedService>();
}
public IBackgroundTaskQueue TaskQueue { get; }
protected async override Task ExecuteAsync(
CancellationToken cancellationToken)
{
_logger.LogInformation("TestHostedService is starting.");
_logger.LogInformation("TestHostedService is stopping.");
}
}
However, this automatically starts and I want to be able to start it on demand, similarly to how Hangfire allows:
BackgroundJob.Enqueue<TestJob>(x => x.DoWork());
This also allows the job to naturally use ASP.NET CORE DI.
Question: How to start an ASP.NET Core BackgroundService on demand?
###Background information
I am dealing with an application that needs to fire-and-forget various methods. The already written code looks like this:
Task.Run(() => RunSomething(_serviceScopeFactory));
This means that each method must explicitly deal with getting a scope and retrieving the dependencies which is quite ugly.
If you want to run the BackgroundService in the MVC controller or other service. You could try to inject the IServiceProvider to that class and then loop all the hosted service and find the background service, at last you could call the startasync method.
More details, you could refer to below codes:
Register the service in Startup.cs
services.AddHostedService<TestHostedService>();
Execute the background service in the controller:
public class HomeController : Controller
{
private readonly IServiceProvider _serviceProdiver;
public HomeController(IServiceProvider serviceProdiver) {
_serviceProdiver = serviceProdiver;
}
public async Task<IActionResult> Index()
{
var allBackgroundServices = _serviceProdiver.GetServices<IHostedService>();
foreach (var hostedService in allBackgroundServices)
{
if (hostedService.GetType() == typeof(TestHostedService))
{
await hostedService.StartAsync(CancellationToken.None);
}
}
return View();
}
}
Result:

ASP.Net Core WebApi - storing values from ActionFilter to access in controller

In an ASP.Net Core WebApp I want to use an ActionFilter and send information from the ActionFilter to the controller it is applied to.
MVC
For MVC I can do this
ActionFilter
public class TenantActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
//Using some sneaky logic to determine current tenant from domain, not important for this example
int tenantId = 1;
Controller controller = (Controller)context.Controller;
controller.ViewData["TenantId"] = tenantId;
}
public void OnActionExecuted(ActionExecutedContext context) { }
}
Controller
public class TestController : Controller
{
[ServiceFilter(typeof(TenantActionFilter))]
public IActionResult Index()
{
int tenantId = ViewData["TenantId"];
return View(tenantId);
}
}
It works and I can pass data back to the controller via ViewData - great.
WebApi
I want to do the same for WebApi Controllers.
The actionFilter itself can be applied, runs etc - but I cannot write to ViewData, because WebAPI inherits from ControllerBase - not from Controller (like MVC).
Question
How can I push data from my ActionFilter back to the calling ControllerBase, similar to MVC?
Notes
ASP.Net Core 2.2 being used, but I would be surprised if a solution would not be usable in all of .Net Core.
...So I found the answer when I was almost done writing the question, so here goes...
The answer is the HttpContext.Items collection
ActionFilter
public class TenantActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
int tenantId = 1;
var controller = (ControllerBase)context.Controller;
controller.HttpContext.Items.Add("TenantId", tenantId);
}
public void OnActionExecuted(ActionExecutedContext context) { }
}
Controller
public class TestApiController : ControllerBase
{
[ServiceFilter(typeof(TenantActionFilter))]
public SomeClass Get()
{
int tenantId;
if (!int.TryParse(HttpContext.Items["TenantId"].ToString(), out tenantId))
{
tenantId = -1;
}
return new SomeClass();
}
}

Asp.Net Core No service for type has been registered

I have the following two classes
public class RepositoryConnection : IRepositoryConnection{
public RepositoryConnection(IConfiguration configuration, ILogger<RepositoryConnection> logger){
//STUFF
}
}
public class AuthenticationTokenFactory : IAuthenticationTokenFactory {
public AuthenticationTokenFactory(ILogger<AuthenticationTokenFactory> logger) {
//STUFF
}
}
Here is my Startup.cs
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services) {
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddSingleton<IAuthenticationTokenFactory, AuthenticationTokenFactory>();
services.AddSingleton<IRepositoryConnection,RepositoryConnection>();
}
}
I can successfully inject IAuthenticationTokenFactory to controllers but when i try to inject IRepositoryConnection i get the following error→
InvalidOperationException: No service for type 'TrainingCommerce.Accessors.RepositoryConnection' has been registered.
Thanks to comments i immediately noticed my wrongful ways.
I was trying to access at another line
var debug = ControllerContext.HttpContext.RequestServices.GetRequiredService<RepositoryConnection>();
Try injecting the interface instead of the implementation:
In your sample you inject ILogger<RepositoryConnection> logger this is a typo and should be: ILogger<IRepositoryConnection> logger.
So:
public class RepositoryConnection : IRepositoryConnection{
public RepositoryConnection(IConfiguration configuration, ILogger<IRepositoryConnection> logger){
//STUFF
}
}

dependency injection into view model class in asp.net core

I am using the following DTO class in one of my api controller class, in an asp.net core application.
public class InviteNewUserDto: IValidatableObject
{
private readonly IClientRepository _clientRepository;
public InviteNewUserDto(IClientRepository clientRepository)
{
_clientRepository = clientRepository;
}
//...code omitted for brevity
}
This is how I using it in a controller
[HttpPost]
public async Task<IActionResult> RegisterUser([FromBody] InviteNewUserDto model)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
//...omitted for brevity
}
But I am getting a System.NullReferenceException in the DTO class
This is happening since dependency injection is not working in the DTO class.
How can I fix this ?
DI will not resolve dependences for ViewModel.
You could try validationContext.GetService in Validate method.
public class InviteNewUserDto: IValidatableObject
{
public string Name { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
IClientRepository repository = (IClientRepository)validationContext.GetService(typeof(IClientRepository));
return null;
}
}
Did you register ClientRepository in startup.cs?
public void ConfigureServices(IServiceCollection services)
{
...
// asp.net DI needs to know what to inject in place of IClientRepository
services.AddScoped<IClientRepository, ClientRepository>();
...
}