Nancy - Unable to resolve type: NHibernate.ISession - nhibernate

My CustomBootstrapper looks like below
public class CustomBootstrapper : DefaultNancyBootstrapper
{
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
//This will tell Nancy it won't have to look in the Nhibernate assemblies for implementations of our interfaces.
return NancyInternalConfiguration
.Default
.WithIgnoredAssembly(asm => asm.FullName.StartsWith("NHibernate", StringComparison.InvariantCulture))
.WithIgnoredAssembly(asm => asm.FullName.StartsWith("Fluent", StringComparison.InvariantCulture))
.WithIgnoredAssembly(asm => asm.FullName.StartsWith("Iesi", StringComparison.InvariantCulture));
}
}
protected override void ConfigureRequestContainer(TinyIoCContainer container, NancyContext context)
{
base.ConfigureRequestContainer(container, context);
//container.Register((c, p) => SessionFactory.OpenSession());
container.Register(SessionFactory.OpenSession());
}
}
I have a repository which accepts ISession as a constructor dependency. When I run my application I get an error saying Unable to resolve type: NHibernate.ISession
I can confirm that
My bootstrapper is picked up by Nanacy
The ISession registration code is executed
I have tried commenting out .WithIgnoredAssembly(asm => asm.FullName.StartsWith("NHibernate", StringComparison.InvariantCulture)) from property InternalConfiguration
I get the error with both of the ways of registering component (one is commented in my code)
I have looked at similar other questions on SO and none has helped so far.

I've done a sample project that uses NH with Nancy. In the bootstrapper I set up:
a BeforeRequest hook that creates the session and binds it to the session context
a AfterRequest hook that commits the session
an OnError hook that rolls back
The code is as follows:
public class Bootstrapper : WindsorNancyBootstrapper
{
// other stuff
protected override void ApplicationStartup(IWindsorContainer container, IPipelines pipelines)
{
base.ApplicationStartup(container, pipelines);
// other setup
ConfigureNHibernateSessionPerRequest(container, pipelines);
}
private void ConfigureNHibernateSessionPerRequest(IWindsorContainer container, IPipelines pipelines)
{
pipelines.BeforeRequest += ctx => CreateSession(container);
pipelines.AfterRequest += ctx => CommitSession(container);
pipelines.OnError += (ctx, ex) => RollbackSession(container);
}
private Response RollbackSession(IWindsorContainer container)
{
var sessionFactory = container.Resolve<ISessionFactory>();
if (CurrentSessionContext.HasBind(sessionFactory))
{
var requestSession = sessionFactory.GetCurrentSession();
requestSession.Transaction.Rollback();
CurrentSessionContext.Unbind(sessionFactory);
requestSession.Dispose();
}
return null;
}
private Response CreateSession(IWindsorContainer container)
{
var sessionFactory = container.Resolve<ISessionFactory>();
var requestSession = sessionFactory.OpenSession();
CurrentSessionContext.Bind(requestSession);
requestSession.BeginTransaction();
return null;
}
private AfterPipeline CommitSession(IWindsorContainer container)
{
var sessionFactory = container.Resolve<ISessionFactory>();
if (CurrentSessionContext.HasBind(sessionFactory))
{
var requestSession = sessionFactory.GetCurrentSession();
requestSession.Transaction.Commit();
CurrentSessionContext.Unbind(sessionFactory);
requestSession.Dispose();
}
return null;
}
}

Related

Caching odata Web Api

