I'm getting null reference exception when trying to access a singleton class from my ASP.NET MVC Controller Action. I use Autofac as the IoC Container.
Here is the code:
Register dependencies method:
public static void RegisterDependencies()
{
var builder = new ContainerBuilder();
const string nameOrConnectionString = "name=DefaultConnection";
builder.RegisterApiControllers(typeof(WebApiConfig).Assembly);
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterModule<AutofacWebTypesModule>();
builder.RegisterGeneric(typeof(EntityRepository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope();
builder.RegisterGeneric(typeof(Service<>)).As(typeof(IService<>)).InstancePerLifetimeScope();
builder.RegisterType(typeof(UnitOfWork)).As(typeof(IUnitOfWork)).InstancePerLifetimeScope();
builder.Register<IEntitiesContext>(b =>
{
var logger = b.Resolve<ILogger>();
var context = new InterfaceContext(nameOrConnectionString, logger);
return context;
}).InstancePerRequest();
builder.Register(b => NLogLogger.Instance).SingleInstance();
builder.Register(b => UserControlHelper.Instance).SingleInstance();
builder.RegisterModule(new IdentityModule());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver =
new AutofacWebApiDependencyResolver(container);
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
UserControlHelper class:
public class UserControlHelper
{
private static volatile UserControlHelper _instance;
private static readonly object SyncRoot = new object();
private static IService<Administrator> _service;
private static IService<Customer> _customerService;
private UserControlHelper() { }
private UserControlHelper(IService<Administrator> service, IService<Customer> customerService)
{
_service = service;
_customerService = customerService;
}
public static UserControlHelper Instance
{
get
{
if (_instance == null)
{
lock (SyncRoot)
{
if (_instance == null)
_instance = new UserControlHelper(_service, _customerService);
}
}
return _instance;
}
}
public static string GetUserData(int userId, string type)
{
var getImage = _service.GetByIdAsync(userId);
switch (type)
{
case "Image":
{
return getImage.GetAwaiter().GetResult().Image;
}
case "Name":
{
return getImage.GetAwaiter().GetResult().FullName;
}
case "Email":
{
return getImage.GetAwaiter().GetResult().Email;
}
case "AllUsers":
{
return _customerService.GetCountAsync(userId).GetAwaiter().GetResult().ToString();
}
default:
return "No Data";
}
}
}
I'm calling it like this:
ViewBag.FullName = UserControlHelper.GetUserData(UserId, "Name");
Your _service variable is going to be null all the time. Hence you maybe getting the null referece.
private static IService<Administrator> _service;
This variable is never instantiated (manually or via Autofac)
And when you call your method, this is the code that might be causing the null reference.
var getImage = _service.GetByIdAsync(userId);
because _service is null
For all the Autofac wireup being done, there is no place we are indicating to Autofac that this class needs to be instantiated automatically. The class doesn't seem to be a controller (MVC or API) or any dependencies to the controller.
Also, the _service variable being static doesn't help with Autofac.
To solve the problem, you might want to rethink this class in terms of a controller or better, a dependency (constructor parameter) to a controller, with the _service and such variables as instance variables rather than static variables, where Autofac cannot help you much.
This way, when the controller is instantiated by Autofac, it'll automatically create an instance of 'UserControlHelper' for you.
Answering to your comment (You need a singleton of UserControlHelper):
you can leverage Autofac for this.
we'll make this class a constructor parameter of your controller.
And let Autofac know to instantiate this as a singleton.
public class MyController: Controller
{
public MyController(UserControlHelper helper)
{
ViewBag.FullName = helper.GetUserData(UserId, "Name");
}
}
And when you register this class with Autofac, you can do:
build.RegisterType<UserControlHelper>().SingleInstance();
This would mean that you have to remove the Instance variable and any singleton-like logic in your class. And also convert the static methods to instance methods. And convert the constructor to a public one.
It is best to let Autofac/frameworks do the grunt work of Singletons/other such functionality. (Lazy variables are another such tool)
And we can focus on keeping your class relevant to the business logic.
And if you really want to do the singleton implementation yourself, you can still register it with autofac as:
builder.RegisterInstance<UserControlHelper>(singletonInstanceYouConstructed);
But in general, I have found it to be simpler to let Autofac manage the whole lifetime management.
Related
The problem is that the Azure WebJobs SDK supports only public static methods as job entry-points which means there is no way of implementing constructor/property injection.
I am unable to find anything about this topic in official WebJobs SDK documentation/resources. The only solution that I came across is based on service locator (anti) pattern described on this post here.
Is there a good way to use "proper" dependency injection for projects based on Azure WebJobs SDK?
Azure WebJobs SDK now supports instance methods. Combining this with a custom IJobActivator allows you to use DI.
First, create the custom IJobActivator that can resolve a job type using your favourite DI container:
public class MyActivator : IJobActivator
{
private readonly IUnityContainer _container;
public MyActivator(IUnityContainer container)
{
_container = container;
}
public T CreateInstance<T>()
{
return _container.Resolve<T>();
}
}
You need to register this class using a custom JobHostConfiguration:
var config = new JobHostConfiguration
{
JobActivator = new MyActivator(myContainer)
};
var host = new JobHost(config);
Then, you can use a simple class with instance methods for your jobs (here I'm using Unity's constructor injection feature):
public class MyFunctions
{
private readonly ISomeDependency _dependency;
public MyFunctions(ISomeDependency dependency)
{
_dependency = dependency;
}
public Task DoStuffAsync([QueueTrigger("queue")] string message)
{
Console.WriteLine("Injected dependency: {0}", _dependency);
return Task.FromResult(true);
}
}
This is how I handled scoping using the new SDK. Using the IJobactivator as described by Alexander Molenkamp.
public class ScopedMessagingProvider : MessagingProvider
{
private readonly ServiceBusConfiguration _config;
private readonly Container _container;
public ScopedMessagingProvider(ServiceBusConfiguration config, Container container)
: base(config)
{
_config = config;
_container = container;
}
public override MessageProcessor CreateMessageProcessor(string entityPath)
{
return new CustomMessageProcessor(_config.MessageOptions, _container);
}
private class CustomMessageProcessor : MessageProcessor
{
private readonly Container _container;
public CustomMessageProcessor(OnMessageOptions messageOptions, Container container)
: base(messageOptions)
{
_container = container;
}
public override Task<bool> BeginProcessingMessageAsync(BrokeredMessage message, CancellationToken cancellationToken)
{
_container.BeginExecutionContextScope();
return base.BeginProcessingMessageAsync(message, cancellationToken);
}
public override Task CompleteProcessingMessageAsync(BrokeredMessage message, FunctionResult result, CancellationToken cancellationToken)
{
var scope = _container.GetCurrentExecutionContextScope();
if (scope != null)
{
scope.Dispose();
}
return base.CompleteProcessingMessageAsync(message, result, cancellationToken);
}
}
}
You can the use your custom MessagingProvider in your JobHostConfiguration like
var serviceBusConfig = new ServiceBusConfiguration
{
ConnectionString = config.ServiceBusConnectionString
};
serviceBusConfig.MessagingProvider = new ScopedMessagingProvider(serviceBusConfig, container);
jobHostConfig.UseServiceBus(serviceBusConfig);
After asking my own question about how to handle scoping ... I've just came up to this solution: I don't think this is ideal but I couldn't find any other solution for the moment.
In my example I am dealing with ServiceBusTrigger.
As I am using SimpleInjector, the implementation of the IJobActivator interface looks like that:
public class SimpleInjectorJobActivator : IJobActivator
{
private readonly Container _container;
public SimpleInjectorJobActivator(Container container)
{
_container = container;
}
public T CreateInstance<T>()
{
return (T)_container.GetInstance(typeof(T));
}
}
Here, I am dealing with Triggered webjobs.
So I have two dependencies:
A singleton:
public interface ISingletonDependency { }
public class SingletonDependency : ISingletonDependency { }
And another that need to live only the time my function is triggered:
public class ScopedDependency : IScopedDependency, IDisposable
{
public void Dispose()
{
//Dispose what need to be disposed...
}
}
So in order to have a process that run independently from the webjob. I've encapsulated my process into a class :
public interface IBrokeredMessageProcessor
{
Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token);
}
public class BrokeredMessageProcessor : IBrokeredMessageProcessor
{
private readonly ISingletonDependency _singletonDependency;
private readonly IScopedDependency _scopedDependency;
public BrokeredMessageProcessor(ISingletonDependency singletonDependency, IScopedDependency scopedDependency)
{
_singletonDependency = singletonDependency;
_scopedDependency = scopedDependency;
}
public async Task ProcessAsync(BrokeredMessage incommingMessage, CancellationToken token)
{
...
}
}
So now when the webjob starts, I need to register my dependencies depending their scopes:
class Program
{
private static void Main()
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.RegisterSingleton<ISingletonDependency, SingletonDependency>();
container.Register<IScopedDependency, ScopedDependency>(Lifestyle.Scoped);
container.Register<IBrokeredMessageProcessor, BrokeredMessageProcessor>(Lifestyle.Scoped);
container.Verify();
var config = new JobHostConfiguration
{
JobActivator = new SimpleInjectorJobActivator(container)
};
var servicebusConfig = new ServiceBusConfiguration
{
ConnectionString = CloudConfigurationManager.GetSetting("MyServiceBusConnectionString")
};
config.UseServiceBus(servicebusConfig);
var host = new JobHost(config);
host.RunAndBlock();
}
}
And this is the triggered job:
Only have one dependency : the IoC container. Because this class is part of my composition root, it should be ok.
It handle the scope into the triggered function.
public class TriggeredJob
{
private readonly Container _container;
public TriggeredJob(Container container)
{
_container = container;
}
public async Task TriggeredFunction([ServiceBusTrigger("queueName")] BrokeredMessage message, CancellationToken token)
{
using (var scope = _container.BeginExecutionContextScope())
{
var processor = _container.GetInstance<IBrokeredMessageProcessor>();
await processor.ProcessAsync(message, token);
}
}
}
I've used a couple patterns that rely on the concept of child containers/scopes (depending on the terminology of your IoC container of choice). Not sure which ones support it, but I can tell you that StructureMap 2.6.x and AutoFac do.
The idea is to spin up a child scope for each message coming in, inject any context that's unique to that request, resolve the top-level object from the child scope, and then run your process.
Here's some generalized code showing it with AutoFac. It does do a direct resolve from the container, similar to the anti-pattern you're attempting to avoid, but it's been isolated to one place.
In this case, it's using a ServiceBusTrigger to fire the job, but could be anything - a job host could potentially have a list of these for the different queues/processes.
public static void ServiceBusRequestHandler([ServiceBusTrigger("queuename")] ServiceBusRequest request)
{
ProcessMessage(request);
}
This method is called by all instances of the above methods. It wraps creation of the child scope in a using block to make sure things are cleaned up. Then, any objects that would vary per request and contain context used by other dependencies (user/client information, etc) would be created and injected into the child container (in this example, the IRequestContext). Finally, the component doing the work would be resolved from the child container.
private static void ProcessMessage<T>(T request) where T : IServiceBusRequest
{
try
{
using (var childScope = _container.BeginLifetimeScope())
{
// create and inject things that hold the "context" of the message - user ids, etc
var builder = new ContainerBuilder();
builder.Register(c => new ServiceRequestContext(request.UserId)).As<IRequestContext>().InstancePerLifetimeScope();
builder.Update(childScope.ComponentRegistry);
// resolve the component doing the work from the child container explicitly, so all of its dependencies follow
var thing = childScope.Resolve<ThingThatDoesStuff>();
thing.Do(request);
}
}
catch (Exception ex)
{
}
}
All answers to the question are outdated now. Using the latest packages you can easily get constructor injection right out of the box. Two steps are only required:
Create the event handler function as an instance method in a non-static class. Let's call the class QueueFunctions.
Add your class to the list of services.
builder.ConfigureServices(services =>
{
// Add
// dependencies
// here
services.AddScoped<QueueFunctions>();
});
Now, you'll be able to inject dependencies through the constructor.
I'm trying to implement dependency injection in my ASP.NET MVC Project using Unity and would like some advice on how to avoid circular references.
At my work we used to implement the service locator pattern, which returned a singleton for each individual service of the application.
public class ServiceWrapper
{
private UserService _userService;
private ProductService _productService;
public UserService User
{
if(_userService == null)
{
_userService = new UserService();
}
return _userService;
}
public ProductService Product
{
if(_productService == null)
{
_productService = new ProductService();
}
return _productService;
}
}
Then in the controller, you could easily access all the services by instantiating the ServiceWrapper and calling methods, like:
private ServiceWrapper _services = new ServiceWrapper();
public ActionResult Index()
{
List<Product> products = _services.Product.GetProducts();
return View(products);
}
Setting up DI using Unity was a breeze. I created a container in Application_Start() (global.asax), like so:
var container = new UnityContainer();
container.RegisterType<IUserService, UserService>(new ContainerControlledLifetimeManager());
container.RegisterType<IProductService, ProductService>(new ContainerControlledLifetimeManager());
container.RegisterType<IServiceWrapper, ServiceWrapper>(new ContainerControlledLifetimeManager());
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
The ServiceWrapper is registered as a Singleton. And implemented constructor injection as follows:
public class ProductController: Controller
{
private IServiceWrapper _services;
public ProductController(IServiceWrapper services)
{
_services = services;
}
public ActionResult Index()
{
List<Product> products = _services.Products.GetProducts();
return View(products);
}
That worked beautifully. But then I came accross the problem.
We like every service to also have a property containing the ServiceWrapper, so that you can easily access the other services from within another, like so:
public class ProductService
{
private IServiceWrapper _services;
public ProductService(IServiceWrapper services)
{
_services = services;
}
public IServiceWrapper Services { get { return _services; } }
}
But when I implemented constructor injection of the ServiceWrapper in the individual services, it resulted in a stackoverflow exception due to circular referencing.
I read that Unity does not support circular referencing. Is there a (solid) way around this. Or should I implement a different architecture? If so, could you recommend a solution?
The way this is typically done is to declare just the services you need and have them ctor-injected. Don't inject a "ServiceWrapper" which just contains everything. Inject what you need. As the container builds up your type you don't have to worry about providing the services. They will be just there.
The development workflow often goes like this:
Add a new dependency injected field
Delete the existing ctor
Regenerate the ctor using Resharper: alt+ins, generate ctor.
In my bootstrapper:
namespace Conduit.Mam.ClientServices.Common.Initizliaer
{
public static class Initializer
{
private static bool isInitialize;
private static readonly object LockObj = new object();
private static IUnityContainer defaultContainer = new UnityContainer();
static Initializer()
{
Initialize();
}
public static void Initialize()
{
if (isInitialize)
return;
lock (LockObj)
{
IUnityContainer container = defaultContainer;
//registering Unity for MVC
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
//registering Unity for web API
// GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
#region managers
container.RegisterType<ISettingsManager, SettingsManager>();
container.RegisterType<IMamDataManager, MamDataManager>();
container.RegisterType<IAppsDataManager, AppsDataManager>();
#endregion
if (!isInitialize)
{
isInitialize = true;
}
}
}
}
}
in my controller's code:
ISettingsManager sm = mUnityContainer.Resolve<ISettingsManager>();
hovering on mUnityContainer I see ISettingsManager is mapped to SettingsManager
but then I get the error:
Exception is: InvalidOperationException - The current type, is an
interface and cannot be constructed. Are you missing a type mapping?
I have also tried
ISettingsManager sm = (ISettingsManager)mUnityContainer.Resolve<>(typeof(ISettingsManager));
but no use
Just for others (like me) who might have faced the above error. The solution in simple terms.
You might have missed to register your Interface and class (which implements that inteface) registration in your code.
e.g if the error is
"The current type, xyznamespace. Imyinterfacename, is an interface and cannot be constructed. Are you missing a type mapping?"
Then you must register the class which implements the Imyinterfacename in the UnityConfig class in the Register method. using code like below
container.RegisterType<Imyinterfacename, myinterfaceimplclassname>();
You are incorrectly using Dependency Injection. The proper way is to have your controllers take the dependencies they need and leave to the dependency injection framework inject the concrete instances:
public class HomeController: Controller
{
private readonly ISettingsManager settingsManager;
public HomeController(ISettingsManager settingsManager)
{
this.settingsManager = settingsManager;
}
public ActionResult Index()
{
// you could use the this.settingsManager here
}
}
As you can see in this example the controller doesn't know anything about the container. And that's how it should be.
All the DI wiring should happen in your Bootstraper. You should never use container.Resolve<> calls in your code.
As far as your error is concerned, probably the mUnityContainer you are using inside your controller is not the same instance as the one constructed in your Bootstraper. But since you shouldn't be using any container code in your controllers, this shouldn't be a problem anymore.
In my case, I was getting this error despite registering an existing instance for the interface in question.
Turned out, it was because I was using Unity in WebForms by way of the Unity.WebForms Nuget package, and I had specified a Hierarchical Lifetime manager for the dependency I was providing an instance for, yet a Transient lifetime manager for a subsequent type that depended on the previous type - not usually an issue - but with Unity.WebForms, the lifetime managers work a little differently... your injected types seem to require a Hierarchical lifetime manager, but a new container is still created for every web request (because of the architecture of web forms I guess) as explained excellently in this post.
Anyway, I resolved it by simply not specifying a lifetime manager for the types/instances when registering them.
i.e.
container.RegisterInstance<IMapper>(MappingConfig.GetMapper(), new HierarchicalLifetimeManager());
container.RegisterType<IUserContext, UserContext>(new TransientLifetimeManager());
becomes
container.RegisterInstance<IMapper>(MappingConfig.GetMapper());
container.RegisterType<IUserContext, UserContext>();
So that IMapper can be resolved successfully here:
public class UserContext : BaseContext, IUserContext
{
public UserContext(IMapper _mapper) : base(_mapper)
{
}
...
}
In my case, I have used 2 different context with Unitofwork and Ioc container so i see this problem insistanting while service layer try to make inject second repository to DI. The reason is that exist module has containing other module instance and container supposed to gettng a call from not constractured new repository.. i write here for whome in my shooes
May be You are not registering the Controllers.
Try below code:
Step 1.
Write your own controller factory class
ControllerFactory :DefaultControllerFactory by implementing defaultcontrollerfactory
in models folder
public class ControllerFactory :DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
throw new ArgumentNullException("controllerType");
if (!typeof(IController).IsAssignableFrom(controllerType))
throw new ArgumentException(string.Format(
"Type requested is not a controller: {0}",
controllerType.Name),
"controllerType");
return MvcUnityContainer.Container.Resolve(controllerType) as IController;
}
catch
{
return null;
}
}
public static class MvcUnityContainer
{
public static UnityContainer Container { get; set; }
}
}
Step 2:Regigster it in BootStrap:
inBuildUnityContainer method
private static IUnityContainer BuildUnityContainer()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
//RegisterTypes(container);
container = new UnityContainer();
container.RegisterType<IProductRepository, ProductRepository>();
MvcUnityContainer.Container = container;
return container;
}
Step 3:
In Global Asax.
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
Bootstrapper.Initialise();
ControllerBuilder.Current.SetControllerFactory(typeof(ControllerFactory));
}
And you are done
I had this problem, and the cause was that I had not added the Microsoft.Owin.Host.SystemWeb NuGet package to my project. Although the code in my startup class was correct, it was not being executed.
So if you're trying to solve this problem, put a breakpoint in the code where you do the Unity registrations. If you don't hit it, your dependency injection isn't going to work.
Below code will be helpful for you
public static IUnityContainer Initialise(IUnityContainer container = null)
{
if (container == null)
{
container = new UnityContainer();
}
container.RegisterType<ISettingsManager, SettingsManager>();
container.Resolve<SettingsManager>();
container.RegisterType<SettingsManagerController>(new InjectionProperty("_SettingManagerProvider", new ResolvedParameter<ISettingManager>()));
return container;
}
In a class I am using this code:
public User CurrentUser
{
get
{
var unityContainer = new UnityContainer();
var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
return httpContextHelper.GetUser();
}
}
This is in the Bootstrapper.cs file:
public static class Bootstrapper
{
public static void Initialise()
{
IUnityContainer unityContainer = new UnityContainer();
unityContainer.RegisterType<IHttpContextHelper, HttpContextHelper>();
DependencyResolver.SetResolver(new UnityDependencyResolver(unityContainer));
}
}
I cannot use constructor injection here because it is a base class and it would take quite some work to refactor.
But how would I unit test this? I cannot find a suitable method to mock unityContainer.Resolve.
First things first the following code is wrong:
get
{
var unityContainer = new UnityContainer();
var httpContextHelper = unityContainer.Resolve<HttpContextHelper>();
return httpContextHelper.GetUser();
}
You are creating a new Unity container which of course is empty and then you are attempting to resolve some instances from this container which would simply call the default constructor of the HttpContextHelper class. Gosh I hate Unity for not throwing an exception when you attempt to resolve an instance of something that has never been registered into the container (which is what you are doing here). Instead it is silently calling its constructor with most known (registered) dependencies.
So this will not return the instance you have registered in your Bootstrapper because there you have a different instance of the UnityContainer in which you have registered the IHttpContextHelper instance.
So the first step towards refactoring this is to use the DependencyResolver:
public User CurrentUser
{
get
{
var httpContextHelper = DependencyResolver
.Current
.GetService<IHttpContextHelper>();
return httpContextHelper.GetUser();
}
}
Now in your unit test you could write a custom dependency resolver:
public class DepepndecyResolverMock : IDependencyResolver
{
private readonly IDictionary<Type, object> kernel;
public DepepndecyResolverMock(IDictionary<Type, object> kernel)
{
this.kernel = kernel;
}
public object GetService(Type serviceType)
{
return this.kernel[serviceType];
}
public IEnumerable<object> GetServices(Type serviceType)
{
throw new NotImplementedException();
}
}
which you could configure for your tests:
var kernel = new Dictionary<Type, object>
{
{ typeof(IHttpContextHelper), new HttpContextHelperMock() }
};
DependencyResolver.SetResolver(new DepepndecyResolverMock(kernel));
This being said, this code is still horribly wrong. It might allow you to unit test it but please I insist, this is wrong design. Do not use it. This uses the service locator pattern which is an anti-pattern.
The proper way to do this is to invert the control of this class so that it doesn't need to fetch its dependencies, but its dependencies need to be injected into it. So instead of wasting your time in useless patterns, refactor your code so that it uses real dependency injection.
I heared this should be possible, but I can not imagine how this should work.
I am using Dependency Injection (autofac) for my project. I develop a project with someone else and call the methods of his classes (I use his assembly).
Then I get an instance of an object which the other person should use for his operations.
We want to avoid passing this object instance on every method and use autofac.
Can he resolve this instance in his assembly project without passing any parameter?
I think we have to pass at least the DI-Container... But I heard that the concept of Dependency Injection should make it possible that you can resolve objects in the whole "execution context" and get the same one.
Here is an example with the asp.net web api:
This is a api controller of a asp.net webapi project:
public class DocumentsController : ApiController
{
// GET /api/documents
public HttpResponseMessage Get()
{
// Here I call the method of the other developer,
// security/authorization should be handled in
// his method!
// In this context the WebAPI provides the
// IPrincipal of the current user in this
// variable => "HttpContext.Current.User" but we
// don't want to pass it on every method call
ClassFromOtherAssembly.GetDocuments();
HttpResponseMessage response =
Request.CreateResponse<IEnumerable<Document>>(
HttpStatusCode.OK, documents);
return response;
}
}
This is the class of the other developer. He should deliver the documents and check if the user is authorized:
public class ClassFromOtherAssembly
{
public List<Documents> GetDocuments()
{
//Security check
IPrincipal principal =
DI_Container.Resolve(IPrincipal);
if(principal.IsInRole("Admin"))
{
//return the list
}
else
{
//return empty list
}
}
}
No, do not pass the container itself, you will end up with a Service Locator patter, and if you do a quick search you will understand that this pattern has a rotten smell.
public class Foo
{
private IContainer container;
private IBar bar;
public Foo( IContainer container) //no-no
{
this.container = container;
this.bar = container.Resolve<IBar>();
}
}
Instead use proper DI, like
public class Foo
{
private IBar bar;
public Foo(IBar bar)
{
this.bar = bar;
}
}
It doesn't really matter in which assembly your types are. This is the whole point of IoC and DI - to decouple parts of the application and make you depend on abstractions, rather than concrete implementations.
Edit
You misunderstood Service locator pattern with DI. "Instead of passing a parameter we want to use Dependency Injection" - passing a parameter is a DI, in contrast, resolving a type from a static container is a service locator.
public class DocumentsController : ApiController
{
public HttpResponseMessage Get()
{
ClassFromOtherAssembly.GetDocuments(); //this is Service locator
//really bad for testability and maintenance
...
}
}
DI looks like this
public class DocumentsController : ApiController
{
private IDocumentProvider;
public DocumentsController(IDocumentProvider provider)
{
this.provider = provider;
}
public HttpResponseMessage Get()
{
provider.GetDocuments(); //this is DI
...
}
}
You're using the ServiceLocator (anti-pattern) by calling Resolve directly from GetDocuments()
Use inversion of control with constructor injection to pass in the IPrinciple thus:
public class ClassFromOtherAssembly
{
private IPrincipal principal;
public ClassFromOtherAssembly(IPrincipal principal)
{
this.principal = principal;
}
public List<Documents> GetDocuments()
{
//Security check
if (principal.IsInRole("Admin"))
{
//return the list
}
else
{
//return empty list
}
}
}