Service Stack Injecting and Resolving Service in Filter (dot net core 2) - asp.net-core

I have a TypeFilterAtrribute which instantiates and ActionFilter. The ActionFilter needs two services injected.
public class ValidateUserAttribute : TypeFilterAttribute
{
public ValidateUserAttribute() : base(typeof(AuthenticationFilter))
{
}
private class AuthenticationFilter : ActionFilterAttribute
{
private readonly IActiveDirectoryService ActiveDirectoryService;
private readonly MessageService MessageSerivce;
public AuthenticationFilter(IActiveDirectoryService activeDirectoryService, MessageService messageSerivce)
{
ActiveDirectoryService = activeDirectoryService;
MessageSerivce = messageSerivce;
}
I have it working with the default IOC container of dot net core 2 but I could not use Funq container to do it.
I am reading from appsettings.json (I think I read on the docs ServiceStack does not support this) and registering
var config = Configuration.GetSection("LdapAuth");
services.Configure<LdapAuthenticationOptions>(Configuration.GetSection("LdapAuth"));
services.AddActiveDirectoryService(options =>
Configuration.GetSection("LdapAuth"));//uses collection.AddTransient<IActiveDirectoryService, ActiveDirectoryService>()
services.AddMessageService(); //same as above
I can't think of a way to inject into the filter a parameterized service.
So this does not work at all because I don't have a default constructor.
public class AuthenticationFilter : ActionFilterAttribute
{
public IActiveDirectoryService ActiveDirectoryService {get; set;};
But this below at least should have worked. I'm not using an interface here though.
public class AuthenticationFilter : ActionFilterAttribute
{
public MessageService MessageService{get; set}; //notice not using interface here although this as default constructor.
Where this gets really ugly is then I have controllers that inherit ServiceStackController and I inject services using ResolveService from the Funq container.
public class MessageController : ServiceStackController
{
...
var messageService = ResolveService<MessageService>()
I re-register them.. like below.
public override void Configure(Funq.Container container)
{
SqlServerDialect.Provider.RegisterConverter<TimeSpan>(new ServiceStack.OrmLite.SqlServer.Converters.SqlServerTimeConverter
{
Precision = 7
});
var connectionString = GetConnectionString(AppSettings);
container.Register<IDbConnectionFactory>(
new OrmLiteConnectionFactory(connectionString, new SqlServerOrmLiteDialectProvider()));
LdapAuthenticationOptions options = GetLdapAuthenticationOptions(AppSettings); //notice now I have to read from AppSetting.. which is appsettings.txt file.
container.Register(c => new ActiveDirectoryService(options));
container.Register(c => new MessageService());
}

Related

How to inject dependency into NServiceBus pipeline behavior?

I've been following the NServiceBus samples, specifically for how to use an entity framework (core) DbContext integrated with Sql Persistence so that I can save dbcontext state changes along with the outbox messages. This is the sample: https://docs.particular.net/samples/entity-framework-core/
I've modified the unit of work code a little to support creation of an aspnet core DI scoped DbContext. The relevant code follows:
public class UnitOfWork<TDbContext>
where TDbContext : DbContext
{
private Func<SynchronizedStorageSession, IServiceProvider, TDbContext> _contextFactory;
private TDbContext _context;
private IServiceProvider _serviceProvider;
public UnitOfWork(Func<SynchronizedStorageSession, IServiceProvider, TDbContext> contextFactory, IServiceProvider serviceProvider)
{
_contextFactory = contextFactory;
_serviceProvider = serviceProvider;
}
public TDbContext GetDataContext(SynchronizedStorageSession storageSession)
{
if (_context == null)
{
_context = _contextFactory(storageSession, _serviceProvider);
}
return _context;
}
}
public class UnitOfWorkSetupBehavior<TDbContext> : Behavior<IIncomingLogicalMessageContext>
where TDbContext : DbContext
{
private readonly Func<SynchronizedStorageSession, IServiceProvider, TDbContext> _contextFactory;
private readonly IServiceScopeFactory _serviceScopeFactory;
public UnitOfWorkSetupBehavior(Func<SynchronizedStorageSession, IServiceProvider, TDbContext> contextFactory, IServiceScopeFactory serviceScopeFactory)
{
_contextFactory = contextFactory;
_serviceScopeFactory = serviceScopeFactory;
}
public override async Task Invoke(IIncomingLogicalMessageContext context, Func<Task> next)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var uow = new UnitOfWork<TDbContext>(_contextFactory, scope.ServiceProvider);
context.Extensions.Set(uow);
await next().ConfigureAwait(false);
context.Extensions.Remove<UnitOfWork<TDbContext>>();
}
}
}
public static class EndpointConfigurationExtensions
{
public static void RegisterUnitOfWork<TDbContext>(this EndpointConfiguration endpointConfiguration, IServiceScopeFactory serviceScopeFactory)
where TDbContext : DbContext
{
var pipeline = endpointConfiguration.Pipeline;
pipeline.Register(new UnitOfWorkSetupBehavior<TDbContext>((storageSession, serviceProvider) =>
{
var dbConnection = storageSession.SqlPersistenceSession().Connection;
var dbContextFactory = serviceProvider.GetService<IDbContextConnectionFactory<TDbContext>>();
var dbContext = dbContextFactory.GetDbContext(dbConnection);
//Use the same underlying ADO.NET transaction
dbContext.Database.UseTransaction(storageSession.SqlPersistenceSession().Transaction);
//Call SaveChanges before completing storage session
storageSession.SqlPersistenceSession().OnSaveChanges(x => dbContext.SaveChangesAsync());
return dbContext;
}, serviceScopeFactory), "Sets up unit of work for the message");
}
}
public static class UnitOfWorkContextExtensions
{
public static TDbContext DataContext<TDbContext>(this IMessageHandlerContext context)
where TDbContext : DbContext
{
var uow = context.Extensions.Get<UnitOfWork<TDbContext>>();
return uow.GetDataContext(context.SynchronizedStorageSession);
}
}
For this to work the behavior needs an injected IServiceScopeFactory.
Now all examples I've been able to find of behavior registration only show the type manually instantiated and passed in to the endpointconfiguration's pipeline.
Is there a way to either gain access to an IServiceScopeFactory via the behavior's Invoke method (maybe by the context via some extension perhaps?), or is it possible to register the behavior itself such that I can construct it with services created by the DI container?
FYI I took a look at this Q&A which gave me the idea of injecting the IServiceScopeFactory. Unfortunately, the answer doesn't show how to actually get an instance of the interface.
You would use context.builder.Build<T>(); within the Invoke method to resolve any objects like IServiceScopeFactory.
https://docs.particular.net/samples/multi-tenant/di/
Make sure that the IServiceScopeFactory is registered in the DI container. For example, during your endpoint initialization:
endpointConfiguration.RegisterComponents(registration: x =>
{
x.ConfigureComponent<IServiceScopeFactory>(yourServiceScopeFactory);
});
https://docs.particular.net/nservicebus/dependency-injection/
You can also do this by creating a Feature
https://docs.particular.net/nservicebus/pipeline/features

How to simplify asp.net core dependency injection

Since asp.net core DI provides only constructor injection and method injection.
If there's a lot of services to inject.
Instead of writing a lot inside constructor and change constructors frequently.
Can I just use some kind of provider so that I can get the services everywhere inside controller?
Instead of :
public class HomeController : BaseController
{
public HomeController(
IEmailService emailService,
ISMSService smsService,
ILogService logService,
IProductRepository _productRepository)
:base(emailService,smsService,logService)
{
}
public IActionResult()
{
_emailService.SendSomething();
}
...
}
public class BaseController : Controller
{
protected readonly IEmailService _emailService;
protected readonly ISMSService _smsService;
protected readonly ILogService _logService;
public BaseController(
IEmailService emailService,
ISMSService smsService,
ILogService logService)
{
_emailService = emailService;
_smsService = smsService;
_logService = logService;
}
}
With some kind of provider like:
public class HomeController : BaseController
{
public HomeController(IDIServiceProvider provider)
:base(provider)
{
}
public IActionResult()
{
_provider.GetScopedService<IEmailService>().SendSomething();
}
...
}
public class BaseController : Controller
{
protected readonly IDIServiceProvider _provider;
public BaseController(IDIServiceProvider provider)
{
_provider = provider;
}
}
So that I don't have to change all controller's constructors every time when BaseController's constructor changes and simplify all controller's constructors.
You can inject IServiceProvider to your controller and get your dependencies from that but it's not DI anymore and it's called Service Locator pattern.
public class HomeController
{
private readonly ITestService _testService;
public HomeController(IServiceProvider serviceProvider)
{
_testService = serviceProvider.GetRequiredService<ITestService>();
}
}
It's recommended to not use Service Locator because :
1- Your controller dependencies are not obvious with the first look.
2- It's harder to write unit tests for that.
3- Your service now needs one more dependency (IServiceProvider).
Use Service Locator pattern only when it needed like injecting your dependencies to FilterAttributes or ValidationAttributes. ( You can use ServiceFilter for this situations too. )

Ninject request scope and callback

I have a problem with Ninject in a MVC project using Owin.
I have a generic class for UnitOfWork that is not specific to my project :
public class UnitOfWork : IUnitOfWork
{
public UnitOfWork(DbContext context)
{...}
}
I define two repositories using my custom DbContext :
public UserRepository : IUserRepository
{
public UserRepository(MyEntities context)
{...}
}
public OrderRepository : IOrderRepository
{
public OrderRepository(MyEntities context)
{...}
}
Then I have a ApiController which use the unit of work and the repositories.
public OrderController : ApiController
{
public OrderController(IUnitOfWork uow, IUserRepository userRepository, IOrderRepository orderRepository)
{...}
}
I configure my Ninject kernel within a module. My bindings are with a request scope.
public class MyModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
// Bind all the repositories
this.Bind(x =>
x.FromAssembliesMatching("*.Repositories")
.SelectAllClasses()
.BindDefaultInterface()
.Configure(c => c.InRequestScope()));
// Bind the DbContext of the application
this.Bind<MyEntities>()
.ToSelf()
.InRequestScope();
// To bind the UnitOfWork, I need to specify the real DbContext to use. For that I use a callback which provide argument to constructor :
this.Bind<IUnitOfWork>()
.To<UnitOfWork>()
.InRequestScope()
.WithConstructorArgument("context", GetContext);
}
private Object GetContext(IContext context, ITarget target)
{
IResolutionRoot resolver;
ActivationBlock scope;
scope = context.Request.GetScope() as ActivationBlock;
resolver = scope ?? (IResolutionRoot)context.Kernel;
var o = resolver.Get<MyEntities>();
var o2 = resolver.Get<MyEntities>();
var same = Object.ReferenceEquals(o, o2);
return o;
}
}
Then I activate Ninject with Owin like this in the Startup class :
public class Startup
{
public void Configuration(IAppBuilder app)
{
...
app.UseNinjectMiddleware(Startup.CreateKernel);
var config = new HttpConfiguration();
...
app.UseNinjectWebApi(config);
}
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Load(new MyModule());
return kernel;
}
}
It seems good but there is a big problem. The repositories share the same DbContext, but the DbContext in the UnitOfWork is a different instance.
In the function GetContext, the scope is always null, so the MyContext instance is retrieved from the kernel. The boolean variable same is always false. The problem is here. The Get function of the kernel return a new instance, instead of the instance of the request scope.
Not sure if you still need this... but you can bind the dbcontext to self and then ask for it when you want to use it.
Bind<ApplicationDbContext>().ToSelf();
Bind<IUserStoreGuid<User>>().To<UserStoreGuid<User>>().WithConstructorArgument("context", Kernel.GetService(typeof(ApplicationDbContext)));
Although the connection string in the app is called "DefautConnection", you need to use "context" because that is how it is called in the constructor argument. I got this from here

