How to pass parameter of different type to a generic ServiceFilter or ActionFilter

I am not very experienced on C# and ASP, and I am not sure I am taking the right approach to this problem.

This is a brief representation of it:

I have several endpoints related to an user but with different parameters (eg. string or UserDTO)
Here are a couple of them:

[AllowAnonymous]
[HttpPut("{username}")]
// I want to pass [FromBody]UserUpdateDTO to the filter
[ServiceFilter(typeof(UserChangeManagerFilter<UserUpdateDTO>))]
public ActionResult<InternalStatus> UpdateUser([FromBody]UserUpdateDTO userDto)
{
...
}

[AllowAnonymous]
[HttpDelete("{username}")]
// I want to pass {username} to the filter 
[ServiceFilter(typeof(UserChangeManagerFilter<string>))]
public ActionResult<InternalStatus> DeleteUser(string username)
{
...
}

Now, I need to execute some code after each action is executed. For this, I have created a generic filter
My problem is that the filter needs to know the user details, so the PUT endpoint has to pass the UserDTO element to the filter, and the DELETE endpoint has to pass the username. I don’t know how to do that exactly, but researching, I have seen that using a generic sercive filter was an option. So I created this one:

namespace ActionFilters.ActionFilters
{
    public class UserChangeManagerFilter<T> : IActionFilter
    {
        private UserInfo _user;

        public UserChangeManagerFilter(UserUpdateDTO userContext)
        {
            _user.Username = userContext.Username;
            _user.Firstname = userContext.FirstName; 
            ...
        }
        public UserChangeManagerFilter(string username)
        {
            _user.Username = username;
            _user.Firstname = ""; 
            ...
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {

        }
        public void OnActionExecuted(ActionExecutedContext context)
        {
              // Do whatever I need to do here
        }
}

I am adding the service in Startup.cs as below:

services.AddScoped<UserChangeManagerFilter<UserUpdateDTO>>();
services.AddScoped<UserChangeManagerFilter<string>>();

When I execute the PUT endpoint, I get

System.InvalidOperationException: No constructor for type 'ActionFilters.ActionFilters.UserChangeManagerFilter`1[xxx.Services.UserUpdateDTO]' can be instantiated using services from the service container and default values.

When I execute the DELETE endpoint I get

System.InvalidOperationException: No constructor for type 'ActionFilters.ActionFilters.UserChangeManagerFilter`1[System.String]' can be instantiated using services from the service container and default values.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

I know this is not a direct answer to your question but how about using a non generic filter and then using the OnActionExecuting to inspect the model being passed and extracting the data as needed depending on the type of object received:

   public void OnActionExecuting(ActionExecutingContext context)
   {
       var userDto = actionContext.ActionArguments.Values.OfType<UserUpdateDTO>().Single();
       if(userDto !=null)
       {
           _user.Username = userContext.Username;
           _user.Firstname = userContext.FirstName;
           ...
       }else
       {
           //look for the string value
       }
   }


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x