accessing dbcontext within an Authroization Policy Requirement Handler - asp.net-core-mvc

in a previous posting from a few years ago - Can Policy Based Authorization be more dynamic?
one of the answers offers up the following code:
Then define the handler.
public class MinimumAgeHandler : AuthorizationHandler<DataDrivenRequirement>
{
protected override void Handle(AuthorizationContext context,
DataDrivenRequirement requirement)
{
// Do anything here, **interact with DB**, User, claims, Roles, etc.
// As long as you set either:
// context.Succeed(requirement);
// context.Fail();
}
}
I am using .NET Core 3 MVC with EntityFrameworkCore. I wish to interact with a database in the Handler. The Handler is not passed a dbcontext like a Controller is. I have tried several ways to do it without any success. Does anyone know how to access a dbcontext from here?
Just so you know, the closest I came was using the following code from another post - How to access dbcontext & session in Custom Policy-Based Authorization
public class CheckAuthorizeHandler : AuthorizationHandler<CheckAuthorizeRequirement>
{
MyContext _context;
public CheckAuthorizeHandler(MyContext context)
{
_context = context;
}
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
MyRequirement requirement)
{
// Do something with _context
// Check if the requirement is fulfilled.
return Task.CompletedTask;
}
}
but got the following error: InvalidOperationException: Cannot consume scoped service 'NASAppsAdmin.Models.NASAppsDbContext' from singleton 'Microsoft.AspNetCore.Authorization.IAuthorizationHandler'.

InvalidOperationException: Cannot consume scoped service 'NASAppsAdmin.Models.NASAppsDbContext' from singleton 'Microsoft.AspNetCore.Authorization.IAuthorizationHandler'. Entity Framework contexts are usually added to the service container using the scoped lifetime, if you'd like to use database context from your handler, plese make sure your handler is not registered as singleton. – Fei Han

Related

Inject IOwinContext with Web API and Ninject

Using Web API 2 and OWIN hosting with Ninject.
I would like to inject the current IOwinContext into certain services (so I can get at the Request to get the principal to do some data filtering).
With Web Hosting I would, in the old days, simply have used HttpContext.Current but that is not an option with OWIN hosting (and good riddance).
This SO question explains how to do it with Autofac. Essentially, you create a Dependency Scope and then, on each request, calls Autofac's Registerinstance to register the current IOwinContext into that dependency scope like so:
app.Use(async (ctx, next) =>
{
// this creates a per-request, disposable scope
using (var scope = container.BeginLifetimeScope(b =>
{
// this makes owin context resolvable in the scope
b.RegisterInstance(ctx).As<IOwinContext>();
}))
{
// this makes scope available for downstream frameworks
ctx.Set<ILifetimeScope>("idsrv:AutofacScope", scope);
await next();
}
});
That is very elegant. With Ninject and the Ninject.Web.WebApi.OwinHosting I already get a named scope for each request so that plumbing is taken care of. However, I haven't been able to find any way in ninject to mirror AutoFac's RegisterInstance method: The key here is that this binding is only valid within this particular dependency scope.
I have read up on the various options around Scope but everything I have found relies on being able to declare constants or ToMethod. What I am looking to do here is to say, "okay, I now have a ninject dependency scope and if anyone asks for an IOwinContext from this scope, give them this instance that I already have.
Note
I do understand that I can get the current context from within my controller and pass it on, but that rather defeats the purpose of what I am trying to do; I want my DbContext to understand who the user is so it can filter the data. And, of course, once I can get the IOwinContext I won't actually pass that to the DbContext, rather I will use a ToMethod or similar to extract the ClaimsPrincipal but that is out of scope of this question.
DISCLAIMER: This is a hack. It works, but it feels very unclean. Use at your peril.
In essence, you can create an OwinContextHolder class, bind it InRequestScope and use a DelegatingHandler to populate it on each request. Something like this:
public class OwinContextHolder
{
public IOwinContext OwinContext { get; set; }
}
public class OwinContextHolderModule : NinjectModule
{
public override void Load()
{
// Instead of a NinjectModule you can of course just register the service
this.Kernel.Bind<OwinContextHolder>().ToSelf().InRequestScope();
}
}
Your delegating handler:
public class SetOwinContextHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var holder = request.GetDependencyScope().GetService(typeof(OwinContextHolder)) as OwinContextHolder;
if (holder != null)
{
holder.OwinContext = request.GetOwinContext();
}
return base.SendAsync(request, cancellationToken);
}
}
Finally add the DelegatingHandler to your Startup class:
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
webApiConfiguration.Routes.MapHttpRoute(...);
webApiConfiguration.MessageHandlers.Add(new SetOwinContextHandler());
app.UseNinjectMiddleware(CreateKernel);
app.UseNinjectWebApi(webApiConfiguration);
}
You can now inject OwinContextHolder into your classes.
Note that if you have your API in a separate assembly from your host, you may have problems with InRequestScope silently not working (as in, you get a different object every time you request one and no errors). If you do, see https://groups.google.com/forum/#!topic/ninject/Wmy83BhhFz8.