Ninject Property Injection in WebAPI custom ExceptionFilterAttribute Not Working

I am trying to use Ninject to inject an EventLogger instance into a custom ExceptionFilterAttribute. Whenever I run the code, the EventLogger instance is null. I have implemented an IFilterProvider to resolve dependencies in a similar manner for my custom AuthorizationFilterAttribute, and that works fine. Any ideas?
Not Working
public class ErrorHandlingAttribute : ExceptionFilterAttribute
{
[Inject]
public IEventLogger EventLogger { get; set; }
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
EventLogger.LogException(actionExecutedContext.Exception);
actionExecutedContext.Response = actionExecutedContext.Request.
CreateResponse(HttpStatusCode.BadRequest,
new ServiceErrorResponseDTO("An unhandled exception occurred while calling " +
actionExecutedContext.Request.RequestUri.ToString() +
". This event has been logged. If you continue to receive this error contact Weichert"));
}
}
Working
public class RequireAuthorizationAttribute : AuthorizationFilterAttribute
{
[Inject]
public IServiceRepository ServiceRepository { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
#region Header Authentication
var authHeader = actionContext.Request.Headers.Authorization;
if (authHeader != null)
{
Custom IFilterProvider
public class NinjectWebApiFilterProvider : IFilterProvider
{
private IKernel _kernel;
public NinjectWebApiFilterProvider(IKernel kernel)
{
_kernel = kernel;
}
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
var controllerFilters = actionDescriptor.ControllerDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Controller));
var actionFilters = actionDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Action));
var filters = controllerFilters.Concat(actionFilters);
foreach(var filter in filters)
{
_kernel.Inject(filter.Instance);
}
return filters;
}
}
NinjectWebCommon CreateKernel Method
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
// Ad Ninject support for Web API.
GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
GlobalConfiguration.Configuration.Services.Add(typeof(IFilterProvider),
new NinjectWebApiFilterProvider(kernel));
RegisterServices(kernel);
return kernel;
}
NinjectWebCommon Bindings
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ServiceDbContext>().To<ServiceDbContext>();
kernel.Bind<IServiceRepository>().To<ServiceRepository>();
kernel.Bind<CareerDevelopmentDbContext>().To<CareerDevelopmentDbContext>();
kernel.Bind<ICareerDevelopmentRepository>().To<CareerDevelopmentRepository>();
kernel.Bind<ICareerDevelopmentService>().To<CareerDevelopmentService>();
kernel.Bind<IEventLogger>().To<ServiceEventLogger>();
kernel.Bind<IFilterProvider>().To<NinjectWebApiFilterProvider>().WithConstructorArgument("kernel", kernel);
}
I had the same problem and was configuring my error handler the same way by adding it to the filter collection in WebApiConfig.cs which meant it wasn't getting handled by the FilterProvider implementation I had added. So I did this instead:
public class LoggingExceptionFilterAttribute : ExceptionFilterAttribute, IExceptionFilter
{
// this is what I wanted injected
private IEmailService emailService;
public LoggingExceptionFilterAttribute(IEmailService service)
{
emailService = service;
}
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
// my implementation here
}
}
Then I registered this in NinjectWebCommon like so:
kernel.Bind<System.Web.Http.Filters.IExceptionFilter>().To<LoggingExceptionFilterAttribute>().InSingletonScope();
And then in WebApiConfig I realized that I could get a hold of the DependencyResolver so I did this:
config.Filters.Add((IFilter)config.DependencyResolver.GetService(typeof(IExceptionFilter)));
Now Ninject handles constructing my exception filter and I can even do constructor injection instead of needing [Inject] attributes and I don't have to add my ExceptionFilterAttribute to every API controller.
Ok, you have to make sure you are binding your custom IFilterProvider as well. As of writing the Ninject.Web.WebApi Nuget package is unstable and would do that automatically for you, if you were using it. Just in the same fashion Ninject.MVC3 does this for your regular controllers.
Just make sure you have this binding, and the replaced DependencyResolver will look for IFilterProvider implementation via your Ninject kernel as well:
kernel.Bind<IFilterProvider>().To<NinjectWebApiFilterProvider>();
Then your NinjectWebApiFilterProvider will kick in and inject dependencies into your filters as per your code.

