MVC - Simple Injector and Attribute calling the Context (EF) Throwing exceptions - asp.net-mvc

If I start my application and let it settle, it works great.
However, when I debug my application and if I close the browser tab before it initializes anything and then call another like localhost:81/Home/Test, it throws an exception on retrieving data from DB (EF).
This exception occurs during a call to a Filter CultureResolver which then calls LanguageService. Inside LanguageService there is a call to the DB to retrieve all the available languages.
I got many different exceptions, like:
The context cannot be used while the model is being created. This
exception may be thrown if the context is used inside the
OnModelCreating method or if the same context instance is accessed by
multiple threads concurrently. Note that instance members of
DbContext and related classes are not guaranteed to be thread safe.
Object reference not set to an instance of an object.
The underlying provider failed on Open.
Those exceptions occur all in the same query, it depends on how much time I left the first tab running.
So it seems it's something like Thread-Unsafe code or this query trying to get items before the Context is initialized.
I've the following:
SimpleInjectorInitializer.cs
public static class SimpleInjectorInitializer
{
/// <summary>Initialize the container and register it as MVC3 Dependency Resolver.</summary>
public static void Initialize()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters, container);
}
private static void InitializeContainer(Container container)
{
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
/* Bindings... */
container.RegisterPerWebRequest<IAjaxMessagesFilter, AjaxMessagesFilter>();
container.RegisterPerWebRequest<ICustomErrorHandlerFilter, CustomErrorHandlerFilter>();
container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>();
}
}
FilterConfig.cs
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters, Container container)
{
filters.Add(container.GetInstance<ICultureInitializerFilter>());
filters.Add(container.GetInstance<ICustomErrorHandlerFilter>());
filters.Add(container.GetInstance<IAjaxMessagesFilter>());
}
}
CultureResolver.cs
public class CultureResolver : ICultureResolver
{
ILanguageService Service;
public CultureResolver(ILanguageService Service)
{
this.Service = Service;
}
public string Resolve(string CultureCode)
{
// Get the culture by name or code (pt / pt-pt)
ILanguageViewModel language = Service.GetByNameOrCode(CultureCode);
if (language == null)
{
// Get the default language
language = Service.GetDefault();
}
return language.Code;
}
}
LanguageService.cs
public class LanguageService : ILanguageService
{
IMembership membership;
ChatContext context;
ILanguageConverter converter;
public LanguageService(
ChatContext context,
IMembership membership,
ILanguageConverter converter
)
{
this.membership = membership;
this.context = context;
this.converter = converter;
}
public virtual ILanguageViewModel GetByNameOrCode(string Text)
{
string lowerText = Text.ToLower();
string lowerSmallCode = "";
int lowerTextHiphen = lowerText.IndexOf('-');
if (lowerTextHiphen > 0)
lowerSmallCode = lowerText.Substring(0, lowerTextHiphen);
Language item = this.context
.Languages
.FirstOrDefault(x => x.Code.ToLower() == lowerText
|| x.SmallCode.ToLower() == lowerText
|| x.SmallCode == lowerSmallCode);
return converter.Convert(item);
}
public virtual ILanguageViewModel GetDefault()
{
Language item = this.context
.Languages
.FirstOrDefault(x => x.Default);
return converter.Convert(item);
}
}
This is the query that is giving me the exceptions
Language item = this.context
.Languages
.FirstOrDefault(x => x.Code.ToLower() == lowerText
|| x.SmallCode.ToLower() == lowerText
|| x.SmallCode == lowerSmallCode);