Problems After Disposing DbContext

I recently made changes to my MVC3 Application in attempt to properly dispose of the DbContext objects [1]. This worked great in development, but once the application was pushed to my production server, I started intermittently getting some funny exceptions which would persist until the AppPool was recycled. The exceptions can be traced back to code in my custom AuthorizeAttribute and look like:
System.InvalidOperationException: The 'Username' property on 'User' could not be set to a 'Int32' value. You must set this property to a non-null value of type 'String'.
System.InvalidOperationException: The 'Code' property on 'Right' could not be set to a 'String' value. You must set this property to a non-null value of type 'Int32'.
(Database schema looks like this: Users: [Guid, String, ...], Rights: [Guid, Int32, ...])
It is as if some "wires are getting crossed", and the application is mixing up results from the database: trying to materialize the Right result as a User and vise versa.
To manage the disposal of DbContext, I put code in to store this at a per-controller level. When the controller is disposed, I dispose the DbContext as well. I know it's hacky, but the AuthorizeAttribute uses the same context via filterContext.Controller.
Is there something wrong with handling the object lifecycle of DbContext in this manor? Are there any logical explanations as to why I am getting the crisscross exceptions above?
[1] Although I understand that it is not necessary to dispose of DbContext objects, I recently came across a number of sources stating that it was best practice regardless.
Edit (per #MikeSW's comment)
A property of the AuthorizeAttribute representing the DbContext is being set in the OnAuthorization method, when the AuthorizationContext is in scope. This property is then later used in the AuthorizeCore method.
Do you actually need to dispose the context?
According to this post by Jon Gallant who has been in touch with the Microsoft ADO.NET Entity Framework team:
Do I always have to call Dispose() on my DbContext objects? Nope
Before I talked with the devs on the EF team my answer was always a resounding “of course!”. But it’s not true with DbContext. You don’t need to be religious about calling Dispose on your DbContext objects. Even though it does implement IDisposable, it only implements it so you can call Dispose as a safeguard in some special cases. By default DbContext automatically manages the connection for you.
First i recommend that you get "really" familiar with
ASP.NET Application Life Cycle Overview for IIS 7.0 as it's fundamental to good MVC application design.
Now to try and "mimic" your code base
Let's say you have a similar custom MembershipProvider as described here https://stackoverflow.com/a/10067020/1241400
then you would only need a custom Authorize attribute
public sealed class AuthorizeByRoles : AuthorizeAttribute
{
public AuthorizeByRoles(params UserRoles[] userRoles)
{
this.Roles = AuthorizationHelper.GetRolesForEnums(userRoles);
}
}
public static class AuthorizationHelper
{
public static string GetRolesForEnums(params UserRoles[] userRoles)
{
List<string> roles = new List<string>();
foreach (UserRoles userRole in userRoles)
{
roles.Add(GetEnumName(userRole));
}
return string.Join(",", roles);
}
private static string GetEnumName(UserRoles userRole)
{
return Enum.GetName(userRole.GetType(), userRole);
}
}
which you can use on any controller or specific action
[AuthorizeByRoles(UserRoles.Admin, UserRoles.Developer)]
public class MySecureController : Controller
{
//your code here
}
If you want you can also subscribe to the PostAuthorizeRequest event and discard the results based on some criteria.
protected void Application_PostAuthorizeRequest(Object sender, EventArgs e)
{
//do what you need here
}
As for the DbContext, i have never run into your situation and yes per request is the right approach so you can dispose it in the controller or in your repository.
Of course it's recommended that you use filters and then add [AllowAnonymous] attribute to your actions.

ActionFilter for Nhibernate Transaction Management is this an ok way to go

I have the following wrapper:
public interface ITransactionScopeWrapper : IDisposable
{
void Complete();
}
public class TransactionScopeWrapper : ITransactionScopeWrapper
{
private readonly TransactionScope _scope;
private readonly ISession _session;
private readonly ITransaction _transaction;
public TransactionScopeWrapper(ISession session)
{
_session = session;
_scope = new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted});
_transaction = session.BeginTransaction();
}
#region ITransactionScopeWrapper Members
public void Dispose()
{
try
{
_transaction.Dispose();
}
finally
{
_scope.Dispose();
}
}
public void Complete()
{
_session.Flush();
_transaction.Commit();
_scope.Complete();
}
#endregion
}
In my ActionFilter I have the following:
public class NhibernateTransactionAttribute : ActionFilterAttribute
{
public ITransactionScopeWrapper TransactionScopeWrapper { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
TransactionScopeWrapper.Complete();
base.OnActionExecuted(filterContext);
}
}
I am using Castle to manage my ISession using a lifestyle of per web request:
container.Register(
Component.For<ISessionFactory>().UsingFactoryMethod(
x => x.Resolve<INHibernateInit>().GetConfiguration().BuildSessionFactory()).LifeStyle.Is(
LifestyleType.Singleton));
container.Register(
Component.For<ISession>().UsingFactoryMethod(x => container.Resolve<ISessionFactory>().OpenSession()).
LifeStyle.Is(LifestyleType.PerWebRequest));
container.Register(
Component.For<ITransactionScopeWrapper>().ImplementedBy<TransactionScopeWrapper>().LifeStyle.Is(
LifestyleType.PerWebRequest));
So now on to my questions.
Any issues with managing the transaction this way
Does an ActionFilter OnActionExecuting and OnActionExecuted methods use the same thread.
I ask number 2 because BeginRequest and EndRequest are not guaranteed to operate on the same thread and if you toss transactions on them you will run into big problems.
In my ActionFilter TransactionScopeWrapper is property injected.
There are some other aspects you should also look into.
First I would say is to decide where to dispose of your transaction. Be aware that if you use lazy loading and pass a data entity back to your view and access a property or reference that is configured to be lazy loaded, you'll encounter problems because your transaction has already been closed in your OnActionExecuted. Though as much as I know you should only use viewmodels in your views, sometimes an entity is a little more convenient. Regardless of the reason if you do want to use lazy loading and access them in your views you'll have to move your transaction completion into the OnResultExecuted method so that it doesn't get prematurely committed.
Second you should also look into checking if there were any exceptions or model errors before committing your transaction. I ended up using inspiration from here and here for my final Filter for dealing with my nHibernate Transaction.
Third, if you decide to dispose of your transaction in the OnResultExecuted handler that you do not do so if it's a request for a child actions. The reason being that like you I scoped my session to the web request, but I found that child actions don't count as a new request and when they are called and they try to open their own session they were getting the already open session context instead. When the child action then completed it was trying to close ITS session but was actually closing the session used by the parent view as well. This caused any logic after the child action that relied on lazy loaded data to fail as well.
I'd like to go through and try to remove my lazy loaded data from my app when it comes to views but until I get the time to do so you should be aware of these issues that may come up.
I was going to post my own action filter when I realized I had some DRY issues I needed to fix. suffice to say I am checking that filterContext.Exception and filterContext.ExceptionHandled to see if there were any errors and if they have been handled already. Note that just because an exception was handled doesn't mean that your transaction is OK to be committed. And though this is more subjective to how your app is coded you may also want to check filterContext.Controller.ViewData.ModelState.IsValid before your commit your transaction as well.
UPDATE: Unlike you, I'm using StructureMap, not Castle for Dependency Injection but in my case I added this line to my Application_EndRequest method in the gobal.asax file as a final bit of cleanup. I'm assuming there is something similar in Castle?
StructureMap.ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
UPDATE 2: Anyway, a more direct answer to your question. I don't see anything wrong with using a wrapper like you opt'd to, though I am not sure why you feel the need to wrap it? nHibernate does a really good job of handling the transaction itself so another abstraction layer around that seems unneeded to me. You could just as easily explicitly start the transaction in your OnActionExecuting and explicitly complete it in the OnActionExecuted. By retrieving the ISession object through the DependencyResolver you eliminate any concerns you may have with threading as the IoC container is thread-safe I believe, and from there you can get your current transaction using Session.Transaction and check it's current state from the IsActive property. My understanding is that it's possible for the two methods to occur on different threads though, particularly when dealing with an action on a class inheriting from AsynController.
I've got a problem with a such method. What it do if you use "#Html.Action("TestMethod", "TestController")" ?
As for me I prefer to use explicit transaction call:
using (var tx = session.BeginTransaction())
{
// perform your insert here
tx.Commit();
}
What's about threadsafe, I'd like to know too.