Castle windsor wire generic irepository with 2 types

Hi I am trying to change a code example found here
http://imar.spaanjaars.com/577/aspnet-n-layered-applications-implementing-a-repository-using-ef-code-first-part-5
In his example he uses structure map, when I converted it to windsor I can get it to work with the one repository using the following.
container.Register(Component.For<IUnitOfWorkFactory>().ImplementedBy<EFUnitOfWorkFactory>(),
Component.For<IUnitOfWork>().ImplementedBy<EFUnitOfWork>(),
Component.For<Model.Repositories.IPeopleRepository>().ImplementedBy<PeopleRepository>().LifestyleTransient());
But what I really want to do is to map all the irepository based interfacees to thier implementation.
Here is the IRepository, T is the entity, K is the prmiary key type
public interface IRepository<T, K> where T : class
{
}
Its implementation Is
public abstract class Repository<T> : IRepository<T, int>, IDisposable where T : DomainEntity<int>
{
}
My controller has the interface IPeopleRepository as a constructor paramerter.
public interface IPeopleRepository : IRepository<Person, int>
{
}
public class PeopleRepository : Repository<Person>, IPeopleRepository
{
}
I want to have one register to register all repositories, something like this, but it wont match and i get the error Service 'Spaanjaars.ContactManager45.Model.Repositories.IPeopleRepository' which was not registered
container.Register(Component.For(typeof(IRepository<,>))
.ImplementedBy(typeof(Repository<>))
.LifestylePerWebRequest());
What am i missing in regards to this? is it because my irepository has 2 generic types?
In order to map all the IRepository based interfaces to their implementations .WithService.AllInterfaces() should be used.
This registration should solve your issue.
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(IRepository<,>))
.WithService.AllInterfaces()
.LifestylePerWebRequest());
There are some tests to test it. I claim they are green.
[TestClass]
public class InstallerTest
{
private IWindsorContainer container;
[TestInitialize]
public void Init()
{
container = new WindsorContainer().Install(new Installer());
}
[TestMethod]
public void ResilveTest_ResolvesViaIRepository()
{
// act
var repository = container.Resolve<IRepository<Person, int>>();
// assert
repository.Should().BeOfType<PeopleRepository>();
}
[TestMethod]
public void ResilveTest_ResolvesViaIPeopleRepository()
{
// act
var repository = container.Resolve<IPeopleRepository>();
// assert
repository.Should().BeOfType<PeopleRepository>();
}
}
public class Installer : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Classes.FromThisAssembly()
.BasedOn(typeof(IRepository<,>))
.WithService.AllInterfaces()
.LifestylePerThread());
}
}