Global filters in MVC and Web API are singletons. There is only one instance of such filter during the lifetime of your application. This becomes obvious when you look at the following code:
filters.Add(container.GetInstance<ICultureInitializerFilter>());
Here you resolve the filter once from the container and store it for the lifetime of the container.
You however, have registered this type as Scoped using:
container.RegisterPerWebRequest<ICultureInitializerFilter, CultureInitializerFilter>();
You are effectively saying that there should be one instance per web request, most likely because that class depends on a DbContext, which isn't thread-safe.
To allow your filters to have dependencies, you should either make them humble objects, or wrap them in a humble object that can call them. For instance, you can create the following action filter:
public sealed class GlobalActionFilter<TActionFilter> : IActionFilter
where TActionFilter : class, IActionFilter
{
private readonly Container container;
public GlobalActionFilter(Container container) { this.container = container; }
public void OnActionExecuted(ActionExecutedContext filterContext) {
container.GetInstance<TActionFilter>().OnActionExecuted(filterContext);
}
public void OnActionExecuting(ActionExecutingContext filterContext) {
container.GetInstance<TActionFilter>().OnActionExecuting(filterContext);
}
}
This class allows you to add your global filters as follows:
filters.Add(new GlobalActionFilter<ICultureInitializerFilter>(container));
filters.Add(new GlobalActionFilter<ICustomErrorHandlerFilter>(container));
filters.Add(new GlobalActionFilter<IAjaxMessagesFilter>(container));
The GlovalActionFilter<T> will callback into the container to resolve the supplied type every time it is called. This prevents the dependency from becoming captive which prevents the problems you are having.

Related

Cannot get a working Unity Session Lifetime Manager, ASP.NET MVC5

I've read and Googled everything on this, but can't seem to get it to work. I created a custom LifetimeManager for Unity in my MVC5 application based on these posts:
MVC3 Unity Framework and Per Session Lifetime Manager
This may be the issue I am experiencing
Here is my SessionLifetimeManager
public class SessionLifetimeManager : LifetimeManager
{
private string key = Guid.NewGuid().ToString();
public override object GetValue()
{
return HttpContext.Current.Session[key];
}
public override void RemoveValue()
{
HttpContext.Current.Session.Remove(key);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Session[key] = newValue;
}
}
I only have a few types I'm playing with, here is the relevant registrations in UnityConfig.cs:
container.RegisterType<IEpiSession, EpiSession>(new SessionLifetimeManager(),
new InjectionConstructor(config.AppServerURI, config.PathToSysConfig));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
Note that the EpicorReportRepository has a dependency on IEpiSession via constructor injection.
public class EpicorReportRepository : IReportRepository
{
private IEpiSession session;
// DI constructor
public EpicorReportRepository(IEpiSession session) {
this.session = session;
}
// ...
}
My Problem: After the first user / session connects to the application, every new user / session after that seems to still be using the EpiSession object and credentials that the first user had create/injected for him. This seems to be a common pattern used on the interwebs, so I'm wondering what I am missing.
How did you test that IEpiSession is the same in different Sessions?
Try to open you application from different browsers. If you open several tabs in the same browser then the same session is used.
I checked your code and it works for me.
There is the only one difference in SetResolver():
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
The full registration code is the following:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
...
var container = new UnityContainer();
container.RegisterType<IEpiSession, EpiSession>(
new SessionLifetimeManager(),
new InjectionConstructor("config.AppServerURI", "config.PathToSysConfig"));
container.RegisterType<IReportRepository, EpicorReportRepository>(new TransientLifetimeManager());
DependencyResolver.SetResolver(
type => container.Resolve(type),
types => container.ResolveAll(types));
}
}

Extending ActionDescriptorFilterProvider to allow dependency injection of class level filters

