Inject httpcontext into custom attribute outside controller in .net core - asp.net-core

I need to inject httpcontext into custom attribute that is used outside the controller. I found several solutions how to do it in controller, but my case is little tricky. Now I have following code in my PermissionController
[PermissionFilter(PermissionEnum.Permission, AccessLevelEnum.Create)] <-- it works perfectly
[HttpPost("users/{userId}")]
public async Task<IActionResult>
AssignPermissionToUser([FromBody] List<PermissionToVM> permissions, int userId)
{
await _permissionService.Assign(permissions); <-- .Assign() extension
//code goes here
}
In the method above there is a call of extension method .Assign. This method code is available below.
//[SecondPermissionFilter(PermissionEnum.Permission,
AccessLevelEnum.Create)] <-- here I check permissions but don't
know how to inject the httpcontext
public async Task Assign(List<PermissionToVM> permissions)
{
//code goes here
}
As mentioned in many websites I visited f.e. here https://dotnetcoretutorials.com/2017/01/05/accessing-httpcontext-asp-net-core/ injecting of httpcontext outside the controller can be done using IHttpContextAccessor. The problem is that I don't know how to use it without passing it into constructor. My custom attribute should be called as decorator [SecondPermissionFilter(PermissionEnum.Permission, AccessLevelEnum.Create)] when only permission settings should be passed, so there is no any reference to httpcontextaccessor.
Is this even possible? If not, there is maybe another way to do this?
EDIT: Here is the code of SecondPermissionFilter class:
public sealed class SecondPermissionFilterAttribute : Attribute
{
private readonly PermissionEnum _requestedPermission;
private readonly IEnumerable<AccessLevelEnum> _accessLevelCollection;
private readonly IHttpContextAccessor _contextAccessor; //<-- how to inject?
public PermissionFilterAttribute(PermissionEnum requestedPermission, params AccessLevelEnum[] accessLevelCollection)
{
_requestedPermission = requestedPermission;
_accessLevelCollection = accessLevelCollection;
}
}

What you are after is something called Property Injection. As per the official docs this is not something that is supported out of the box by the .NET Core DI Container.
You can however use a third party library such as Ninject or Autofac - both of which are available via NuGet.
In my opinion the Ninject syntax is nicer, however as noted in this answer, and this answer property injection itself is considered bad practice. So if possible I would try to avoid it.
So you should instead use one of the three methods specified by the filter documentation, this answer breaks things down a bit more.
Edit
This answer deals specificically with Attribute injection, the second answer looks to achieve this without external dependencies.

Related

How to use WebApplicationFactory in .net6 (without speakable entry point)