I am developing an OData API for my Asp.net core application and i want to implement caching on this.
The problem is all my endpoints will be IQueryable with a queryable services with no execution at all. so i can't implement any caching on service level
Controller
public class TagsController : ODataController
{
private readonly ITagService _tagService;
private readonly ILogger<TagsController> _logger;
public TagsController(ITagService tagService, ILogger<TagsController> logger)
{
_tagService = tagService;
_logger = logger;
}
[HttpGet("odata/tags")]
[Tags("Odata")]
[AllowAnonymous]
[EnableCachedQuery]
public ActionResult<IQueryable<Tag>> Get()
{
try
{
return Ok(_tagService.GetAll());
}
catch (Exception ex)
{
_logger.LogError(ex, "Some unknown error has occurred.");
return BadRequest();
}
}
}
So I tried to apply an extension on EnableQuery attribute to add the caching implementation on it. so i added the following
public class EnableCachedQuery : EnableQueryAttribute
{
private IMemoryCache _memoryCache;
public EnableCachedQuery()
{
_memoryCache = new MemoryCache(new MemoryCacheOptions());
}
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
//var url = GetAbsoluteUri(actionContext.HttpContext);
var path = actionContext.HttpContext.Request.Path + actionContext.HttpContext.Request.QueryString;
//check cache
if (_memoryCache.TryGetValue(path, out ObjectResult value))
{
actionContext.Result = value;
}
else
{
base.OnActionExecuting(actionContext);
}
}
public override void OnActionExecuted(ActionExecutedContext context)
{
if (context.Exception != null)
return;
var path = context.HttpContext.Request.Path + context.HttpContext.Request.QueryString;
var cacheEntryOpts = new MemoryCacheEntryOptions().SetAbsoluteExpiration(TimeSpan.FromMinutes(15));
base.OnActionExecuted(context);
_memoryCache.Set(path, context.Result, cacheEntryOpts);
}
}
the first request completed successfully and retrieved the data correctly with filters and queries applied. then when tried to add the data to cache the context.Result holds the ObjectResult and then in the second request which should be cached the value was there but with an error in executing which means that the cached value is not the final output value that should be passed to the Result
Cannot access a disposed context instance. A common cause of this error is disposing a context instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ApplicationDbContext'.
============================
Update:
public class ApplicationDbContext : IdentityDbContext<User, Account, Session>, IApplicationDbContext
{
public ApplicationDbContext(
DbContextOptions options,
IApplicationUserService currentUserService,
IDomainEventService domainEventService,
IBackgroundJobService backgroundJob,
IDomainEventService eventService,
IDateTime dateTime) : base(options, currentUserService, domainEventService, backgroundJob, dateTime) { }
public DbSet<Tag> Tags => Set<Tag>();
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var entityTypes = builder.Model.GetEntityTypes()
.Where(c => typeof(AuditableEntity).IsAssignableFrom(c.ClrType))
.ToList();
foreach (var type in entityTypes)
{
var parameter = Expression.Parameter(type.ClrType);
var deletedCheck = Expression.Lambda
(Expression.Equal(Expression.Property(parameter, nameof(AuditableEntity.Deleted)), Expression.Constant(false)), parameter);
type.SetQueryFilter(deletedCheck);
}
builder.ApplyConfigurationsFromAssembly(typeof(ApplicationDbContext).Assembly);
builder.ApplySeedsFromAssembly(typeof(ApplicationDbContext).Assembly);
}
}

Unable to seed data in ASP.NET Core in a static method due to exception 'A second operation started on this context before a previous'

