How can I configure Web api dependency settings for NserviceBus 5 and later version.
Version 3 or 4 is like this:
public static class ConfigureWebApi
{
public static Configure ForWebApi(this Configure configure)
{
// Register our http controller activator with NSB
configure.Configurer.RegisterSingleton(typeof(IHttpControllerActivator),
new NSBHttpControllerActivator());
// Find every http controller class so that we can register it
var controllers = Configure.TypesToScan
.Where(t => typeof(IHttpController).IsAssignableFrom(t));
// Register each http controller class with the NServiceBus container
foreach (Type type in controllers)
configure.Configurer.ConfigureComponent(type, ComponentCallModelEnum.Singlecall);
// Set the WebApi dependency resolver to use our resolver
GlobalConfiguration.Configuration.ServiceResolver.SetResolver(new NServiceBusResolverAdapter(configure.Builder));
// Required by the fluent configuration semantics
return configure;
}
}
But Version 5 does not use Configure class, that use BusConfiguration
I try this but can not scan assemblies:
public static class ConfigureWebApi
{
public static BusConfiguration ForWebApi(this BusConfiguration configuration)
{
configuration.RegisterComponents(c => c.RegisterSingleton(typeof(IHttpControllerActivator),
new NServiceBusHttpControllerActivator()));
????
}
}
I'm not sure which way you're thinking. I'm asking, because I might be wrong with my answer. If so, let me know and I'll try to update it.
The way I go about this issue is setting up the container first and then have NServiceBus use that container. I'm using AutoFac and create a special class to set it up.
Disclaimer : I'm copying this from an existing app and didn't try nor compile it. I'm 100% sure this is working though, although I might've forgotten a line or added one too much! :)
public class DependenciesConfig
{
public static IContainer RegisterDependencies()
{
ContainerBuilder builder = new ContainerBuilder();
// MVC Controllers
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterControllers(Assembly.GetExecutingAssembly())
// WebAPI controllers
var config = GlobalConfiguration.Configuration;
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterWebApiFilterProvider(config);
// Way more registrations
// Next line is AutoFac specific for WebAPI
builder.RegisterFilterProvider();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
return container;
}
}
Then I have an additional class for registering NServiceBus. I don't have handlers in my web app, nor do I publish messages, so I use a SendOnly endpoint.
public class ServiceBus
{
public static ISendOnlyBus Bus { get; private set; }
private static readonly object padlock = new object();
public static void Init(ILifetimeScope container)
{
if (Bus != null) return;
NServiceBus.Logging.LogManager.Use<CommonLoggingFactory>();
lock (padlock)
{
if (Bus != null) return;
var configuration = new BusConfiguration();
configuration.UseSerialization<JsonSerializer>();
configuration.UseContainer<AutofacBuilder>(x => x.ExistingLifetimeScope(container));
configuration.UseTransport<AzureStorageQueueTransport>();
ConventionsBuilder conventions = configuration.Conventions();
conventions.DefiningCommandsAs(t => t.Namespace != null && t.Namespace.StartsWith("Messages") && t.Namespace.EndsWith("Commands"));
Bus = NServiceBus.Bus.CreateSendOnly(configuration);
}
}
}
Is this what you're looking for?
Related
I am trying to create Singleton CacheManager class that has dependency on IMemoryCache.
public class CacheManager:ICacheManager
{
private readonly IMemoryCache _cache;
public CacheManager(IMemoryCache cache)
{
_cache = cache;
}
public void LoadCache(MyData data)
{
// load cache here at startup from DB
}
}
I also have a Scoped service that retrives data from the database
public class LookupService:ILookupService
{
private readonly MyDatabaseContext _dbContext;
public class LookupService(MyDatabaseContext dbContext)
{
_dbContext = dbContext;
}
public void Dispose()
{
//Dispose DBContext here
}
// some async methods that returns lookup collection
}
Register these services in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
// EF
services.AddDbContext<MyDatabaseContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
// domain services
services.AddScoped<ILookupService, LookupService>();
services.AddMemoryCache();
// singleton
services.AddSingleton<CacheManager>(sp=>
{
using(var scope = sp.CreateScope())
{
using (var service = scope.ServiceProvider.GetService<ILookupService>())
{
how do i create cacheManager instance by injecting IMemoryCache and also register callback function
}
}
});
}
ILookupService is registered as Scoped service becuase it has dependency on DBContext which is also (by default) registered with Scoped lifetime. I do not want to change lifetime of these services.
However I want CacheManager to be registered as Singleton, that means I cannot inject ILookupService as dependency into CacheManager.
So here is my possible solution to create & register singleton instance of CacheManager
services.AddSingleton<CacheManager>(sp=>
{
using(var scope = sp.CreateScope())
{
using (var lookupService = scope.ServiceProvider.GetService<ILookupService>())
{
var cache = scope.ServiceProvider.GetService<IMemoryCache>();
var manger = new CacheManager(cache);
manger.LoadCache(lookupService.GetData());
return manger;
}
}
});
Not sure this is the best way to create CacheManager. How do I implement a callback function to re-populate CacheEntry if it becomes null?
I guess I would simply configure services.AddSingleton<CacheManager>();
(CacheManager having a default constructor)
After configuring all of the DI dependencies and having a serviceprovider, get the Cachemanager singleton and initialize it with LoadCache.
(so let DI create "empty" singleton cachemanager, but initialize immediately somewhere in startup of application)
var cachemanager = scope.ServiceProvider.Get<CacheManager>();
var lookupService = scope.ServiceProvider.Get<ILookupService>();
var cache = scope.ServiceProvider.Get<IMemoryCache>();
cachemanager.Cache = cache;
cachemanager.LoadCache(lookupService.GetData());
Looks like the underlying issue is that ILookupService cannot be resolved until runtime and requests start coming in. You need to create CacheManager before this.
DI COMPOSITION
This should be done when the app starts - as in this class of mine. Note the different lifetimes for different types of object but I just focus on creating the objects rather than interactions.
DI RESOLUTION
.Net uses a container per request pattern where scoped objects are stored against the HttpRequest object. So a singleton basically needs to ask for the current ILookupService, which is done by calling:
container.GetService<ILookupService>
So include the DI container as a constructor argument to your CacheManager class and you will be all set up. This is the service locator pattern and is needed to meet your requirement.
An alternative per request resolution mechanism is via the HttpContext object as in this class, where the following code is used:
IAuthorizer authorizer = (IAuthorizer)this.Context.RequestServices.GetService(typeof(IAuthorizer));
SUMMARY
The important thing is to understand the above design pattern, and you can then apply it to any technology.
register Cache service as singleton, try below code
public class CacheService : ICacheService
{
private ObjectCache _memoryCache;
/// <summary>
/// Initializes a new instance of the <see cref="CacheService"/> class.
/// </summary>
public CacheService()
{
this._memoryCache = System.Runtime.Caching.MemoryCache.Default;
}
}
I am using Autofac to inject all my project dependencies which is working great. Now I have added a Custom Authorization attribute (I don't need very complex functionality like OWIN and Identity stuff). The custom authorization attribute has dependency to data layer and therefore I am trying to inject it as a property injection. However the property is always Null. The code is below:
public class CustomAuthorizationFilterAttribute : AuthorizeAttribute, IAutofacAuthorizationFilter
{
public IAuthorisationHelper AuthorisationHelper { get; set; }
public override void OnAuthorization(HttpActionContext actionContext)
{
**... removed for brevity**
**// TODO: this should be injected by autofac and is always null??**
if (AuthorisationHelper.IsValidUser(username, password, out roleOfUser))
{
var principal =
new GenericPrincipal((new GenericIdentity(username)),
(new[] { roleOfUser }));
Thread.CurrentPrincipal = principal;
return;
}
... removed for brevity
}
}
Code that injects the AuthorizationHelper:
public static IContainer Container()
{
var builder = new ContainerBuilder();
var assemblies = new List<Assembly>();
assemblies.Add(Assembly.Load("Kids.Math.Interfaces"));
assemblies.Add(Assembly.Load("Kids.Math.Data"));
assemblies.Add(Assembly.Load("Kids.Math.Business"));
assemblies.Add(Assembly.Load("Kids.Math.ImportExport"));
assemblies.Add(Assembly.Load("Kids.Math.Common"));
assemblies.Add(Assembly.Load("Kids.Math.Api"));
builder.RegisterAssemblyTypes(assemblies.ToArray()).
AsImplementedInterfaces();
builder.RegisterType(typeof(MathContext)).As(typeof (DbContext)).InstancePerRequest();
// Register web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
// TODO: this is not working, also this should be generic to register it for all controllers
// inject the authorisation filter
builder.RegisterType<AuthorisationHelper>().As<IAuthorisationHelper>();
builder.Register(c => new CustomAuthorizationFilterAttribute()).PropertiesAutowired()
.AsWebApiAuthorizationFilterFor<QuestionsImportController>()
.InstancePerRequest();
// Set the dependency resolver to be Autofac.
var container = builder.Build();
return container;
}
Attribute is registered in FilterConfig as
filters.Add(new CustomAuthorizationFilterAttribute());
All the wiring up works but AuthorisationHelper is always null.
Any comments will be appreciated.
Aren't you missing some key registration steps here? Refer to the Autofac doco
// OPTIONAL: Register the Autofac filter provider.
builder.RegisterWebApiFilterProvider(config);
// Set the dependency resolver to be Autofac.
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
EDIT: After being told that the configuration has been setup correctly, have you tried registering your filter like this?
builder.RegisterType<CustomAuthorizationFilterAttribute>().PropertiesAutowired()
.AsWebApiAuthorizationFilterFor<QuestionsImportController>()
.InstancePerRequest();
seems like this is a known bug in autofac:
https://code.google.com/p/autofac/issues/detail?id=289
I'm trying to send a command from a filter in my MVC4 project to my command processor.
The problem:
I can't get an NServiceBus instance in the filter to fill.
The components:
ASP.NET MVC 4
NServiceBus version 3
StructureMap
The Attribute/Filter:
namespace AMS.WebApp.Filters
{
public class AMSAuthorizeAttribute : AuthorizeAttribute
{
public IBus Bus { get; set; }
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
bool accessGranted = false;
accessGranted = base.AuthorizeCore(httpContext);
// arbitrary command, don't worry about it
// Why is Bus still null?
var requestAccess = new RequestingAccess();
Bus.Send("AMS.AccessControl.CommandProcessor", requestAccess);
//if(isAdmin)
// accessGranted = true;
#if DEBUG
accessGranted = true;
#endif
return accessGranted;
}
}
}
The IOC Code:
using AMS.WebApp.Filters;
using NServiceBus;
using StructureMap;
namespace AMS.WebApp.DependencyResolution {
public static class IoC {
public static IContainer Initialize() {
ObjectFactory.Initialize(x =>
{
x.Scan(scan =>
{
scan.AssembliesFromApplicationBaseDirectory();
scan.WithDefaultConventions();
});
//This doesn't work
//x.SetAllProperties(y => y.OfType<IBus>());
//Neither does this
//x.ForConcreteType<AMSAuthorizeAttribute>()
// .Configure
// .Setter<IBus>(a => a.Bus)
// .IsTheDefault();
});
return ObjectFactory.Container;
}
}
}
Also, my attempt to bypass structuremap completely by passing in the bus instance from the controller resulted in:
An object reference is required for the non-static field, method, or property
At this point I'm pretty sure its something awkward with attributes/filters and structuremap, but I'm not really sure what that is.
WARNING: the accepted answer does not fix the actual problem of getting nservicebus in an action filter, but it does address how to get DI in an action filter. See ASP.NET MVC4 NServiceBus Attribute/Filter StructureMap for the Nservicebus specific question
Take a look at this post. I think this is what you're looking for.
http://lostechies.com/jimmybogard/2010/05/03/dependency-injection-in-asp-net-mvc-filters/
Edit:
I think you have two different issues here.
Using DI on a filter
Configuring DI on NServiceBus
Can you please post your code which initializes NServiceBus for StructureMap?
You are looking for somthing like this:
Configure.With().StructureMapBuilder()
Can anyone guide me on how I could register RavenDB using Autofac?
builder.Register<DocumentStore>(.. what after that?
Here is a sample console program that illustrates not only how to wire up the document store, but also how to set it up so you can just inject your document session:
using System.Threading.Tasks;
using Autofac;
using Raven.Client;
using Raven.Client.Document;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main()
{
var builder = new ContainerBuilder();
// Register the document store as single instance,
// initializing it on first use.
builder.Register(x =>
{
var store = new DocumentStore { Url = "http://localhost:8080" };
store.Initialize();
return store;
})
.As<IDocumentStore>()
.SingleInstance();
// Register the session, opening a new session per lifetime scope.
builder.Register(x => x.Resolve<IDocumentStore>().OpenSession())
.As<IDocumentSession>()
.InstancePerLifetimeScope()
.OnRelease(x =>
{
// When the scope is released, save changes
// before disposing the session.
x.SaveChanges();
x.Dispose();
});
// Register other services as you see fit
builder.RegisterType<OrderService>().As<IOrderService>();
var container = builder.Build();
// Simulate some activity. 5 users are placing orders simultaneously.
Parallel.For(0, 5, i =>
{
// Each user gets their own scope. In the real world this would be
// a new inbound call, such as a web request, and you would let an
// autofac plugin create the scope rather than creating it manually.
using (var scope = container.BeginLifetimeScope())
{
// Let's do it. Again, in the real world you would just inject
// your service to something already wired up, like an MVC
// controller. Here, we will resolve the service manually.
var orderService = scope.Resolve<IOrderService>();
orderService.PlaceOrder();
}
});
}
}
// Define the order service
public interface IOrderService
{
void PlaceOrder();
}
public class OrderService : IOrderService
{
private readonly IDocumentSession _session;
// Note how the session is being constructor injected
public OrderService(IDocumentSession session)
{
_session = session;
}
public void PlaceOrder()
{
_session.Store(new Order { Description = "Stuff", Total = 100.00m });
// we don't have to call .SaveChanges() here because we are doing it
// globally for the lifetime scope of the session.
}
}
// Just a sample of something to save into raven.
public class Order
{
public string Id { get; set; }
public string Description { get; set; }
public decimal Total { get; set; }
}
}
Note that DocumentStore is single instance, but DocumentSession is instance per lifetime scope. For this sample, I am manually creating the lifetime scopes and doing it in parallel, simulating how 5 different users might be placing orders at the same time. They will each get their own session.
Putting SaveChanges in the OnRelease event is optional, but will save you from having to put it in every service.
In the real world, this might be a web application, or a service bus application, in which case your session should be scoped to either the single web request or the lifetime of the message, respectively.
If you are using ASP.Net WebApi, you should go get the Autofac.WebApi package off NuGet and use their .InstancePerApiRequest() method, which automatically creates the appropriate lifetime scope.
I'm having some problems with Ninject's InRequestScope extension. It's looks like I'm getting new instances of the IDocumentSession within the same request. I'm running RavenDb as an embedded HttpServer with the ASP.NET MVC 4 beta. I have a bootstrapper class that looks like this:
public static class ApplicationBootstrapper
{
private static IKernel _kernel;
private static readonly IDocumentStore DocumentStore = new EmbeddableDocumentStore
{
DataDirectory = #"App_Data\RavenDb",
UseEmbeddedHttpServer = true
}.Initialize();
public static void Initialize()
{
DocumentStore.Conventions.IdentityPartsSeparator = "-";
_kernel = new StandardKernel();
_kernel.Bind<IUserService>().To<UserService>();
_kernel.Bind<IDocumentStore>().ToConstant(DocumentStore);
_kernel.Bind<IDocumentSession>().ToMethod(x =>
{
var store = x.Kernel.Get<IDocumentStore>();
return store.OpenSession();
}).InRequestScope();
}
public static IKernel Kernel
{
get { return _kernel; }
}
}
I tried settings the scope to InSingeltonScope. In that scenario I indeed get the same IDocumentSession but that of course is not what I want. Any suggestions on what I might be doing wrong here?
InRequestScope requires one of the Web Extensions. In your case you should install and use Ninject.MVC3 instead of an own Bootstrapper.