Autofac, OrchardProject and AsyncControllers - autofac

I'm working on trying to get an AsyncController to work in OrchardProject. The current version I'm using is 2.2.4.9.0.
I've had 2 people eyeball my code: http://www.pastie.org/2117952 (AsyncController) which works fine in a regular MVC3 vanilla application.
Basically, I can route to IndexCompleted, but I can't route to Index. I am going to assume i'm missing something in the Autofac configuration of the overall project.
I think the configuration is in the global.asax: http://pastie.org/2118008
What I'm looking for is some guidance on if this is the correct way to implement autofac for AsyncControllers, or if there is something/someplace else I need to implement/initialize/etc.
~Dan

Orchard appears to register its own IActionInvoker, called Orchard.Mvc.Filters.FilterResolvingActionInvoker.
This class derives from ControllerActionInvoker. At a guess, in order to support async actions, it should instead derive from AsyncControllerActionInvoker.
Hope this helps!
Nick

The Autofac setup looks ok, and as long as you can navigate to something I cannot say that your assumption makes sense. Also, the pattern you are using for initialization in global.asax is used by others too.
The AsyncController requires that async methods come in pairs, in your case IndexAsync & IndexCompleted. These together represent the Index action. When you say you can navigate to IndexCompleted, do you mean that you open a url "..../IndexCompleted"?
Also, and this I cannot confirm from any documentation, but I would guess that AsyncController requires that all actions are async. Thus, your NewMessage action causes trouble and should be converted to an async NewMessageAsync & NewMessageCompleted pair.

I did too needed to have AsyncController which I easily changed FilterResolvingActionInvoker to be based on AsyncControllerActionInvoker instead of ControllerActionInvoker.
But there was other problems because of automatic transaction disposal after completion of request. In AsyncController starting thread and the thread that completes the request can be different which throws following exception in Dispose method of TransactionManager class:
A TransactionScope must be disposed on the same thread that it was created.
This exception is suppressed without any logging and really was hard to find out. In this case session remains not-disposed and subsequent sessions will timeout.
So I made dispose method public on ITransactionManager and now in my AsyncController, whenever I need a query to database I wrap it in:
using (_services.TransactionManager) {
.....
}
new TransactionManager :
public interface ITransactionManager : IDependency, IDisposable {
void Demand();
void Cancel();
}
public class TransactionManager : ITransactionManager {
private TransactionScope _scope;
private bool _cancelled;
public TransactionManager() {
Logger = NullLogger.Instance;
}
public ILogger Logger { get; set; }
public void Demand() {
if (_scope == null) {
Logger.Debug("Creating transaction on Demand");
_scope = new TransactionScope(
TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = IsolationLevel.ReadCommitted
});
_cancelled = false;
}
}
void ITransactionManager.Cancel() {
Logger.Debug("Transaction cancelled flag set");
_cancelled = true;
}
void IDisposable.Dispose() {
if (_scope != null) {
if (!_cancelled) {
Logger.Debug("Marking transaction as complete");
_scope.Complete();
}
Logger.Debug("Final work for transaction being performed");
try {
_scope.Dispose();
}
catch {
// swallowing the exception
}
Logger.Debug("Transaction disposed");
}
_scope = null;
}
}
Please notice that I have made other small changes to TransactionManager.