I am attempting to seed my database with the following code:
Startup.Configure:
app.UseCors("AllowAll")
.UseMiddleware<JwtBearerMiddleware>()
.UseAuthentication()
.SeedDatabase() <= here
.UseHttpsRedirection()
.UseDefaultFiles()
.UseMvc()
.UseSpa(SpaApplicationBuilderExtensions => { });
SeedDatabase method:
public static IApplicationBuilder SeedDatabase(this IApplicationBuilder app)
{
IServiceProvider serviceProvider = app.ApplicationServices.CreateScope().ServiceProvider;
try
{
UserManager<ApplicationUser> userManager = serviceProvider.GetService<UserManager<ApplicationUser>>();
RoleManager<IdentityRole> roleManager = serviceProvider.GetService<RoleManager<IdentityRole>>();
IConfiguration configuration = serviceProvider.GetService<IConfiguration>();
ThePLeagueContext dbContext = serviceProvider.GetService<ThePLeagueContext>();
DataBaseInitializer.SeedUsers(userManager, roleManager, configuration, dbContext);
DataBaseInitializer.SeedTeams(dbContext);
}
catch (Exception ex)
{
ILogger<Program> logger = serviceProvider.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "An error occurred while seeding the database.");
}
return app;
}
Everything worked fine until I added ThePLeagueContext dbContext = serviceProvider.GetService<ThePLeagueContext>(); and then the DataBaseInitializer.SeedTeams(dbContext)
DataBaseInitializer.SeedTeams(dbContext):
public static async void SeedTeams(ThePLeagueContext dbContext)
{
List<Team> teams = new List<Team>();
// 7 because we have 7 leagues
for (int i = 0; i < 7; i++)...
if (dbContext.Teams.Count() < teams.Count)
{
foreach (Team newTeam in teams)
{
await dbContext.Teams.AddAsync(newTeam);
await dbContext.SaveChangesAsync();
}
}
}
When I attempt to seed the database with the above code I get the following exception:
System.InvalidOperationException: 'A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext, however instance members are not guaranteed to be thread safe. This could also be caused by a nested query being evaluated on the client, if this is the case rewrite the query avoiding nested invocations.'
My database context is registered with the LifeTime of Scoped.
Two workarounds I found:
When I change my database context to Transient the seeding issue goes away. This however causes other issues in the application so I cannot use Transient
When I call DatabaseInitializer.SeedTeams(dbContext) from inside the DatabaseInitializer.SeedUsers(...) method, this also works, I have no clue why.
DatabaseInitializer.SeedUsers(...) method:
public async static void SeedUsers(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IConfiguration configuration, ThePLeagueContext dbContext)
{
string[] roles = new string[] { AdminRole, SuperUserRole, UserRole };
foreach (string role in roles)
{
if (!roleManager.Roles.Any(r => r.Name == role))
{
IdentityRole newRole = new IdentityRole
{
Name = role,
NormalizedName = role.ToUpper()
};
await roleManager.CreateAsync(newRole);
if (role == AdminRole)
{
await roleManager.AddClaimAsync(newRole, new Claim(Permission, ModifyPermission));
}
else if (role == SuperUserRole)
{
await roleManager.AddClaimAsync(newRole, new Claim(Permission, RetrievePermission));
}
else
{
await roleManager.AddClaimAsync(newRole, new Claim(Permission, ViewPermission));
}
}
}
ApplicationUser admin = new ApplicationUser()...
ApplicationUser sysAdmin = new ApplicationUser()...;
PasswordHasher<ApplicationUser> password = new PasswordHasher<ApplicationUser>();
if (!userManager.Users.Any(u => u.UserName == admin.UserName))
{
string hashed = password.HashPassword(admin, configuration["ThePLeagueAdminInitPassword"]);
admin.PasswordHash = hashed;
await userManager.CreateAsync(admin);
await userManager.AddToRoleAsync(admin, AdminRole);
}
if (!userManager.Users.Any(u => u.UserName == sysAdmin.UserName))
{
string hashed = password.HashPassword(sysAdmin, configuration["ThePLeagueAdminInitPassword"]);
sysAdmin.PasswordHash = hashed;
await userManager.CreateAsync(sysAdmin);
await userManager.AddToRoleAsync(sysAdmin, AdminRole);
}
SeedTeams(dbContext);
}
Is there any way I can use two separate static async methods to seed the database and keep my context as scoped?
So I like to keep things ordered and seperated. Therefore I'd do something like:
public static class SeedData
{
public static void Populate(IServiceProvider services)
{
ApplicationDbContext context = services.GetRequiredService<ApplicationDbContext>();
if (!context.SomeDbSet.Any())
{
// ...code omitted for brevity...
);
context.SaveChanges();
}
}
public static class IdentitySeedData
{
public static async Task Populate(IServiceProvider services)
{
UserManager<ApplicationUser> userManager = services.GetService<UserManager<ApplicationUser>>();
RoleManager<IdentityRole> roleManager = services.GetService<RoleManager<IdentityRole>>();
IConfiguration configuration = services.GetService<IConfiguration>();
ApplicationDbContext context = services.GetRequiredService<ApplicationDbContext>();
if (!context.Users.Any())
{
// ...code omitted for brevity...
await userManager.CreateAsync(sysAdmin);
await userManager.AddToRoleAsync(sysAdmin, AdminRole);
);
context.SaveChanges();
}
}
And then the one to top it off:
public static class DatabaseInitializer
{
public static void Initialize(IServiceProvider services)
{
IdentitySeedData.Populate(services).Wait();
SeedData.Populate(services);
}
}
Disclaimer: I haven't run the code. So if it requires some tweaking let me know. I'll make the adjustments. It's a bit time-consuming to test this out.

Migrating to Automapper 4.2.1 from Automapper 2.2.1