Mvc3 custom event hooks

I have a Mvc3-Project where I want to register to custom event hooks.
So that I can register to an event like "User logon". I do not want to do it in the controller, because there is a business logic behind it in an other project.
So in my Mvc3-Project I want to write some classes that will have the code that has to be executed when a User is loged on. But how do I register these classes (or an instance of them) to the event. Is it a good idea to use reflection an search for all classes inherited from a special base class, or is there an other smarter way?
So again, I do not want to monitor the action that is called, I want that the business logic triggers some classes in my Mvc3-Project.
EDIT
As Chris points out in the comments below, MVC3 is stateless, meaning that with this solution you would have to resubscribe for these events on every request. This is probably not a very good solution for MVC.
Have you considered an global event service?
Rough example:
class Example : IEventReceiver
{
public void Init()
{
EventService.Subscribe("Logon", this);
}
private void OnEvent(string eventName)
{
// Do logon stuff here.
}
}
You would need to create the EventService class, which might be a singleton or service. It might have interface similar to the following:
public interface IEventService
{
void Subscribe(string eventName, IEventReceiver receiver);
void Unsubscribe(string eventName, IEventReceiver receiver);
void DispatchEvent(string eventName);
}
public interface IEventReceiver
{
void OnEvent(string eventName);
}

ASP.NET MVC 3: Validating model when information external to the model is required

