ActionFilter for Nhibernate Transaction Management is this an ok way to go - asp.net-mvc-3

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.

Related

accessing dbcontext within an Authroization Policy Requirement Handler

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

How to rollback transaction invoked with jpa entity listeners

I'm using jpa , spring data and entity listeners to audit my entities precisely on postUpdate , postPersist , PostRemove
This is a pseudo code of my entity listener class
public class EntityListener extends AuditingEntityListener {
#PostUpdate
public void postPersist(Object auditedEntity) {
writer.saveEntity(auditedEntity,"UPDATE");
}
This the pseudo code of the Writer class
public class Writer {
#Async
public void saveEntity(Object auditedEntity, String action) {
try {
//some code to prepare the history entity
historyDAO.save(entity);
} catch (Exception e) {
}
}
when an exception is thrown in Writer class , the auditedEntity is updated or inserted however the historyEntity where i store the audit action doesnt
The problem is i need to invoke the saveEntity method in another thread for performance issue (#Async) but in that case a new transaction is open instead of the previously one which opened
how can i solve the rollack issue for both transactions
so when an exception is throwen both historyEntity and auditedEntity not persisted
I understand that you want to rollback both the child and the parent transaction when an exception is thrown from within Writer.saveEntity.
The problem is that the thread with the original transaction would still need to wait for all these complicated operations to finish before it could mark the transaction as committed. You can't easily span a transaction across multiple threads, either.
The only thing you could probably do to speed things up is you could run the logic of generating the history entities in parallel, and then save them all just before the transaction commits.
One way of doing that that I can think of is using a Hibernate interceptor:
public class AuditInterceptor extends EmptyInterceptor {
private List<Callable<BaseEntity>> historyEntries;
private ExecutorService executor;
...
public void beforeTransactionCompletion(Transaction tx) {
List<Future<BaseEntity>> futures = executor.invokeAll(historyEntries);
if (executor.awaitTermination(/* some timeout here */)) {
futures.stream().map(Future::get).forEach(entity -> session.save(object));
} else {
/* rollback */
}
}
}
Your listener code then becomes:
#PostUpdate
public void postPersist(Object auditedEntity) {
interceptor.getHistoryEntries().add(new Callable<BaseEntity> {
/* history entry generation logic goes here */
});
}
(note that the above code is greatly simplified, you could use any other asynchronous execution API, the basic idea is that you need to block in AuditInterceptor.beforeTransactionCompletion, waiting for all the history entries to be generated)
However, I would strongly advise against using the above technique, as it is rather complicated and error prone.
If you look here: https://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/events/Events.html, you'll find that Hibernate interceptors have more interesting methods that could help you gather auditing info, and that perhaps your implementation could make use of them, possibly avoiding the need for complicated logic altogether (Hibernate already does track changes to fields of individual entities, so you get that information for free).
Why reinvent the wheel, though? If you dig even deeper, you'll find the Hibernate Envers module (http://hibernate.org/orm/envers/, works for both JPA and pure Hibernate) which gives you business auditing out of the box. Envers already digs into the above mechanism, so hopefully the performance issue would go away.
Final note: have you measured how long history entry generation takes? I would guess that executing for loops and if statements might be cheaper than database access operations. If I were you, I wouldn't do any of the above unless I was absolutely sure that's where the performance bottleneck was.

Apache Wicket: Injecting dependencies in Session (using Guice)

I'm using the Wicket Auth/Roles and I ran into the same problem as the OP of this thread.
I need to access the DB service layer in the AuthenticatedWebSession (for user authentication). I followed Steve Flasby's suggestion and did the following:
#Override
public Session newSession(Request request, Response response) {
Session s = new MySession(request);
mInjector.inject(s);
return s;
}
Unfortunately this results in
java.lang.IllegalStateException: EntityManager is closed
(presumably due to the fact that (a) I'm using open session in view, and (b) the session spans over several requests).
I solved this by moving the injection into the AuthenticatedWebSession.authenticate method.
#Override
public boolean authenticate(String username, String pass) {
Injector.get().inject(this);
...
}
I suspect that this is not best practice, because now I need to access to the service layer in other methods too, and it doesn't seem like a good idea to add Injector.get().inject(this) in each such method.
My question:
How do I perform injection into the session object upon each request? (Or, if this is a bad approach all together, how do I access the service layer in the AuthenticatedWebSession?)
You can implement IRequestCycleListener (extend AbstractRequestCycleListener) and implement:
#Override
public void onBeginRequest(RequestCycle cycle)
{
if (Session.exists()) {
Injector.get().inject(Session.get());
}
}
Register your IRequestCycleListener in Application#init() with getRequestCycleListeners().add(new YourRequestCycleListener()).

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.

nHibernate [TransactionAttribute] for UoW conflicts with Repository Pattern

Doing research into the best way to design IRepository<T> structures, I came across a project called 'Whiteboard' (http://whiteboardchat.codeplex.com/) while looking through some forums for NHProf.
I dug around its source code for a while, and found a really interesting attribute for MVC called TransactionAttribute, defined as follows; (I have made brief adjustment to suit my IoC solution)
using System;
using System.Linq;
using Ninject;
namespace System.Web.Mvc
{
/// <summary>
/// This will allow ASP.NET MVC to apply Transactions to the controllers.
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : ActionFilterAttribute
{
[Inject]
public NHibernate.ISession Session
{
get;
set;
}
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
Session.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (Session.Transaction.IsActive)
{
if (filterContext.Exception == null)
{
Session.Flush();
Session.Transaction.Commit();
}
else
{
Session.Transaction.Rollback();
}
}
}
}
}
This is really interesting; And useful, however something about it bothers me. When I run my queries using NHProf, it gives me warnings about 'Not using transactions properly', and suggests I wrap all queries in a Transaction. Alright, that's fine and good...
So then I go and decorate my Repository<T> : IRepository<T> class like this ...
public T Update(T instance)
{
using (var transaction = session.BeginTransaction())
{
// attempt to perform the given update
session.SaveOrUpdate(instance);
try
{
// commit the transaction to the database
transaction.Commit();
// update succeeded, so we'll return true
return instance;
}
catch
{
// restore the database to its previous state if we failed.
transaction.Rollback();
// update failed, so return a null object
return default(T);
}
}
}
Here's the problem I am running into.
Everywhere I read, the common practice is to always use a Repository for adding to the collections. However the TransactionAttribute, which in itself was brought to my attention by Ayende Rahien's blog, who is from what I can gather one of the primary developers of NHProf, and one of the people working on this Whiteboard project, makes the assumption that you are performing Repository commands at the MVC Controller Level.
So which is it? I'm utterly confused now where my Transaction logic is supposed to go for the best practice. I'm literally finding conflicting answers, and in some cases from the same people.
You are not supposed to deal with transactions inside repositories. A controller (like you have) or HTTP module should start and commit/rollback transactions. Saves or updates are not supposed to be done in isolation. They will be committed at the end of the operation by the controller. This way you can take advantage of ADO batching and other NHibernate features.
Also, make sure to set the FlushMode of the nhibernate ISession to Commit.
Are you decorating your action method or controller class with the [Transaction] attribute? If not, this action filter code won't even be called.
Also, you will need to ensure that you [Inject] the session object into your repository as well and that the session object is scoped to the request.
as an example:
public class MyRepository
{
[Inject]
public ISession Session { get; set; }
public void Save(MyModel model) { Session.Save(model); }
}
public class MyController : Controller
{
[Inject]
public MyRepository MyRepository { get; set; }
[Transaction]
public ActionResult Save(MyModel model)
{
MyRepository.Save(model);
}
}
and when registering your session;
var configuration = new NHibernateConfiguration();
Bind<ISessionFactory>().ToConstant(configuration.GetSessionFactory());
Bind<ISession>().ToMethod(x => x.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope();
notice the InRequestScope() part
Posting this for #Fatal.
The original response answered my question, but this is inevitably what I ended up doing to avoid using method level attributes.
Instead of declaring the code to control my transaction in an attribute, I included it right in my ISession management for Ninject.
Bind<ISession>()
.ToMethod(c => OpenSession())
.InRequestScope()
.OnActivation(session =>
{
session.BeginTransaction();
session.FlushMode = FlushMode.Commit;
})
.OnDeactivation(session =>
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
});
What this does is open the new ISession each request where an ISession is injected, and when it is activated it begins a new transaction. At this point, Ninject now tracks the state and handles the consequences of rolling it back, thus implementing a very simplistic unit of work pattern.
I do not know if this is the best approach in the world, but I have shown it to a few people and it has not been shot down for bad practice, and it has worked well for me so far.

Resources