I have a project where I have been using automapper 2.2.1. I upgraded to 4.2.1 and am completely broken. I tried to follow this
by changing all references to Mapper.CreateMap<Source, Target>() to Mapper.Initialize(cfg => { cfg.CreateMap<Source, Target>()}). I'm now broken bad and I cant seem to get it done.I'm getting "System.Reflection.ReflectionTypeLoadException was unhandled by user code exception with Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information", message. What am I missing. Code looks like this:
AutomapperTypeAdapterFactory
public class AutomapperTypeAdapterFactory : ITypeAdapterFactory
{
public AutomapperTypeAdapterFactory()
{
//scan all assemblies finding Automapper Profile
var profiles = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(a => a.GetTypes())
.Where(t => t.BaseType == typeof(Profile));
Mapper.Initialize(cfg =>
{
foreach (var item in profiles)
{
if (item.FullName != "AutoMapper.SelfProfiler`2")
cfg.AddProfile(Activator.CreateInstance(item) as Profile);
}
});
}
public ITypeAdapter Create() => new AutomapperTypeAdapter();
}
Department Profile
public class DepartmentProfile : Profile
{
protected override void Configure()
{
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Department, DepartmentDto>();
});
}
}
UnityContainer
public static class Container
{
static IUnityContainer _container = new UnityContainer();
static Container()
{
var typeAdapterFactory = _container.Resolve<ITypeAdapterFactory>();
TypeAdapterFactory.SetCurrent(typeAdapterFactory);
}
//other container resolutions....
}
In projects where I've moved away from the static configuration I've defined a few mapping profiles (generally a profile per application layer):
public class MappingProfile : Profile
{
protected override void Configure()
{
CreateMap<Source, Destination>();
}
}
I then configure my IoC (SimpleInjector, in my case) to find all profiles and add them to a single, unified configuration. I then register the MapperConfiguration in my container, as well as the IMapper object created from the same:
public void ConfigureSimpleInjector(IAppBuilder app)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new WebRequestLifestyle();
container.RegisterAutoMapper();
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
public static Container RegisterAutoMapper(this Container container)
{
var profiles = typeof(AutoMapperRegistry).Assembly.GetTypes().Where(t => typeof(Profile).IsAssignableFrom(t)).Select(t => (Profile)Activator.CreateInstance(t));
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
container.Register<MapperConfiguration>(() => config);
container.Register<IMapper>(() => container.GetInstance<MapperConfiguration>().CreateMapper());
return container;
}
}
I can then use DI for IMapper (or you could store it statically), as well as the MapperConfiguration for use in LINQ projections.

SignalR OnDisconnected event not persisting data to DB

