Is there a way to create an ActionFilter that wraps the contents of an Action in a using statement?

My scenario: My application is a Web Api 2 application that uses a layer of business logic and a repository to access data. The web application uses ASP.NET impersonation to enter the database as the user accessing the website (authenticated through PKI). I have several asynchronous controller methods. However, when I'm awaitin data access methods, the database call may end in another thread, which will then access the database under the identifier of my application pool, which cannot connect to the database.

Example Controller :

public class TestApiController : ApiController {
    private IBusinessLogicObject _myBlObject;

    public TestApiController(IBusinessLogicObject myBlObject){
        _myBlObject = myBlObject; //Populated through Unity
    }

    public async Task<int> CountMyJobs(string name){
        return await _myBlObject.CountMyJobsAsync(name);
    }
}

Example business logic :

public class BusinessLogicObject : IBusinessLogicObject
{
    private IGenericRepository<Job> _jobRepository;

    public BusinessLogicObject(IGenericRepository<Job> _jobRepository)
    {
        _jobRepository = jobRepository; //Populated with Unity
    }

    public Task<int> CountMyJobsAsync(string name)
    {
        using (WindowsIdentity.GetCurrent().Impersonate())
        {
            //JobRepository is effectively a DbSet<Job> and this call returns IQueryable<Job>
            return _jobRepository.Where(i => i.Name == name).CountAsync();
        }        
    }
}

using ( ), .

, , await , (CountAsync()), .

:

ActionFilter - , ( ) using?

+4
3

merpmerp . ActionFilterAttribute, , , .

ImersonationContext - . filterContext.Request.Properties.

+2

, using , , OnActionExecuting OnResultExecuted ActionFilter.

public class IdentityImpersonateActionFilter : ActionFilterAttribute
{
    IDisposable usingVaribale;

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        usingVaribale = WindowsIdentity.GetCurrent().Impersonate();
    }

    public override void OnResultExecuted(ResultExecutedContext filterContext)
    {
        usingVaribale.Dispose();
    }
}

[IdentityImpersonate]

[IdentityImpersonate]    
public Task<int> CountMyJobsAsync(string name)
{
    //JobRepository is effectively a DbSet<Job> and this call returns IQueryable<Job>
    return _jobRepository.Where(i => i.Name == name).CountAsync();  
}

,

public override void OnActionExecuting(ActionExecutingContext filterContext)
{
    usingVaribale = WindowsIdentity.GetCurrent().Impersonate();
    filterContext.ActionParameters.Add("parameterName", usingVaribale);
}

[IdentityImpersonate]    
public Task<int> CountMyJobsAsync(object parameterName, string name)
{
    //JobRepository is effectively a DbSet<Job> and this call returns IQueryable<Job>
    return _jobRepository.Where(i => i.Name == name).CountAsync();  
}

, !

+1

If you want to maintain the personalization of business logic, you can simply do this:

public async Task<int> CountMyJobsAsync(string name)
{
    using (WindowsIdentity.GetCurrent().Impersonate())
    {
        return await _jobRepository.Where(i => i.Name == name).CountAsync()
            .ConfigureAwait(false);
    }
}
0
source

Source: https://habr.com/ru/post/1538110/


All Articles