Following up on Authorization Filter Dependency Injection with ASP.New MVC 4 Web Api . Is there a way to use dependency injection on filters that are set globally on all controller classes:
config.Filters.Add(new WebApplicationApiAuthorizeAttribute());
It looks like the GetFilters method in the ActionDescriptorFilterProvider only works on method level filters.
public class UnityWebApiFilterAttributeFilterProvider : ActionDescriptorFilterProvider,
System.Web.Http.Filters.IFilterProvider
{
private readonly IUnityContainer _container;
public UnityWebApiFilterAttributeFilterProvider(IUnityContainer container)
{
_container = container;
}
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration,
HttpActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(configuration, actionDescriptor);
this.BuildUpAttributes(filters);
return filters;
}
private void BuildUpAttributes(IEnumerable filterInfo)
{
foreach (FilterInfo filter in filterInfo)
{
object o = _container.BuildUp(filter.GetType(), filter);
}
}
}
If you want these global filters to get injected, you will have to resolve them from the container and add them to the filters collection:
GlobalFilters.Filters.Add(container.Resolve<MyFilter>());
Or do something like:
var filter = WebApplicationApiAuthorizeAttribute();
container.BuildUp(filter.Gettype(), filter);
GlobalFilters.Filters.Add(filter);
But one big warning about using global filters. Global filters are... global. Or in IoC terminology: they are singletons. This means that all its dependencies will effectively become singletons as well, which might cause all sorts of concurrency bugs when they are not expected to live for the duration of the application.
So you should only do this when all the filter's direct and indirect dependencies are singletons, which is great if you can do this, but often isn't the case. So another option is to create a proxy that allows resolving the real instance on the fly:
public sealed class UnityActionFilterProxy<TActionFilter> : IActionFilter
where TActionFilter : IActionFilter
{
private readonly IUnityContainer container;
public UnityActionFilterProxy(IUnityContainer container) {
this.container = container;
}
public Task<HttpResponseMessage> ExecuteActionFilterAsync(HttpActionContext context,
CancellationToken token, Func<Task<HttpResponseMessage>> continuation) {
return this.container.Resolve<TActionFilter>().ExecuteActionFilterAsync(
context, token, continuation);
}
public bool AllowMultiple { get { return false; } }
}
This proxy can be injected as singleton in the global filters collection as follows:
GlobalFilters.Filters.Add(
container.Resolve<UnityActionFilterProxy<MyFilter>>());
The global filters isn't the only place in Web API where the design is a bit... smelly. Take a look at this related question about DelegatingHandlers.

Resolving Unity dependency outside of application start, in libraries

I'm building an ASP.NET MVC app, and implementing Dependency Injection for the first time using Unity. For one particular interface, I've multiple types registered, like so:
container.RegisterType<ICache, AppfabricCache>("AppfabricCache", new ContainerControlledLifetimeManager());
container.RegisterType<ICache, MemoryCache>("MemoryCache", new ContainerControlledLifetimeManager());
I now need to make a decision on which one to use based on a CacheType enum.
I can implement it as follows, as is done in the Sixeyed.Caching project, but it makes you register types in different places. Also you now have a static wrapper around the container, which doesn't feel clean.
public static class Cache
{
private static readonly IUnityContainer _container;
static Cache()
{
_container = new UnityContainer();
_container.RegisterType<ICache, MemoryCache>("MemoryCache", new ContainerControlledLifetimeManager());
}
public static ICache Get(CacheType cacheType)
{
ICache cache = new NullCache();
switch(cacheType)
{
case CacheType.Memory:
cache = _container.Resolve<ICache>("MemoryCache");
break;
...
...
}
}
}
How do I get hold of the container from other library projects in my application? Or rather, how do I do this kind of resolution from libraries? Or maybe I should not?
This blog post says it is not a good idea to have the container outside of the application entry point, which sounds correct. What is the correct way to do this?
As #ploeh suggests, the container shouldn't be known outside of the application root.
To get an implementation based on a runtime value, you should use a factory:
public class CacheFactory : ICacheFactory
{
private readonly IUnityContainer _container;
public CacheFactory(IUnityContainer container)
{
if (container == null)
throw new ArgumentNullException("container");
_container = container;
}
public ICache Get(CacheType cacheType)
{
// implementation as in your post
}
}
public class SomethingUsingTheCache
{
private readonly ICacheFactory _cacheFactory;
public SomethingUsingTheCache(ICacheFactory cacheFactory)
{
if (cacheFactory == null)
throw new ArgumentNullException("cacheFactory");
_cacheFactory = cacheFactory;
}
public void DoStuff()
{
// get from config or wherever
CacheType cacheType = CacheType.Memory;
ICache cache = _cacheFactory.Get(cacheType);
// do something with cache
}
}
The factory is placed in the application root and any other class uses the factory and has no notion of the container.

Linq to SQL ObjectContext in Web App - Thread Safety Concern