I have a SignalR hub in which I'm injecting service classes which persist data to a local SQL Server instance via Castle Windsor.
The hub looks like:
[Authorize]
public class MyHub : Hub
{
private readonly IHubService _hubService;
private readonly IHubUserService _hubUserService;
private readonly IUserService _userService;
public MyHub(IHubService hubService, IHubUserService hubUserService, IUserService userService)
{
_hubService = hubService;
_hubUserService = hubUserService;
_userService = userService;
}
public async Task JoinHub(Guid hubId)
{
var hub = _hubService.GetHubById(hubId);
if (hub == null)
throw new NotFoundException(String.Format("Hub ({0}) was not found.", hubId.ToString()));
var userName = Context.User.Identity.Name;
var user = _userService.GetUserByUserName(userName);
if (user == null)
throw new NotFoundException(String.Format("User ({0}) was not found.", userName));
var hubUser = new HubUser
{
User = user,
Hub = hub,
ConnectionId = Context.ConnectionId
};
// Persist a new HubUser to the DB
hubUser = _hubUserService.InsertHubUser(hubUser);
await Groups.Add(Context.ConnectionId, hub.Id.ToString());
Clients.Group(hub.Id.ToString()).addChatMessage(userName + " has joined.");
}
public async Task LeaveHub()
{
var userName = Context.User.Identity.Name;
var hubUser = _hubUserService.GetHubUserByUserName(userName);
// Removes HubUser from the DB
_hubUserService.RemoveHubUser(hubUser);
await Groups.Remove(Context.ConnectionId, hubUser.Hub.Id.ToString());
Clients.Group(hubUser.Hub.Id.ToString()).addChatMessage(userName + " has left.");
}
public override Task OnDisconnected(bool stopCalled)
{
var userName = Context.User.Identity.Name;
var hubUser = _hubUserService.GetHubUserByUserName(userName);
// Removes HubUser from the DB
_hubUserService.RemoveHubUser(hubUser); // This line executes but does not persist anything to DB
Groups.Remove(Context.ConnectionId, hubUser.Hub.Id.ToString());
Clients.Group(hubUser.Hub.Id.ToString()).addChatMessage(userName + " has left.");
return base.OnDisconnected(stopCalled);
}
}
When calling JoinHub and LeaveHub methods from the client, everything works fine. However, when the OnDisconnected method fires, nothing is deleted from the database. I can see that the code does indeed execute, but the record remains in the DB and does not get deleted.
I'm wondering if perhaps my nhibernate session is not committing the transaction to the database due to castle windsor's dependency lifetimes or something, however, it's odd that LeaveHub executes as expected but the same code does not in the OnDisconnected method.
My dependencies are registered with the following configuration as per this blog post.
Kernel.Register(
//Nhibernate session factory
Component.For<ISessionFactory>().UsingFactoryMethod(CreateNhSessionFactory).LifeStyle.Singleton,
//Nhibernate session
Component.For<ISession>().UsingFactoryMethod(kernel => kernel.Resolve<ISessionFactory>().OpenSession()).LifeStyle.HybridPerWebRequestTransient()
);
and I also register an interceptor to implement a unit of work pattern:
// Unitofwork interceptor
Component.For<NhUnitOfWorkInterceptor>().LifeStyle.HybridPerWebRequestTransient()
If anyone can give any input on why the method LeaveHub works correctly and why it fails to persist anything in the OnDisconnected method, that'd be greatly appreciated.
Just an FYI Nhibernate Sessions don't do so well using async as they are not threadsafe at all. Try running things synchronously and see what you get.
Is Nhibernate set to flush on transaction commit? I can't comment becasue I am a newbie but I ran into this issue some time ago. I am not using FluentNhibernate but I am sure there is a config option to set flush on transaction commit. This is assuming you are wrapping all open session calls in a transaction. I use something like this for sessions. Also go get Nhibernate Profiler it is a godsend.
public class SessionManager : ISessionManager
{
private readonly ISessionFactory _sessionFactory;
private ISession _currentSession;
private ITransaction _currentTransaction;
public SessionManager(ISessionFactory sessionFactory)
{
_sessionFactory = sessionFactory;
}
public ISession OpenSession()
{
if (CurrentSessionContext.HasBind(_sessionFactory))
{
_currentSession = _sessionFactory.GetCurrentSession();
}
else
{
_currentSession = _sessionFactory.OpenSession();
CurrentSessionContext.Bind(_currentSession);
}
CurrentSessionContext.Bind(_currentSession);
_currentTransaction = _currentSession.BeginTransaction();
return _currentSession;
}
public void Dispose()
{
try
{
if (_currentTransaction != null && _currentTransaction.IsActive)
_currentTransaction.Commit();
}
catch (Exception)
{
if (_currentTransaction != null) _currentTransaction.Rollback();
throw;
}
finally
{
if (_currentSession != null)
{
if (_currentTransaction != null) _currentTransaction.Dispose();
_currentSession.Close();
}
}
}
}
Here is my configuration, I am using it on several apps. On a side not there is a reason I don't use FluentNhibernate, The mapping by code built in is awesome and flexible. Let me know I can send you some sample mappings.
public class SessionFactoryBuilder
{
public static ISessionFactory BuildSessionFactory(string connectionString)
{
var cfg = new Configuration();
cfg.DataBaseIntegration(db =>
{
db.Dialect<MsSql2012Dialect>();
db.Driver<Sql2008ClientDriver>();
db.ConnectionString = connectionString;
db.BatchSize = 1500;
db.LogSqlInConsole = false;
db.PrepareCommands = true;
db.ConnectionReleaseMode = ConnectionReleaseMode.AfterTransaction;
db.IsolationLevel = IsolationLevel.ReadCommitted;
})
.SetProperty(Environment.CurrentSessionContextClass, "web")
.SetProperty(Environment.UseSecondLevelCache, "true")
.SetProperty(Environment.ShowSql, "true")
.SetProperty(Environment.PrepareSql, "true")
.Cache(c =>
{
c.UseQueryCache = true;
c.Provider<RtMemoryCacheProvider>();
c.DefaultExpiration = 1440;
}).SessionFactory().GenerateStatistics();
HbmMapping mapping = GetMappings();
cfg.AddDeserializedMapping(mapping, "AppName");
SchemaMetadataUpdater.QuoteTableAndColumns(cfg);
return cfg.BuildSessionFactory();
}
private static HbmMapping GetMappings()
{
var mapper = new ModelMapper();
mapper.AddMappings(typeof (UserMap).Assembly.GetTypes());
HbmMapping mapping = mapper.CompileMappingForAllExplicitlyAddedEntities();
return mapping;
}
}
Here is a neat little bit for managing SignalR dependencies with Castle. You may want to give this a try just for giggles.
public class SignalRDependencyResolver : Microsoft.AspNet.SignalR.DefaultDependencyResolver
{
private readonly IWindsorContainer _container;
public SignalRDependencyResolver(IWindsorContainer container)
{
if (container == null)
{
throw new ArgumentNullException("container");
}
_container = container;
}
public override object GetService(Type serviceType)
{
return TryGet(serviceType) ?? base.GetService(serviceType);
}
public override IEnumerable<object> GetServices(Type serviceType)
{
return TryGetAll(serviceType).Concat(base.GetServices(serviceType));
}
[DebuggerStepThrough]
private object TryGet(Type serviceType)
{
try
{
return _container.Resolve(serviceType);
}
catch (Exception)
{
return null;
}
}
private IEnumerable<object> TryGetAll(Type serviceType)
{
try
{
Array array = _container.ResolveAll(serviceType);
return array.Cast<object>().ToList();
}
catch (Exception)
{
return null;
}
}
}
Put this in global asax before you set your controller factory
// SignalR
_container.Register(Classes.FromThisAssembly().BasedOn(typeof(IHub)).LifestyleTransient());
SignalRDependencyResolver signalRDependencyResolver = new SignalRDependencyResolver(_container);
Microsoft.AspNet.SignalR.GlobalHost.DependencyResolver = signalRDependencyResolver;