What's a good way to validate a model when information external to the model is required in order for the validation to take place? For example, consider the following model:
public class Rating {
public string Comment { get; set; }
public int RatingLevel { get; set; }
}
The system administrator can then set the RatingLevels for which a comment is required. These settings are available through a settings service.
So, in order to fully validate the model I need information external to it, in this case the settings service.
I've considered the following so far:
Inject the service into the model. The DefaultModelBinder uses System.Activator to create the object so it doesn't go through the normal dependency resolver and I can't inject the service into the model without creating a new model binder (besides which, that doesn't feel like the correct way to go about it).
Inject the service into an annotation. I'm not yet sure this is possible but will investigate further soon. It still feels clumsy.
Use a custom model binder. Apparently I can implement OnPropertyValidating to do custom property validation. This seems the most preferable so far though I'm not yet sure how to do it.
Which method, above or not, is best suited to this type of validation problem?
Option 1 doesn't fit. The only way it would work would be to pull in the dependency via the service locator anti-pattern.
Option 2 doesn't work. Although I couldn't see how this was possible because of the C# attribute requirements, it is possible. See the following for references:
Resolving IoC Container Services for Validation Attributes in ASP.NET MVC
NInjectDataAnnotationsModelValidatorProvider
Option 3: I didn't know about this earlier, but what appears to be a very powerful way to write validators is to use the ModelValidator class and a corresponding ModelValidatorProvider.
First, you create your custom ModelValidatorProvider:
public class CustomModelValidatorProvider : ModelValidatorProvider
{
public CustomModelValidatorProvider(/* Your dependencies */) {}
public override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context)
{
if (metadata.ModelType == typeof(YourModel))
{
yield return new YourModelValidator(...);
}
}
}
ASP.NET MVC's IDependencyResolver will attempt to resolve the above provider, so as long as it's registered with your IoC container you won't need to do anything else. And then the ModelValidator:
public class EntryRatingViewModelValidatorMvcAdapter : ModelValidator
{
public EntryRatingViewModelValidatorMvcAdapter(
ModelMetadata argMetadata,
ControllerContext argContext)
: base(argMetadata, argContext)
{
_validator = validator;
}
public override IEnumerable<ModelValidationResult> Validate(object container)
{
if (/* error condition */)
{
yield return new ModelValidationResult
{
MemberName = "Model.Member",
Message = "Rating is required."
};
}
}
}
As the provider is retrieved through the IDependencyResolver and the provider has full control over the returned ModelValidators I was easily able to inject the dependencies and perform necessary validation.
You could try fluent validation. It supports asp.net mvc and DI so you can inject external services into your validators.
Assuming that you want both client and server-side validation of the model based upon the values returned from the service, I would opt for 2., Inject the service into an annotation.
I give some sample code in my response to this question about adding validators to a model. The only additional step in your case is that you will need to inject your service into your class inheriting from DataAnnotationsModelValidatorProvider.
What about just simply using IValidateableObject and in that method determine if validation is appropriate or not and setting the errors there?
How do I use IValidatableObject?

Resources