I tried the AsyncControllerActionInvoker route as well to no avail. I would get intermittent errors from Orchard itself with the following errors:
Orchard.Exceptions.DefaultExceptionPolicy - An unexpected exception was caught
System.TimeoutException: The operation has timed out.
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.ReflectedAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass3f.<BeginInvokeAsynchronousActionMethod>b__3e(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncResultWrapper.WrappedAsyncResult`1.End()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult)
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass37.<>c__DisplayClass39.<BeginInvokeActionMethodWithFilters>b__33()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
at System.Web.Mvc.Async.AsyncControllerActionInvoker.<>c__DisplayClass4f.<InvokeActionMethodFilterAsynchronously>b__49()
NHibernate.Util.ADOExceptionReporter - While preparing SELECT this_.Id as Id236_2_, this_.Number as Number236_2_,...<blah blah blah>
NHibernate.Util.ADOExceptionReporter - The connection object can not be enlisted in transaction scope.
So I don't think just wrapping your own database calls with a transaction object will help. The innards of Orchard would have to modified as well.
Go vote for this issue if you want AsyncControllers supported in Orchard:
https://orchard.codeplex.com/workitem/18012

Related

Detecting when the database session gets refreshed on a Spring Boot 2 application

I'm trying to execute the following SQL statement every time the Database Session gets refreshed. I have a Spring Boot 2.0.1.RELEASE with JPA application and a PostgreSQL Database.
select set_config('SOME KEY', 'SOME VALUE', false);
As the PostgreSQL documentation states the is_local parameter is used to indicate that this configuration value will apply just for the current transaction -if true- or will be attached to the session (as I require) -if false-
The problem is that I'm not aware when Hibernate/Hikari are refreshing the db session, so, in practice, the application start failing when it has a couple of minutes running, as you can imagine...
My approach -that is not working yet- is to implement a EmptyInterceptor, for that I have added a DatabaseCustomizer class to inject my hibernate.session_factory.interceptor properly in a way that Spring can fill out all my #Autowires
DatabaseInterceptor.class
#Component
public class DatabaseInterceptor extends EmptyInterceptor {
#Autowired
private ApplicationContext context;
#Override
public void afterTransactionBegin(Transaction tx) {
PersistenceService pc = context.getBean(PersistenceService.class);
try {
pc.addPostgresConfig("SOME KEY", "SOME VALUE");
System.out.println("Config added...");
} catch (Exception e) {
e.printStackTrace();
}
}
}
DatabaseCustomizer.class
#Component
public class DatabaseCustomizer implements HibernatePropertiesCustomizer {
#Autowired
private DatabaseInterceptor databaseInterceptor;
#Override
public void customize(Map<String, Object> hibernateProperties) {
hibernateProperties.put("hibernate.session_factory.interceptor", databaseInterceptor);
}
}
Obviously, there is a problem with this approach because when I #Override the afterTransactionBegin method to start another transaction I get an Infinite loop.
I tried to look something inside that Transaction tx that could help to be sure that this transaction is not being generated by my own addPostgresConfig but there is not much on it.
Is there something else I could try to achieve this?
Thanks in advance,

Windows Service with DI - Repository injection

I have a Windows service that is designed for Dependency Injection. The service runs several threaded timers, each of which polls a database and sometimes processes records in it.
One of the dependencies injected into the service is a Repository object which gives the required access to the database. The repository in turn encapsulates an Entity Framework DbContext.
Currently, an instance of the repository is injected when the service starts and remains available until it stops. I don't like this for two reasons:
The DbContext lies idle most of the time but keeps a database connection open
The DbContext becomes stale; external changes to the data already read into it are not reflected
I would like to change the way the repository is managed so that each invocation of a timer's execute method gets a fresh repository instance while keeping the repository as an injectable service.
My preferred approach is to inject a RepositoryFactory object rather than the repository so that the timer execute method can create its own repository. However, although the repository instance is created successfully, and the first access to the database through it (a GET) succeeds, the next database access (another GET contained within an UPDATE method) fails as the DbContext appears to have been disposed.
Can anyone cast any light on why this is happening, and suggest a solution? I'm open to using a pattern other than Factory if it meets the instantiation requirements.
//DI configuration
public static void AddRepository(this IServiceCollection services, string connectionString)
{
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(connectionString));
services.AddScoped<IRepository, Repository>();
services.AddScoped<IRepositoryFactory, RepositoryFactory>(Factory);
}
private static readonly Func<IServiceProvider, RepositoryFactory> Factory = (_serviceProvider) =>
{
Console.WriteLine("ServiceProvider instantiated: {0}", _serviceProvider != null);
return new RepositoryFactory(_serviceProvider);
};
//Windows service constructor
public AllocationService(IRepositoryFactory factory, IMapperConfiguration mapperConfig)
{
_repositoryFactory = factory;
_mapperConfig = mapperConfig as MapperConfiguration;
InitializeComponent();
}
//Timer execution method
private void _registrationTimer_Elapsed(object stateObject)
{
EventLog.WriteEntry(Constants.AllocationSourceName, string.Format("Registration Timer Elapsed on thread {0}", Thread.CurrentThread.ManagedThreadId), EventLogEntryType.Information, (int)UseCaseType.Register);
try
{
using (var repository = _repositoryFactory.Create())
{
//query the database for Approved Assets,
var list = repository.GetRegistrations(Status.Approved);
EventLog.WriteEntry(Constants.AllocationSourceName, string.Format("{0} registrations with status=Approved", list.Count()), EventLogEntryType.Information, (int)UseCaseType.Register);
foreach (var registration in list)
{
try
{
//some processing removed here for simplicity
//update database
registration.Status = Status.Allocated;
//exception thrown here (see below)
repository.UpdateRegistration(registration);
}
catch (Exception ex)
{
//Log any problems and continue
EventLog.WriteEntry(Constants.AllocationSourceName, ex.ToString(), EventLogEntryType.Error, (int)UseCaseType.Register);
}
}
}
}
catch (Exception ex)
{
//Log any problems on saving
EventLog.WriteEntry(Constants.AllocationSourceName, ex.ToString(), EventLogEntryType.Error, (int)UseCaseType.Register);
}
}
System.ObjectDisposedException: Cannot access a disposed object.
Object name: 'MyDbContext'.
at Microsoft.Data.Entity.DbContext.get_ServiceProvider()
at Microsoft.Data.Entity.DbContext.Microsoft.Data.Entity.Infrastructure.IInfrastructure<System.IServiceProvider>.get_Instance()
at Microsoft.Data.Entity.Infrastructure.AccessorExtensions.GetService[TService](IInfrastructure`1 accessor)
at Microsoft.Data.Entity.Internal.InternalDbSet`1.<.ctor>b__2_0()
at Microsoft.Data.Entity.Internal.LazyRef`1.get_Value()
at Microsoft.Data.Entity.Internal.InternalDbSet`1.System.Linq.IQueryable.get_Provider()
at System.Linq.Queryable.Any[TSource](IQueryable`1 source, Expression`1 predicate)
at RegistryApp.Repository.Repository.ProcessAsset(Asset asset) in C:\svn\Client Applications\ITC\RegistryApp\RegistryApp.Repository\Repository.cs:line 364
at RegistryApp.Repository.Repository.UpdateAsset(Asset asset) in C:\svn\Client Applications\ITC\RegistryApp\RegistryApp.Repository\Repository.cs:line 270

Java EE6 (with JBoss7): automatically roll back the transaction

I want to test the automatically rolling back of an transaction. Therefore, I implemented a simple bean[src] that throws an system exception which should result in an automatically roll back[1]. I also implemented the interface SessionSynchronization so I can affect the rollback with the method afterCompletion. But the argument of this method is true which I expect to be false in regards to the specs[2].
Am I missing something or is this a bug in JBoss 7? I already searched the bug tracker but did not find anything ... maybe I used the wrong words?
If this is not a bug: are there any settings regarding to set the afterCompletion parameter to false if a system or an application exception occures?
[1]: "There are two ways to roll back a container-managed transaction. First, if a system exception is thrown, the container will automatically roll back the transaction. Second, by invoking the setRollbackOnly method of the EJBContext interface, the bean method instructs the container to roll back the transaction. If the bean throws an application exception, the rollback is not automatic but can be initiated by a call to setRollbackOnly." http://docs.oracle.com/javaee/6/tutorial/doc/bncij.html
[2]: "The afterCompletion method notifies a stateful session bean instance that a transaction commit protocol has completed, and tells the instance whether the transaction has been committed or rolled back." http://docs.oracle.com/javaee/6/api/javax/ejb/SessionSynchronization.html
[src]:
#Stateful
#LocalBean
public class RollbackTestBean implements RollbackTest, SessionSynchronization {
int counter = 0;
int counterBuffer = 0;
private final Logger logger = Logger.getLogger(this.getClass().getName());
#Override
public int getCounter() {
return counter;
}
#Override
public void throwSystemException() throws SystemException {
counter++;
throw new SystemException();
}
#Override
public void afterBegin() throws EJBException, RemoteException {
logger.info("[TX]: after begin");
counterBuffer = counter;
}
#Override
public void afterCompletion(boolean success) throws EJBException, RemoteException {
logger.info("[TX]: after completion: " + success);
if (!success)
counter = counterBuffer;
}
#Override
public void beforeCompletion() throws EJBException, RemoteException {
logger.info("[TX]: before completion");
}
}
There are two SystemExceptions
org.omg.CORBA.SystemException subclass of RuntimeException
javax.transaction.SystemException subclass of Exception
I hope you are using org.omg.CORBA.SystemException
EJB3.1 spec says, if its RuntimeException or ApplicationException, the transaction needs to be rolled back.
As far as I can see, ApplcationException is handled correctly in JBoss 7.1.1, but not RuntimeException.
With RuntimeException, there is a similar issue reported when remove() is called on Statefull bean, reference here. I am getting the same error message when I try to throw RuntimeException. Its fixed in Verion 7.1.3 I think. But I have not tested myself.
You can try 7.1.3, if you are looking for a fix. If you have your Exception and wants transaction rollback, use
#ApplicationException(rollback=true)
Maddy

Configuring EF to throw if accessing navigation property not eager loaded (and lazy-load is disabled)

We have a few apps that are currently using an EF model that has lazy-loading enabled. When I turn off the lazy-loading (to avoid implicit loads and most of our N+1 selects), I'd much rather have accessing a should-have-been-eager-loaded (or manually Load() on the reference) throw an exception instead of returning null (since a specific exception for this would be nicer and easier to debug than a null ref).
I'm currently leaning towards just modifying the t4 template to do so (so, if reference.IsLoaded == false, throw), but wondered if this was already a solved problem, either in the box or via another project.
Bonus points for any references to plugins/extensions/etc that can do source analysis and detect such problems. :)
I wanted to do the same thing (throw on lazy loading) for several performance-related reasons - I wanted to avoid sync queries because they block the thread, and in some places I want to avoid loading a full entity and instead just load the properties that the code needs.
Just disabling lazy loading isn't good enough because some entities have properties that can legitimately be null, and I don't want to confuse "null because it's null" with "null because we decided not to load it".
I also wanted to only optionally throw on lazy loading in some specific code paths where I know lazy loading is problematic.
Below is my solution.
In my DbContext class, add this property:
class AnimalContext : DbContext
{
public bool ThrowOnSyncQuery { get; set; }
}
Somewhere in my code's startup, run this:
// Optionally don't let EF execute sync queries
DbInterception.Add(new ThrowOnSyncQueryInterceptor());
The code for ThrowOnSyncQueryInterceptor is as follows:
public class ThrowOnSyncQueryInterceptor : IDbCommandInterceptor
{
public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
OptionallyThrowOnSyncQuery(interceptionContext);
}
public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext)
{
}
public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
OptionallyThrowOnSyncQuery(interceptionContext);
}
public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
}
public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
OptionallyThrowOnSyncQuery(interceptionContext);
}
public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext)
{
}
private void OptionallyThrowOnSyncQuery<T>(DbCommandInterceptionContext<T> interceptionContext)
{
// Short-cut return on async queries.
if (interceptionContext.IsAsync)
{
return;
}
// Throw if ThrowOnSyncQuery is enabled
AnimalContext context = interceptionContext.DbContexts.OfType<AnimalContext>().SingleOrDefault();
if (context != null && context.ThrowOnSyncQuery)
{
throw new InvalidOperationException("Sync query is disallowed in this context.");
}
}
}
Then in the code that uses AnimalContext
using (AnimalContext context = new AnimalContext(_connectionString))
{
// Disable lazy loading and sync queries in this code path
context.ThrowOnSyncQuery = true;
// Async queries still work fine
var dogs = await context.Dogs.Where(d => d.Breed == "Corgi").ToListAsync();
// ... blah blah business logic ...
}
jamesmanning, the creator of the project https://github.com/jamesmanning/EntityFramework.LazyLoadLoggingInterceptor, managed to intercept lazy-loaded calls by reading the stack trace.
So in you could create DbCommandInterceptor that does something like:
public override void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext)
{
// unfortunately not a better way to detect whether the load is lazy or explicit via interceptor
var stackFrames = new StackTrace(true).GetFrames();
var stackMethods = stackFrames?.Select(x => x.GetMethod()).ToList();
var dynamicProxyPropertyGetterMethod = stackMethods?
.FirstOrDefault(x =>
x.DeclaringType?.FullName.StartsWith("System.Data.Entity.DynamicProxies") == true &&
x.Name.StartsWith("get_"));
if (dynamicProxyPropertyGetterMethod != null)
{
throw new LazyLoadingDisallowedException();
}
I know that reading the stack trace frames can be expensive, although my guess would be that in normal circumstances where data access is occurring, the cost is negligible compared to the data access itself. However you will want to assess the performance of this method for yourself.
(As a side note, what you are after is one of the many nice features that NHibernate has had for many many years).
You shouldn't have to modify the T4. Based on mention of "T4" I'm guessing you are using EDMX. The properties window of the container has the lazyloadingenabled property. It's set to true when you create a new model. You can change it to false. T4 template will see that and add the code into the ctor.
Also if you're using Microsoft's POCO templates, they'll add the virtual keyword to your nav properties. Virtual + lazyloadingenabled is the necessary combination to get lazy loading. If you remove the virtual keyword then the property will never be lazy loaded, eve if lazyloading is enabled.
hth
julie

unable to query EntityFramework shared dbcontext reliably

I'm trying to share a simple DbContext with 4 DbSets among multiple repositories, each of my repositories inherit from this base class
public class CodeFirstRepository : IDisposable
{
private static MyContext _ctx = new MyContext();
protected MyContext Context
{
get { return _ctx; }
}
public void Dispose()
{
if (Context != null)
{
Context.Dispose();
}
}
}
Question: is this an appropriate way to share a connection between repositories?
I'm getting intermittent failures in my unit tests when accessing the various repositories. An exception is thrown from the repository method GetEntityByName
public IOfferResult GetEntityByName(string name)
{
return Context.Entities.Where(o => o.Name == name).FirstOrDefault()
}
Test method
Tests.Service.TestDelete
threw exception: System.ObjectDisposedException: The ObjectContext
instance has been disposed and can no longer be used for operations
that require a connection.
if the database already exists, the code executes as expected. it also works when i change the implementation of GetEntityByName(string name) to the following non-performant code
public IOfferResult GetEntityByName(string name)
{
foreach (OfferResult offer in Context.Offers)
{
if (offerName.ToLower() == offer.Name.ToLower())
{
return offer;
}
}
}
Question: what is going on here?
bear in mind that if the database exists when i run the tests i don't get the error at all.
tia,
jt
This problem is arising because you are treating the DbContext like a singleton by declaring it as a static field, but then you are treating it like it like a transient instance by disposing it as soon as any instance of CodeFirstRepository gets disposed. For example:
using (var r = new PersonRepository())
{
// do something
} // When you hit the end of this block, your static DbContext is disposed.
using (var r = new IOfferRepository())
{
r.GetEntityByName("test"); // this will fail because the context is still disposed.
}
You should not share contexts this way. If you really want all of your repositories to use a single instance of the DbContext, remove the call to Context.Dispose(). This would fix the problem you're getting right now, but it will likely introduce other problems in the future.
But I would strongly caution against using a single DbContext in a scenario where multiple threads could be trying to access it simultaneously. According to the DbContext specs:
Any instance members are not guaranteed to be thread safe.
You'd be better off just removing the static keyword from your field.