There is no argument given that corresponds to the required formal parameter 'userRoleService' of 'AuthorizeUserAttribute.AuthorizeUserAttribute(string, IUserRoleService, IModuleService, IUserService)'
AuthorizationController.cs
[AuthorizeUserAttribute("User.Edit")]
public ActionResult UserAuthorizationEdit()
AuthorizeUserAttribute.cs
public string Action { get; set; }
private IUserRoleService _userRoleService;
private IModuleService _moduleService;
private IUserService _userService;
public AuthorizeUserAttribute(IUserRoleService userRoleService, IModuleService moduleService, IUserService userService)
{
_userRoleService = userRoleService;
_moduleService = moduleService;
_userService = userService;
}
When I try to add constructor,controller side says write constructor as a parameter. How Can i change interface to a constructor
You need to use
[TypeFileter(typeof(AuthorizeUser),Arguments = new object[] { "User.Edit" }))]
public ActionResult UserAuthorizationEdit(int userId,
RoleRegisterDto authorizationModel)
in order to dependency injection can inject your services.
If you want to uses interfaces via class constructor using DI,you need to pass the parameter with the same type from custom attribute on controller side.
To avoid doing that, you could register your interfaces as services and get them using below code without constructor injection.For example:
1.Interface
public interface IUserRoleService
{
List<string> GetValues();
}
public class UserRoleService : IUserRoleService
{
private List<string> _privateList = new List<string>();
public List<string> GetValues()
{
_privateList.Add("test");
return _privateList;
}
}
2.In startup:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IUserRoleService, UserRoleService>();
}
3.Custom Authorization Attribute
public class AuthorizeUserAttribute:AuthorizeAttribute, IAsyncAuthorizationFilter
{
public string Action { get; set; }
public AuthorizeUserAttribute(string action)
{
Action = action;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext authorizationFilterContext)
{
var x = authorizationFilterContext.HttpContext.RequestServices.GetRequiredService<IUserRoleService>();
var y = x.GetValues();
}
}
4.Action
[AuthorizeUserAttribute("User.Edit")]
public ActionResult UserAuthorizationEdit()
Related
I'm very new to ASP.NET Web API and I'm trying to use Entity Framework Core's Dependency Injection to POST data to the API Controller using MediatR pattern. But every time I run my code and it opens Swagger UI, I get an error 500 response saying
Unable to cast object of type 'AsyncStateMachineBox1[System.Threading.Tasks.VoidTaskResult,S3E1.Repository.CartItemRepository+<Createitem>d__5]' to type 'System.Threading.Tasks.Task1[S3E1.Entities.CartItemEntity]'.
First, I added Dependency Injections to Program.cs
//Dependency Injection
builder.Services.AddDbContext<AppDataContext>(contextOptions => contextOptions.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
));
//Connection
builder.Services.AddSingleton<DataConnectionContext>();
These are the classes.
AppDataContext.cs
public class AppDataContext : DbContext
{
public AppDataContext(DbContextOptions<AppDataContext> contextOptions) : base(contextOptions) { }
public DbSet<CartItemEntity> CartItems { get; set; }
public DbSet<OrderEntity> Orders { get; set; }
public DbSet<UserEntity> Users{ get; set; }
}
DataConnectionContext.cs
public class DataConnectionContext
{
private readonly IConfiguration _configuration;
private readonly string _connectionString;
public DataConnectionContext(IConfiguration configuration)
{
_configuration = configuration;
_connectionString = _configuration.GetConnectionString("DefaultConnection");
}
public IDbConnection CreateConnection() => new SqlConnection(_connectionString);
}
Next is making a repository which holds the interface that has the create method.
public interface ICartItemRepository
{
//public Task<IEnumerable<CartItemEntity>> GetCartItems();
//public Task<CartItemEntity> GetCartItemEntity(Guid id);
public Task Createitem(CartItemEntity itemEntity);
}
Then a class that inherits the interface and calls the dependency constructors
public class CartItemRepository : ICartItemRepository
{
private readonly DataConnectionContext _connectionContext;
private readonly AppDataContext _appDataContext;
public CartItemRepository(DataConnectionContext connectionContext, AppDataContext appDataContext)
{
_connectionContext = connectionContext;
_appDataContext = appDataContext;
}
public async Task Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
await _appDataContext.CartItems.ToListAsync();
}
}
Next is a command for POST request MediatR pattern
public record AddCartItemCommand(CartItemEntity cartItem) : IRequest<CartItemEntity>;
and a Handler which manages and returns the method createitem
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
private readonly ICartItemRepository _cartItemRepository;
public AddItemsHandler(ICartItemRepository cartItemRepository) => _cartItemRepository = cartItemRepository;
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await (Task<CartItemEntity>) _cartItemRepository.Createitem(request.cartItem);
}
}
and lastly, in the controller
[Route("api/cart-items")]
[ApiController]
public class CartItemsController : ControllerBase
{
private ISender _sender;
public CartItemsController(ISender sender) => _sender = sender;
[HttpPost]
public async Task<CartItemEntity> Post(CartItemEntity cartItemEntity)
{
return await _sender.Send(new AddCartItemCommand(cartItemEntity));
}
}
I tried modifying the return object in the handler but every time I change anything it always get the error squiggly line, so I just casted the (Task) after the await. Is this where I went wrong? Thank you for any answers.
The exception is clear. You can't cast a VoidTaskResult to Task<CartItemEntity>.
To solve the problem:
In ICartItemRepository, modify the return type for Createitem as Task<CartItemEntity>.
In CartItemRepository, implement Createitem method from the ICartItemRepository interface. Return the inserted itemEntity in the method.
Since you have implemented Task<CartItemEntity> Createitem(CartItemEntity itemEntity) in the ICartItemRepository interface, the casting to (Task<CartItemEntity>) is no longer needed, and suggested to be removed.
public interface ICartItemRepository
{
...
public Task<CartItemEntity> Createitem(CartItemEntity itemEntity);
}
public class CartItemRepository : ICartItemRepository
{
...
public async Task<CartItemEntity> Createitem(CartItemEntity itemEntity)
{
_appDataContext.CartItems.Add(itemEntity);
await _appDataContext.SaveChangesAsync();
return itemEntity;
}
}
public class AddItemsHandler : IRequestHandler<AddCartItemCommand, CartItemEntity>
{
...
public async Task<CartItemEntity> Handle(AddCartItemCommand request, CancellationToken cancellationToken)
{
return await _cartItemRepository.Createitem(request.cartItem);
}
}
Is there any way to resolve the instance of a class at the controller level? I would like to override the previous instance created by unity and assign this new value via the controller.
Problem is I am not sure how to access the unity container in the web app controller.
Here is my code:
Repository:
public class UserRepository: IUserRepository
{
private UserInformation _userInfo;
public UserRepository(string headerValue)
{
_userInfo = LoadUserData(headerValue);
}
public UserInformation GetUserInfo()
{
return _userInfo;
}
}
public class UserInformation
{
public string FirstName;
public string LastName;
}
Unity Configuration:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
//Some code omitted
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.RegisterComponents());
}
}
public static class UnityConfig
{
public static UnityContainer RegisterComponents()
{
//Unity Configuration
var container = new UnityContainer();
container.RegisterType<IUserRepository, UserRepository>(new InjectionConstructor("DummyHeaderValue"));
return container;
}
}
Controller:
public class CustomerController : ApiController
{
public CustomerController()
{
//Something like this
container.Resolve<UserRepository>(new InjectionConstructor(Request.GetHeader("RealHeaderValueFromHttpRequest")));
}
}
Then I should be able to use the updated UserRepository instance throughout the application.
Any thoughts on how to achieve this?
Edit: As pointed out by #Nkosi I don't have access to Request in controller constructor. So let me rephrase my question again:
How would I initialise UserRepository with UserInformation object which contains details about the current user? The reason I want to do this is that throughout my application I want user details and I don't want to pass User Id from each method
Something like this: From any method throughout application
UserInformation obj = _userRepository().GetUserInfo();
Create an abstraction to get access to the request
public interface IHeaderService {
string RealHeaderValueFromHttpRequest();
}
Its Implementation will have access to the context and request to get the desired functionality
public class HeaderService : IHeaderService {
public string RealHeaderValueFromHttpRequest() {
return HttpContext.Current.Request.Headers["RealHeaderValueFromHttpRequest"];
}
}
The service will now be explicitly injected into the dependent repository
public class UserRepository: IUserRepository {
private readonly IHeaderService headerService;
public UserRepository(IHeaderService headerService) {
this.headerService = headerService;
}
public UserInformation GetUserInfo() {
var headerValue = headerService.RealHeaderValueFromHttpRequest();
var _userInfo = LoadUserData(headerValue);
return _userInfo;
}
//...
}
The repository will then also be explicitly injected into dependent controllers.
public class CustomerController : ApiController {
private readonly IUserRepository repositoty;
public CustomerController(IUserRepository repositoty) {
this.repository = repository;
}
public IHttpActionResult SomeAction() {
//NOTE: Only access user info in a controller action
var userInfo = repository.GetUserInfo();
//... use user info.
}
//...
}
Now all that is left is to make sure all abstractions and their implementations are registered with the dependency container
public static class UnityConfig {
public static UnityContainer RegisterComponents() {
//Unity Configuration
var container = new UnityContainer();
container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<IHeaderService, HeaderService>();
return container;
}
}
I am trying to add specific properties to telemetry request for every route.
After digging a bit, I've found that I can create my own custom TelemetryInitializer by implementing ITelemetryInitializer.
By doing this I've managed to add global properties to the request.
However, I still need to add specific properties at the controller level.
Do you have any idea how can I achieve this?
I've tried to inject TelemetryClient into the controller, but if I use it the properties are shared between requests.
This is how I've tried to log in the controller:
private TelemetryClient telemetryClient;
public ValueController(TelemetryClient telemetryClient)
{
this.telemetryClient = telemetryClient;
}
[HttpGet]
public async Task<IActionResult> RouteOne([FromQuery(Name = "param1")]string param1, [FromQuery(Name = "param2")]string param2)
{
telemetryClient.Context.GlobalProperties["param1"] = param1;
telemetryClient.Context.GlobalProperties["param2"] = param2;
}
[HttpGet]
public async Task<IActionResult> RouteTwo([FromQuery(Name = "param3")]string param3, [FromQuery(Name = "param4")]string param4)
{
telemetryClient.Context.GlobalProperties["param3"] = param3;
telemetryClient.Context.GlobalProperties["param4"] = param4;
}
And this is the implementation of ITelemetryInitializer:
public class CustomPropertiesTelemetryInitializer : ITelemetryInitializer
{
private readonly IHttpContextAccessor httpContextAccessor;
public CustomPropertiesTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
telemetry.Context.GlobalProperties["RequestId"] = httpContextAccessor.HttpContext.GetProperty("requestId");
telemetry.Context.GlobalProperties["Ip"] = httpContextAccessor.HttpContext?.Connection.RemoteIpAddress.ToString();
telemetry.Context.GlobalProperties["RoutePath"] = httpContextAccessor.HttpContext?.Request.Path;
}
}
If the properties you added are always like "paramxxx", then there is a workaround(but it's really not very elegant).
In the controller constructor, check the GlobalProperties if it contains key like "paramxxx":
public ValueController(TelemetryClient telemetryClient)
{
this.telemetryClient = telemetryClient;
var props = this.telemetryClient.Context.GlobalProperties;
foreach (var p in props)
{
if (p.Key.Contains("param"))
{
props.Remove(p.Key);
}
}
}
The key here is to use the DI framework. You can use it to get request-scoped data or services into your ITelemetryInitializer.
(These examples are based on the standard ASP.Net Dependency Injection framework. This pattern should work with any DI framework, but will need to be adjusted slightly.)
First, create a class to represent your request-scoped telemetry. I've used a simple DTO, but this could also be a service that knows how to fetch/generate the data itself. Register it using AddScoped. "Scoped" means that a new instance will be created for each HTTP request, and then that instance will be re-used within that request.
Because I used a DTO, I didn't bother with an interface--you should use an interface if the class contains any logic you'll want to mock in unit tests.
public class RequestScopedTelemetry
{
public string MyCustomProperty { get; set; }
}
services.AddScoped<RequestScopedTelemetry>();
Now, create the ITelemetryInitializer and register it as a singleton. App Insights will discover and use it through the DI framework.
class RequestScopedTelemetryInitializer : ITelemetryInitializer
{
readonly IHttpContextAccessor httpContextAccessor;
public RequestScopedTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
=> this.httpContextAccessor = httpContextAccessor;
public void Initialize(ITelemetry telemetry)
{
// Attempt to resolve the request-scoped telemetry from the DI container
var requestScopedTelemetry = httpContextAccessor
.HttpContext?
.RequestServices?
.GetService<RequestScopedTelemetry>();
// RequestScopedTelemetry is only available within an active request scope
// If no telemetry available, just move along...
if (requestScopedTelemetry == null)
return;
// If telemetry was available, add it to the App Insights telemetry collection
telemetry.Context.GlobalProperties[nameof(RequestScopedTelemetry.MyCustomProperty)]
= requestScopedTelemetry.MyCustomProperty;
}
}
services.AddSingleton<ITelemetryInitializer, RequestScopedTelemetryInitializer>();
Finally, in your controller method, set your per-request values. This part isn't necessary if your telemetry class is able to fetch or generate the data itself.
public class ExampleController : ControllerBase
{
readonly RequestScopedTelemetry telemetry;
public ValuesController(RequestScopedTelemetry telemetry)
=> this.telemetry = telemetry;
[HttpGet]
public ActionResult Get()
{
telemetry.MyCustomProperty = "MyCustomValue";
// Do what you want to
return Ok();
}
}
In order to add per request data into telemetry, you need to have a way to share data within the request. A reliable way is by using HttpContent.Items property, which is basically a Dictionary.
You can create a service to keep a Dictionary inside HttpContent.Items with all custom data you want in telemetry (key prefix is used to ensure we only read the things we want later in Initializer):
public class LogTelemetryRequest
{
private const string KEY_PREFIX = "CustomTelemetryData_";
private readonly IHttpContextAccessor _httpContextAccessor;
public LogTelemetryRequest(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void AddProperty(string key, string value)
{
_httpContextAccessor.HttpContext.Items[KEY_PREFIX + key] = value;
}
}
Register this as scoped in Startup.cs:
services.AddScoped<LogTelemetryRequest>();
Use it in your controller:
private LogTelemetryRequest logTelemetryRequest;
public ValueController(LogTelemetryRequest logTelemetryRequest)
{
this.logTelemetryRequest = logTelemetryRequest;
}
[HttpGet]
public async Task<IActionResult> RouteOne([FromQuery(Name = "param1")]string param1, [FromQuery(Name = "param2")]string param2)
{
// telemetryClient.Context.GlobalProperties["param1"] = param1;
// telemetryClient.Context.GlobalProperties["param2"] = param2;
logTelemetryRequest.AddProperty("param1", param1);
logTelemetryRequest.AddProperty("param2", param2);
}
Then read it within initializer:
public class AddCustomTelemetryInitializer : ITelemetryInitializer
{
private const string KEY_PREFIX = "CustomTelemetryData_";
private readonly IHttpContextAccessor _httpContextAccessor;
public AddCustomTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
if (requestTelemetry == null) return;
foreach (var item in _httpContextAccessor.HttpContext.Items)
{
if (item.Key is string key && key.StartsWith(KEY_PREFIX))
requestTelemetry.Properties.Add(key, item.Value.ToString());
}
}
}
Ideally LogTelemetryRequest should be registered using an interface, and the key prefix should be a single shared constant, didn't do for the sake of simplicity.
I'm using FluentValidation with Autofac and ValidatorFactoryBase
When I execute my project my Validator is executed, but when I send a post my rules not is used but the current validator is my own Validator.
My Validator:
public class UsuarioCadastrarValidator : AbstractValidator<UsuarioCadastrarVM>
{
public UsuarioCadastrarValidator()
{
RuleFor(a => a.Nome).NotEmpty().WithMessage("Campo obrigatório");
RuleFor(a => a.Nome).Length(4, 200).WithMessage("Digite seu nome completo");
}
}
My Model:
public class UsuarioCadastrarVM
{
public string Nome { get; set; }
public int CargoId { get; set; }
}
Global.asax(Works well):
...
FluentValidationModelValidatorProvider.Configure();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Validator"))
.AsImplementedInterfaces()
.InstancePerLifetimeScope();
builder.RegisterAssemblyTypes(assembly);
builder
.RegisterType<FluentValidation.Mvc.FluentValidationModelValidatorProvider>()
.As<ModelValidatorProvider>();
builder.RegisterType<AutofacValidatorFactory>().As<IValidatorFactory>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
...
Controller(Works well):
[HttpPost]
public ActionResult Cadastrar(UsuarioCadastrarVM vm)
{
if(ModelState.IsValid)
{
}
}
My ValidatorFactoryBase (Works well):
public class AutofacValidatorFactory : ValidatorFactoryBase
{
private readonly IComponentContext _context;
public AutofacValidatorFactory(IComponentContext context)
{
_context = context;
}
public override IValidator CreateInstance(Type validatorType)
{
object instance;
if (_context.TryResolve(validatorType, out instance))
{
var validator = instance as IValidator;
return validator;
}
return null;
}
}
When I send Post with "Nome" and "CargoId" empty in ModelState has only one message "CargoId is required" and not exists that Rule, I think is because CargoId is a integer.
But, Why my Rules are not consider?
The problem was CargoId is a integer, so the MVC is not able to bind my post to my ViewModel, because in my tests I sended a empty value, if I send a value to CargoId or change to nullable (int?) the validation works well.
public class FooController : ApiController
{
private IDb db;
public FooController (IDb context)
{
db = context;
}
public void DoSomething(string value)
{
var output = new DoSomethingElse(value);
}
}
DoSomethingElse object is used by couple of methods in this class but it's not a requirement for all the methods. How do I register and resolve DoSomethingElse?
The problem as I understand it:
public class FooController : ApiController
{
private IDb db;
public FooController (IDb context)
{
db = context;
}
public void DoSomething(string value)
{
var output = new DoSomethingElse(value);
}
}
You don't want to instantiate the DoSomethingElse type everytime you instantiate the FooController. You also want to provide it with a value at run time.
So this calls for the Factory Pattern:
public interface IDoSomethingElseFactory
{
IDoSomethingElse Create(string value);
}
public class DoSomethingElseFactory : IDoSomethingElseFactory
{
public IDoSomethingElse Create(string value)
{
// Every call to this method will create a new instance
return new DoSomethingElse(value);
}
}
public class FooController : ApiController
{
private IDb db;
private readonly IDoSomethingElseFactory doSomethingElseFactory;
public FooController (
IDb context,
IDoSomethingElseFactory doSomethingElseFactory)
{
db = context;
this.doSomethingElseFactory = doSomethingElseFactory;
}
public void DoSomething(string value)
{
// this will be the point at which a brand new
// instance of `DoSomethingElse` will be created.
var output = doSomethingElseFactory.Create(value);
}
}
Then to register this:
builder.RegisterType<DoSomethingElseFactory>()
.As<IDoSomethingElseFactory>()