SetterProperty injection using structuremap to Asp.Net MVC ActionFilter

Why I am not able to inject the SetterProperty via StructureMap to an MVC ActionFilter?
public class LockProjectFilter : ActionFilterAttribute
{
[SetterProperty]
public ISecurityService SecurityService { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var loggedinStaffId = SecurityService.GetLoggedInStaffId();
if (loggedinStaffId == 1)
throw new ArgumentNullException();
base.OnActionExecuting(filterContext);
}
}
public static IContainer Initialize()
{
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.AssemblyContainingType<ISecurityService>();
});
x.SetAllProperties(p => p.OfType<ISecurityService>());
//x.ForConcreteType<LockProjectFilter>().Configure
// .Setter(c => c.SecurityService).IsTheDefault();
});
return ObjectFactory.Container;
}
You need to utilize the 'BuildUp' method off the ObjectFactory.
http://docs.structuremap.net/ConstructorAndSetterInjection.htm#section4
[Test]
public void create_a_setter_rule_and_see_it_applied_in_BuildUp_through_ObjectFactory()
{
var theGateway = new DefaultGateway();
ObjectFactory.Initialize(x =>
{
x.ForRequestedType<IGateway>().TheDefault.IsThis(theGateway);
// First we create a new Setter Injection Policy that
// forces StructureMap to inject all public properties
// where the PropertyType is IGateway
x.SetAllProperties(y =>
{
y.OfType<IGateway>();
});
});
// Create an instance of BuildUpTarget1
var target = new BuildUpTarget1();
// Now, call BuildUp() on target, and
// we should see the Gateway property assigned
ObjectFactory.BuildUp(target);
target.Gateway.ShouldBeTheSameAs(theGateway);
}
Then you can create a new FilterAttributeFilterProvider like this:
public class DependencyResolverFilterProvider : FilterAttributeFilterProvider
{
public override IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(controllerContext, actionDescriptor);
foreach (var filter in filters)
{
//DI via Setter Injection
DependencyResolver.BuildUp(filter.Instance);
}
return filters;
}
}
Then finally add your custom filter provider to the .net pipeline.
private static void RegisterProviderAndFilters()
{
var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
FilterProviders.Providers.Add(new DependencyResolverFilterProvider());
RegisterGlobalFilters(GlobalFilters.Filters);
}
Hope this helps!
wm