Busy doing some work on an existing web app and concerned about the thread safety of the ObjectContext being used in a BaseRepository class. The code that is causing my spidey sense to tingle is:
// within base repository
private SiteDataContext context;
public SitepDataContext Context
{
get
{
if (context == null)
context = new SiteDataContext();
return context;
}
}
// inherited repository
public class InheritedRepository1 : BaseRepository
{
public SomeEntity Get()
{
var something = Context.SomeEntity.First();
}
}
public class InheritedRepository2 : BaseRepository
{
public SomeOtherEntity Get()
{
var something = Context.SomeOtherEntity.First();
}
}
My understanding is:
the ObjectContext is not threadsafe and may be shared across threads in this instance.
A single objectcontext should be used across an http request. Multiple objectcontexts are being created from various repositories to render a page.
The objectcontext does not seem to be closed, disposed off at any point in the http request. This could be a problem if transactions are being used and transactions are committed from threads than did not begin them.
Would appreciate any feedback on these 3 points above as my experience is primarily based on NHibernate.
You could implement the Repository and Unit of Work patterns.
Considering the IIS uses Thread pool to manage requests, my solution is to create one and only one ThreadStatic DataContext for each request, and clear it after request ending.
public class DataContextManager
{
[ThreadStatic]
private static MyDataContext dataContext = null;
public static MyDataContext GetContext()
{
if (dataContext == null)
{
dataContext = new MyDataContext();
}
return dataContext;
}
public static void Clear()
{
dataContext = null;
}
}

architectural question asp.net mvc, nhibernate, castle

I have implemented a service which uses a DAOFactory and a NHibernate Helper for the sessions and transactions. The following code is very much simplified:
public interface IService
{
IList<Disease> getDiseases();
}
public class Service : IService
{
private INHibernateHelper NHibernateHelper;
private IDAOFactory DAOFactory;
public Service(INHibernateHelper NHibernateHelper, IDAOFactory DAOFactory)
{
this.NHibernateHelper = NHibernateHelper;
this.DAOFactory = DAOFactory;
}
public IList<Disease> getDiseases()
{
return DAOFactory.getDiseaseDAO().FindAll();
}
}
public class NHibernateHelper : INHibernateHelper
{
private static ISessionFactory sessionFactory;
/// <summary>
/// SessionFactory is static because it is expensive to create and is therefore at application scope.
/// The property exists to provide 'instantiate on first use' behaviour.
/// </summary>
private static ISessionFactory SessionFactory
{
get
{
if (sessionFactory == null)
{
try
{
sessionFactory = new Configuration().Configure().AddAssembly("Bla").BuildSessionFactory();
}
catch (Exception e)
{
throw new Exception("NHibernate initialization failed.", e);
}
}
return sessionFactory;
}
}
public static ISession GetCurrentSession()
{
if (!CurrentSessionContext.HasBind(SessionFactory))
{
CurrentSessionContext.Bind(SessionFactory.OpenSession());
}
return SessionFactory.GetCurrentSession();
}
public static void DisposeSession()
{
var session = GetCurrentSession();
session.Close();
session.Dispose();
}
public static void BeginTransaction()
{
GetCurrentSession().BeginTransaction();
}
public static void CommitTransaction()
{
var session = GetCurrentSession();
if (session.Transaction.IsActive)
session.Transaction.Commit();
}
public static void RollbackTransaction()
{
var session = GetCurrentSession();
if (session.Transaction.IsActive)
session.Transaction.Rollback();
}
}
At the end of the day I just want to expose the IService to ASP.NET MVC/Console application/Winform. I can already use the Service in a console application but would like to improve it first. I guess the first improvement would be to inject the interfaces INHibernateHelper and IDAOFactory via castle. But I think the problem is that the NHibernateHelper might cause problems in a asp.net context where NHibernateHelper should run according to the 'Nhibernate session per request' pattern. One question I have is whether this pattern is determined by the nhibernate config section (setting current_session_context_class = web) or can i control this via castle somehow?
I hope this makes sense. The final aim is just to expose THE IService.
Thanks.
Christian
You have two choices..
1) Host it in WCF. This allows you access from any source you want.
2) Abstract away everything that's specific to how the code is being used. In our system for instance we use our own Unit Of Work implementation which is stored differently based on where the code is running. A small example would be storing something using the WCF call context vs. the current thread.

Resources