syed mhamudul hasan akash syed mhamudul hasan akash - 13 days ago 6
ASP.NET (C#) Question

Lifestyle Mismatch Web Request depends on Transient in Simple Injector

I am using simple injector with nuget in asp.net mvc 5

Install-Package SimpleInjector -Version 3.1.5
Install-Package SimpleInjector.Integration.Web.Mvc -Version 3.1.5


In global.asax

protected void Application_Start()
{
//removed for bravity
// Container container = new DependencyInjectionContiner().DI();
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.Register<IHomeRepository, HomeRepository>(Lifestyle.Scoped);

//For WebApi Request
// container.Register<IWebApi, WebApi>(Lifestyle.Transient);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
////To verify life styles of injection
container.Verify();
DependencyResolver.SetResolver(
new SimpleInjectorDependencyResolver(container));
}


I showed error on

The configuration is invalid. The following diagnostic warnings were reported:

-[Lifestyle Mismatch] HomeRepository (Web Request) depends on UnitOfWork (Transient).


IHomeRepository

public interface IHomeRepository
{
void InsertDepartment(Department department, List<Student> students);
}


HomeRepository

public class HomeRepository : IHomeRepository
{
private UnitOfWork unitOfWork;
public HomeRepository(UnitOfWork unitOfWork)
{
this.unitOfWork = unitOfWork;
}

public void InsertDepartment(Department department, List<Student> students)
{
department.Students = students;
unitOfWork.DepartmentRepository.Insert(department);
unitOfWork.Save();
}
}


IUnitOfWork

public class UnitOfWork : IDisposable
{
private SchoolContext context = new SchoolContext();
private GenericRepository<Department> departmentRepository;
private GenericRepository<Student> studentRepository;

public GenericRepository<Department> DepartmentRepository
{
get
{

if (this.departmentRepository == null)
{
this.departmentRepository = new GenericRepository<Department>(context);
}
return departmentRepository;
}
}

public GenericRepository<Student> StudentRepository
{
get
{

if (this.studentRepository == null)
{
this.studentRepository = new GenericRepository<Student>(context);
}
return studentRepository;
}
}

public void Save()
{
context.SaveChanges();
}

private bool disposed = false;

protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}

public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}


GenericRepository

public class GenericRepository<TEntity> where TEntity : class
{
internal SchoolContext context;
internal DbSet<TEntity> dbSet;

public GenericRepository(SchoolContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}

public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
IQueryable<TEntity> query = dbSet;

if (filter != null)
{
query = query.Where(filter);
}

foreach (var includeProperty in includeProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
{
query = query.Include(includeProperty);
}

if (orderBy != null)
{
return orderBy(query).ToList();
}
else
{
return query.ToList();
}
}

//public IQueryable GetIQueryable()
//{
// return context.Set<TEntity>().AsQueryable();
//}
public IEnumerable<TEntity> Query(Expression<Func<TEntity, bool>> filter)
{
return context.Set<TEntity>().Where(filter);
}
public IEnumerable<TEntity> Query()
{
return context.Set<TEntity>();
}

//public IQueryable Query()
//{
// return context.Set<TEntity>();
//}
public virtual TEntity GetByID(object id)
{
return dbSet.Find(id);
}

public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}

public virtual void Delete(object id)
{
TEntity entityToDelete = dbSet.Find(id);
Delete(entityToDelete);
}

public virtual void Delete(TEntity entityToDelete)
{
if (context.Entry(entityToDelete).State == EntityState.Detached)
{
dbSet.Attach(entityToDelete);
}
dbSet.Remove(entityToDelete);
}

public virtual void Update(TEntity entityToUpdate)
{
dbSet.Attach(entityToUpdate);
context.Entry(entityToUpdate).State = EntityState.Modified;
}
}


why verify shows the error? and Is it ok to use Transient and Scoped on a single container ????

Answer

The exception message refers to the following documentation page: https://simpleinjector.org/diagnostics. The documentation states the following about Lifestyle Mismatches:

In general, components should only depend on other components that are configured to live at least as long. In other words, it is safe for a transient component to depend on a singleton, but not the other way around. Since components store a reference to their dependencies in (private) instance fields, those dependencies are kept alive for the lifetime of that component. This means that dependencies that are configured with a shorter lifetime than their consumer, accidentally live longer than intended. This can lead to all sorts of bugs, such as hard to debug multi-threading issues.

The documentation also provides the following suggestions for fixes:

  • Change the lifestyle of the component to a lifestyle that is as short or shorter than that of the dependency.
  • Change the lifestyle of the dependency to a lifestyle as long or longer than that of the component.

This means you should either make the HomeRepository Transient, or make the UnitOfWork Scoped.

Making the UnitOfWork Scoped is the most obvious as discussed in this q&a.

You mean to say make use of Hybrid Life style

You should forget about hybrid lifestyles. They don't provide an answer to your problem.