In ASP.NET Core 6 default template moves everything from Sturtup.cs into Program.cs, and uses top-level statements in Program.cs, so there's no more (speakable) Program class ether.
That looks awesome, but now, I need to test all of this. WebApplicationFactory<T> still expects me to pass entry-point-class, but I cannot do this (due to it's name now being unspeakable).
How integration tests are expected to be configured in ASP.NET Core 6?
Note that if you are trying to use xUnit and its IClassFixture<T> pattern, you will run into problems if you just use the InternalsVisibleTo approach. Specifically, you'll get something like this:
"Inconsistent accessibility: base class WebApplicationFactory<Program> is less accessible than class CustomWebApplicationFactory."
Of course you can solve this by making CustomWebApplicationFactory internal but it only moves the problem as now your unit test class will give the same error. When you try to change it there, you will find that xUnit requires that tests have a public constructor (not an internal one) and you'll be blocked.
The solution that avoids all of this and allows you to still use IClassFixture<Program> is to make the Program class public. You can obviously do this by getting rid of the magic no class version of Program.cs, but if you don't want to completely change that file you can just add this line:
public partial class Program { } // so you can reference it from tests
Of course once it's public you can use it from your test project and everything works.
As an aside, the reason why you typically want to prefer using IClassFixture is that it allows you to set up your WebApplicationFactory just once in the test class constructor, and grab an HttpClient instance from it that you can store as a field. This allows all of your tests to be shorter since they only need to reference the client instance, not the factory.
Example:
public class HomePage_Get : IClassFixture<CustomWebApplicationFactory>
{
private readonly HttpClient _client = new HttpClient();
public HomePage_Get(CustomWebApplicationFactory factory)
{
_client = factory.CreateClient();
}
[Fact]
public async Task IncludesWelcome()
{
HttpResponseMessage response = await _client.GetAsync("/");
response.EnsureSuccessStatusCode();
string stringResponse = await response.Content.ReadAsStringAsync();
Assert.Contains("Welcome.", stringResponse);
}
}
Finally note that Damian Edwards' MinimalAPIPlayground was updated to use this approach after we discussed the issue. See this commit
The problem is was solved on ASP.NET Core RC1, but as of now (September 20, 2021) the docs are incomplete.
The compiler generates a Program class behind the scenes that can be used with WebApplicationFactory<>. The class isn't public though so the InternalsVisibleTo project setting should be used.
Damien Edwards' Minimal API sample uses the latest nightly bits. The test web app class is declared as :
internal class PlaygroundApplication : WebApplicationFactory<Program>
{
private readonly string _environment;
public PlaygroundApplication(string environment = "Development")
{
_environment = environment;
}
protected override IHost CreateHost(IHostBuilder builder)
{
...
In the application project file,InternalsVisibleTo is used to make the Program class visible to the test project:
<ItemGroup>
<InternalsVisibleTo Include="MinimalApiPlayground.Tests" />
</ItemGroup>
RC1 is feature complete and, judging by previous major versions, it will probably be the first version to have a Go Live license, which means it's supported in production.
I tried
<InternalsVisibleTo Include="MinimalApiPlayground.Tests" />
but no cigar! Removed it and added a partial class to program.cs
#pragma warning disable CA1050 // Declare types in namespaces
public partial class Program
{
}
#pragma warning restore CA1050 // Declare types in namespaces
amazingly it worked.

Translate property name in error messages with FluentValidation

I use FluentValidation in my project in order to validate almost every requests coming into my WebApi.
It works fine, but I've been asked to translate property names in the error messages. My projet must handle at least french and english, so for example, what I want to achieve is :
'First Name' is required (english case)
'Prénom' est requis (french case)
I already have a IPropertyLabelService for other purposes, that is injected in the Startup.cs, that I want to use. It finds translations of property names in a .json, which already works fine.
My problem is that I don't know how to use it globally. I know that FluentValidation's doc says to set the ValidatorOptions.DisplayNameResolver in the Startup file, like this :
FluentValidation.ValidatorOptions.DisplayNameResolver = (type, memberInfo, expression) => {
// Do something
};
I don't know how I can use my IPropertyLabelService inside this, as the Startup.ConfigureServices method is not over yet, so I can't resolve my service...
Any other solution to achieve this behaviour is also more than welcome. I considered using .WithMessage() or .WithName() but I have a really big amount of validators, that would be really long to add this to all individually.
I answered this over on the FluentValidation issue tracker, but for completeness will include the answer here too:
Ssetting FluentValidation.ValidatorOptions.Global.DisplayNameResolver is the correct way to handle this globally (or you can use WithName at the individual rule level).
You need to ensure that this is set once, globally. If you need the service provider to have been initialized first, then make sure you call it at a point after the service provider has been configured (but ensure you still only set it once).
The "options" configuration mechanism in .NET Core allows you to defer configuration until after the point services have been constructed, so you can create a class that implements IConfigureOptions, which will be instantiated and executed during the configuration phase for a particular options type. FluentValidation doesn't provide any options configuration itself, so you can just hook into one of the built-in options classes (ASP.NET's MvcOptions is probably the simplest, but you can also use a different one if you're not using mvc).
For example, you could do something like this inside your ConfigureServices method:
public void ConfigureServices(IServiceCollection services) {
// ... your normal configuration ...
services.AddMvc().AddFluentValidation();
// Afterwards define some deferred configuration:
services.AddSingleton<IConfigureOptions<MvcOptions>, DeferredConfiguration>();
}
// And here's the configuration class. You can inject any services you need in its constructor as with any other DI-enabled service. Make sure your IPropertyLabelService is registered as a singleton.
public class DeferredConfiguration : IConfigureOptions<MvcOptions> {
private IPropertyLabelService _labelService;
public DeferredConfiguration(IPropertyLabelService labelService) {
_labelService = labelService;
}
public void Configure(MvcOptions options) {
FluentValidation.ValidatorOptions.Global.DisplayNameResolver = (type, memberInfo, expression) => {
return _labelService.GetPropertyOrWhatever(memberInfo.Name);
};
}
}

How to implement Transactions with Generic Repository Pattern?

I am developing a .NET Core application where I leverage the Generic Repository pattern and I would like to know how can I implement a transaction:
IGenericRepository
public interface IGenericRepository<T>
{
Task InsertAsync(T insert);
Task<bool> RemoveAsync(object id);
Task UpdateAsync(T entity);
Task<T> GetByIdAsync(object id,string includeProperties="");
Task<IQueryable<T>> GetAsync(Expression<Func<T, bool>> filter=null,
int? skip=null,
int? take=null,
Func<IQueryable<T>,IOrderedQueryable<T>> orderBy = null,
string includeProperties = "");
Task SaveAsync();
}
I was looking at this implementation which uses UnitOfWork as well, but in .NET Core, I do not have a DbContextTransaction.
I am not using UnitOfWork yet. Currently my service looks like this:
public class SomeService
{
IGenericRepository<A> arepo;
IGenericRepository<B> brepo;
public SomeService(IGenericRepository<A> arepo,IGenericRepository<B> brepo)
{
this.arepo=arepo;
this.brepo=brepo;
}
public async Task DoTransaction(id)
{
var a=await arepo.GeyById(id)
await brepo.RemoveAsync(a.Id);
await brepo.SaveChangesAsync();
await arepo.InsertAsync([something]);
await arepo.SaveChanges();
}
}
I would want to make this transactional and also, avoid using SaveChangesAsync for all repositories that get involved.
What would be a solution?
Well I am not expert in entity framework, but I am answering in terms of repository and unit of work.
To begin with, avoid unnecessary wrapper of additional generic repository as you are already using full-ORM. Please refer to this answer.
but in .NET Core i do not have a DbContextTransaction.
The DbContextTransaction is important but not a key for implementing unit of work in this case. What is important is DBContext. It is DBContext that tracks and flushes the changes. You call SaveChanges on DBContext to notify that you are done.
I would want to make this transactional
I am sure there must be something available to replace DbContextTransaction or to represent transaction.
One way suggested by Microsoft is to use it as below:
context.Database.BeginTransaction()
where context is DbContext.
Other way is explained here.
also ,avoid using SaveChangesAsync for all repos that get involved
That is possible. Do not put SaveChanges in repositories. Put it in separate class. Inject that class in each concrete/generic repository. Finally, simply call SaveChanges once when you are done. For sample code, you can have a look at this question. But, code in that question have a bug which is fixed in the answer I provided to it.

How to receive IHubContext out of Dependency Injected classes?

I want to send message from Service A using SignalR when some event occures (for example, message from Service B received).
So hub method needs to be called from some sort of handler, that not constructed using Dependency Injection. How I can do this?
So far, I tried and read about the following things:
I can inject context into Controller and lead it to my handler. I probably can do that, but passing hub context from the top (controller class) to the bottom (handler class) is not the best approach, which adds a lot of dependencies to the classes that should not be aware of this context, so I would like to avoid that.
I can inject my IHubContext in "any" class, but then, the thing is, how to get an instance of that class on my handler?
Add Static method to class with injected context!? Well, that works until you have 1 client because with new client static property is going to be overwritten.
So I cannot imagine, how handler can use dependency injected IHubContext.
Probably, someone did that before and have an example of how to truly inject context into any class.
Thank you in advance and any additional information will be provided, if necessary.
Answer 1
Here is one possible solution. Implement a factory pattern. Create a factory that knows how to create your handler. Inject the IHubContext in the factory. You can use a few approaches that way:
Construct the Handler by passing in the IHubContext
Create a public property in the Handler and set the IHubContext
Create a method in the Handler and pass the IHubContext as a parameter
You can decide whichever approach suits you. Inject that factory in the controller via DI, and get the handler using the factory method. That way you are not exposing the IHubContext. Please see the code below
public interface IHandlerFactory
{
Handler CreateHandler();
}
public class HandlerFactory : IHandlerFactory
{
private IHubContext _hubContext;
public HandlerFactory(IHubContext context)
{
_hubContext = context;
}
public Handler CreateHandler()
{
return new Handler(param1, param2, _context);
}
}
Then in the entry point, controller/service, inject the factory via DI
public class MyController : Controller
{
private Handler _handler;
public MyController(IHandlerFactory factory)
{
_handler = factory.CreateHandler();
}
}
Then you can use that _handler in the other methods. I hope this helps.
Answer 2
Another possible solution is to use IHostedService if it's possible at all for you. Please see a solution to a GitHub issue, provided by David Fowler here, that I think somewhat relevant to your scenario.

Late binding with Ninject

I'm working on a framework extension which handles dynamic injection using Ninject as the IoC container, but I'm having some trouble trying to work out how to achieve this.
The expectation of my framework is that you'll pass in the IModule(s) so it can easily be used in MVC, WebForms, etc. So I have the class structured like this:
public class NinjectFactory : IFactory, IDisposable {
readonly IKernel kernel;
public NinjectFactory(IModule[] modules) {
kernel = new StandardKernel(modules);
}
}
This is fine, I can create an instance in a Unit Test and pass in a basic implementation of IModule (using the build in InlineModule which seems to be recommended for testing).
The problem is that it's not until runtime that I know the type(s) I need to inject, and they are requested through the framework I'm extending, in a method like this:
public IInterface Create(Type neededType) {
}
And here's where I'm stumped, I'm not sure the best way to check->create (if required)->return, I have this so far:
public IInterface Create(Type neededType) {
if(!kernel.Components.Has(neededType)) {
kernel.Components.Connect(neededType, new StandardBindingFactory());
}
}
This adds it to the components collection, but I can't work out if it's created an instance or how I create an instance and pass in arguments for the .ctor.
Am I going about this the right way, or is Ninject not even meant to be be used that way?
Unless you want to alter or extend the internals of Ninject, you don't need to add anything to the Components collection on the kernel. To determine if a binding is available for a type, you can do something like this:
Type neededType = ...;
IKernel kernel = ...;
var registry = kernel.Components.Get<IBindingRegistry>();
if (registry.Has(neededType)) {
// Ninject can activate the type
}
Very very late answer but Microsoft.Practices.Unity allows Late Binding via App.Config
Just in case someone comes across this question