This project is read-only.

GetAllInstances method

Aug 21, 2014 at 9:52 PM
Edited Aug 27, 2014 at 7:35 PM
Hello,
I had the following implementation for a class QueryProcessor:
 public TResult Process<TResult>(INewQuery<TResult> newQuery) 
{
  var handlerType = typeof(INewQueryHandler<,>).MakeGenericType(newQuery.GetType(), typeof(TResult));
  IEnumerable<object> handlers = this.container.GetAllInstances(handlerType);    
  dynamic handler = handlers.ElementAt(0);
  return handler.Handle((dynamic)newQuery);
}
The INewQuery is defined as:
 public interface INewQuery<TResult> 
 { 
 } 
The INewQueryHandler is defined as:
 public interface INewQueryHandler<TNewQuery, TResult>
where TNewQuery : INewQuery<TResult>
{
TResult Handle(TNewQuery query);
} 
I register using container as shown below:
this.container = new SimpleInjector.Container();

this.container.RegisterManyForOpenGeneric(
    typeof(Cai.Apex.Library.Infrastructure.INewQueryHandler<,>),
    container.RegisterAll,
    assemblyLoader.GetAssemblies());
Now if I create a concrete query like:
 public class GetDriver : INewQuery<Apdriver> 
 {
public string DriverId { get; set; }
} 
Then create an instance of it:
 GetDriver driver = new GetDriver {DriverId = "AXN"}; 
Then invoke Process on queryProcessor:
 var result = this.queryProcessor.Process(driver); 
It all works fine and the container finds the handler for the query fine and all is good.

Now for another scenario, I just know the name of the query, in this case GetDriver and through a service call, I get the value for its property, "AXN".
I need to create an instance of the query GetDriver in this scenario. So up front, the registration of the all the INewQuery types is done and the name of the query and its type is stored in a dictionary.
 foreach (var assembly in assemblyLoader.GetAssemblies())
  {
    var types = from type in assembly.GetTypes()
                from i in type.GetInterfaces()
                where i.IsGenericType &&
                ((i.GetGenericTypeDefinition() == typeof(INewQuery<>)))
                select type;

    foreach (var type in types)
    {
      this.newBusinessTypes.Add(type.Name, type);
    }
  }
Later this newBusinessTypes is used to get the type using the name "GetQuery" that came in and an instance of it is created as shown below:
 var specificQuery = Activator.CreateInstance(matchedQuery);
(here matchedquery is the matching type for the query name).
The matchedquery is defined as dynamic type.

Then I invoke the queryprocessor process method doing:
 var result = this.queryProcessor.Process(specificQuery); 
What is happening in the Process method is that, the handlerType gets defined fine but the container.getallinstances for that type does not return a matching handler. So the next call to get the 0th element fails and so the Handle method cannot be invoked.

I am not sure, what is going wrong here and why the handler is not being retrieved by the container.

Please advise,

Thanks,

Amit
Aug 22, 2014 at 6:09 PM
In the second case you are still using the RegisterManyForOpenGeneric call? Otherwise the handlers will obviously be unknown to the container. Btw, why are you registering a collection? You would usually have a one to one mapping between a query and a handler.

Instead of reflecting over the assembly by hand, try using the BatchRegistrationExtensions.GetTypes method. This method is used under the covers by RegisterManyForOpenGeneric and this allows you to get the exact same types back.

I hope this helps.
Aug 22, 2014 at 7:30 PM
Edited Aug 27, 2014 at 7:36 PM
Hi dot_NET_Junkie,
Thanks for your response. Yes, I am using RegisterManyForOpenGeneric for the second case.
this.container.RegisterManyForOpenGeneric(
 typeof(Cai.Apex.Library.Infrastructure.INewQueryHandler<,>),
 container.RegisterAll,
 assemblyLoader.GetAssemblies());
Yes there is one to one mapping between the query and the handler. I couldn't get any other call on the register on the injector to work or rather couldn't understand how to use it . If you have a better way, could you post a code snippet and I will be definitely give it a try.

Regarding the BatchRegistrationExtensions.GetTypes method, could you post a sample for how to use it. I am using 2.5.2 version of SimpleInjector and couldn't find the call to BatchRegistrationExtentions.GetTypes method. Essentially, where I am stuck is that when I am trying to instantiate the query dynamically and I inject it to the QueryProcessor.Process method, the handler is not found. I added the container.Verify() and after doing that, I am able to see the handler being registered in there, i.e. the same handler that is found, when I pass in the concrete type of query. From what I can tell, the handlerType that is generated is looks identical to what was generated when concrete query was injected in.

I appreciate your input.

Thanks.
Aug 22, 2014 at 11:31 PM
To be honest, I have no clue why the type isn't resolved. Make sure the type is really the type you are expecting. If you switch from registering a collection to registering single types, the container will throw a pretty clear exception message and this might give you some clues. The way to do this is as follows:
this.container.RegisterManyForOpenGeneric(
    typeof(INewQueryHandler<,>),
    assemblyLoader.GetAssemblies()); 
In other words, remove the delegate call. The detault behavior of the.method is to do a one to one mapping.

About the other method, it is actually called GetTypesToRegister and you can use it like this:
var types = OpenGenericBatchRegistrationExtensions.GetTypesToRegister(
    _container,
    typeof (ICommandValidator<>), AccessibilityOption.PublicTypesOnly,
    typeof (ICommandValidator<>).Assembly)
    .ToList();
I copied this code from a recent sts koverflow answer; you will have to fill in yur own types. Sorry for my laziness; I'm currently in holiday mode :-)

You can use the list of returned types in your dictionary and even pass it on to an overload of RegisterManyForOpenGeneric that accepts a list of types.

I hope this helps.
Aug 26, 2014 at 3:13 AM
Hi,

Thanks for the response. I just wanted to mention that the logic, where the type is not found is when it runs from a web api controller being hosted inside a windows service. For it, I am registering the types into the injector and then injecting the injector into the controller. I can see the types registered in the container. But the type of query handler does not match to find the registered handler in the container. The same logic works from a windows application. I also tried the OpenGenericBatchRegistration option to get all query handlers registered and then find the matching handler for each query name and store in a dictionary. So when the query came in to the controller, I picked up the handler from the dictionary and ran the Handle method on it. That gives me the error of : An unexpected exception occurred when binding a dynamic operation.

Is there something different needed for the injector to work in a web api set up ?

Thanks.
Aug 26, 2014 at 5:24 PM
>> Is there something different needed for the injector to work in a web api set up ?

There's nothing special to Simple Injector when it comes to Web API. Simple Injector doesn't work differently when running inside Web API.
Aug 26, 2014 at 6:00 PM
Hi,
Thanks again for your response. I was able to determine the problem with not getting the handler in the other scenario. The types were not being registered correctly and am able to get it to work now. I was now trying to figure out, how to register the container for a web api request. I will query, if I have questions about it. I am using this link to get per web request set up:

https://simpleinjector.codeplex.com/wikipage?title=ObjectLifestyleManagement

I need to register a couple of objects per web api request.

Thanks much.
Aug 26, 2014 at 8:01 PM
Edited Aug 27, 2014 at 8:26 PM
Hello,

Actually, I had question on the scenario, I am using the container. The container is getting instantiated in a windows service base class with all registrations as shown below:
 this.container = new SimpleInjector.Container();
 this.container.Register<Ilog>(() => this.ApexLog);
 this.container.Register<User>(() => this.ApexUser);
 this.container.Register(() => this.database);
 this.container.Register<Configuration>(() => new Configuration(this.ApexUser));
 this.container.RegisterManyForOpenGeneric(typeof(Cai.Apex.Library.Infrastructure.INewQueryHandler<,>), container.RegisterAll, assemblyLoader.GetAssemblies());
This injector gets injected to a web api controller and in the HttpPost method. Now per the web request, I need to override the registration of User, Configuration before invoking call to : this.queryProcessor.Process(query) so that the handler can use specific User and Configuration.

I tried setting AllowOverridingRegistrations to true after the new Container(); Then override the User and the Configuration in the controller and it worked for the first web request. But for the second web request, I got error mentioning, that the container cannot be changed after the call to getallinstance.

What is the best and easy way to do this ?

Thanks much.
Aug 26, 2014 at 9:08 PM
Edited Oct 21, 2014 at 6:48 PM
First of all, it's good to understand why the container is locked after first use. You can read more about this here.

As you already experienced, AllowOverridingRegistrations doesn't do the trick. AllowOverridingRegistrations merely exist to replace a earlier made registration, before the container gets locked (and everything gets compiled down).

If I understand you correctly, you run a Windows Service that does two things. It runs some background process in which case you have a certain configured user that you use (the this.ApexUser). Besides this the Windows Service is a self hosted Web API service and during the handling of the requests you need the User of the current Web API request to be used, which is a different user than your this.ApexUser. Is that right?

If that's the case, I see a few options. Since you are running two different types of applications in the same AppDomain (you are running both a background service and a web service) a very valid and obvious solution is to give each 'virtual application' its own container instance. You can extract the common configuration lines into some Container CreateContainer() method and add the few missing configurations for each application. That means that the background service gets the this.container.Register<User>(() => this.ApexUser); line and your configuration of the Web API container gets a different registration for User. I personally think this is your best option. A benefit of this approach is that it could make your configuration much easier, since you'll often see configurational changes in how and which cross-cutting concerns (using decorators for instance) should be applied. Splitting this in multiple container instances makes this much easier. Downside of course is that if you have registrations that have to be truly appdomain-wide singletons, that need to be shared across containers, things get complicated again. But chances of needing that would typically be slim if you're really talking about two different applications that happen to run in the same AppDomain.

Another option is to use delegate registrations. For instance:
ScopedLifestyle lifestyle = new WebApiRequestLifestyle();

container.Register<User>(() =>
{
    bool runningInTheContextOfAWebApiRequest =
        lifestyle.GetCurrentScope(container) != null;

    if (runningInTheContextOfAWebApiRequest) {
       // TODO: return your Web API user here
    } else {
        return this.ApexUser;
    }
}
In this case you keep using the same container instance for both application types and have a check in the registered delegate that checks whether we're running in a Web API request or not.

I hope this helps.
Aug 26, 2014 at 9:49 PM
Edited Aug 27, 2014 at 8:17 PM
Sorry, I did not explain well at all. What we are doing is, that we are registering our queries, commands, query handlers, command handlers up front. An example of a command and command handler is shown below:
 public class InactivateCustomer : ICommand  { public string CustomerId { get; set; } } 

public class Customers: ICommandHandler<InactivateCustomer>
{ 
private User user; 
private dynamic database; 
public Customers(dynamic database, User user)
{ 
this.database = database;
this.user = user; 
} 

public void Handle(InactivateCustomer command) 
{ 
var customer = this.database.Customers.Get(command.CustomerId); 
customer.Active = false; 
customer.LastUpdatedBy = user.Id; 
this.database.Customers.Update(customer); 
} 
 // omit other handlers 
}  

Before registering the handler, we registered the User in the container. But for every request that comes in from the client via web api, we need to change this User before calling the Handle method on the Customers handler. What is the best way to do that ? Thanks much.
Aug 27, 2014 at 7:35 AM
Prevent injecting runtime data into services. Your user is probably runtime data and this leads to many complications. I've written more about this here, here and here.

Instead, inject an IUserContext of some sort that allows access to the User for that particular context/request.

And what's about that dynamic database? That sounds scary. For Simple Injector, that dynamic will simply be an System.Object, so there's no type information for Simple Injector (or yourself) available to work with. This might currently work in your case, but will stop working the moment you have a second dynamic dependency for some other registration. In a typed language like C#, always prefer working with types as much as you can.
Aug 27, 2014 at 4:54 PM
Hi,

Thanks for your response. Could you provide an example of how to use the IUserContext ? We would want to register this once only into the container, right ? I tried to register the User in the api controller but then it complained about the container cannot be changed when the next request came in. About the dynamic use, yes we will change it use a specific type.


Thanks again
Aug 27, 2014 at 5:11 PM
Edited Aug 27, 2014 at 7:33 PM
It depends on what solution you pick. If you go with one container per application-type, you will have two implementations, for instance:
// Implementation for the background service
public class FixedUserContext : IUserContext
{
   public FixedUserContext(User user) {
        this.User = user;
    }

    public User User { get; private set; }
}

// registered as follows:
container.RegisterSingle<IUserContext>(new FixedUserContext(this.ApexUser));

// Implementation for the Web API
public class WebApiUserContext : IUserContext
{
    public User User {
        get {
            // Do here what you need to do to get the proper user based on the
            // current Web API request. For instance:
            IPrincipal principal = HttpContext.Current.User;

            return new ApplicationUser(principal);
        }
    }
}

// registered as follows:
container.Register<IUserContext, WebApiUserContext>();
If you use a single container, the solution will be a bit more complex, but there are a few ways to do it. For instance, you can register a delegate as shown before:
ScopedLifestyle lifestyle = new WebApiRequestLifestyle();

// Register both implementations by their concrete type:
container.RegisterSingle<FixedUserContext>(new FixedUserContext(this.ApexUser));
container.RegisterSingle<WebApiUserContext>();

// Register the IUserContext
container.Register<IUserContext>(() =>
{
    bool runningInTheContextOfAWebApiRequest =
        lifestyle.GetCurrentScope(container) != null;

    if (runningInTheContextOfAWebApiRequest) {
       return container.GetInstance<WebApiUserContext>();
    } else {
        return container.GetInstance<FixedUserContext>();
    }
}
Another option is to move this logic to a proxy implementation:
public class ApplicationTypeUserContextProxy : IUserContext
{
    private readonly WebApiUserContext web;
    private readonly FixedUserContext fixed;
    private Func<bool> isInWebRequest;

    public ApplicationTypeUserContextProxy(WebApiUserContext web, FixedUserContext fixed, Func<bool> isInWebRequest) {
        this.web = web;
        this.fixed =fixed;
        this.isInWebRequest = isInWebRequest;
    }

    public User User {
        get { return this.isInWebRequest() ? this.web.User : this.fixed.User; }
    }
}

// Registered as follows:
ScopedLifestyle lifestyle = new WebApiRequestLifestyle();

container.Register<IUserContext>(() => new ApplicationTypeUserContextProxy(
    new WebApiUserContext(),
    new FixedUserContext(this.ApexUser),
    isInWebRequest: () => ifestyle.GetCurrentScope(container) != null);
I hope this helps
Aug 27, 2014 at 6:34 PM
Thanks for the response. We like the implementation of a single container.

ScopedLifestyle lifestyle = new WebApiLifestyle();

// Register both implementations by their concrete type:
container.RegisterSingle<FixedUserContext>(new FixedUserContext(this.ApexUser));
container.RegisterSingle<WebApiUserContext>();

// Register the IUserContext
container.Register<IUserContext>(() =>
{
bool runningInTheContextOfAWebApiRequest =
    lifestyle.GetCurrentScope(container) != null;

if (runningInTheContextOfAWebApiRequest) {
   return container.GetInstance<WebApiUserContext>();
} else {
    return container.GetInstance<FixedUserContext>();
}
}


Regarding the lifestyle.GetCurrentScope(container), what governs that it is running in the context of a web api request. I tried to do this code of setting the Boolean in the web api controller and it returned false.

Does the container need to be created in the web api ?

Thanks
Aug 27, 2014 at 7:17 PM
I'm not sure I follow you. Could you rephrase your question? I'm not sure what the problem or question is?
Aug 27, 2014 at 7:26 PM
Edited Aug 27, 2014 at 7:38 PM
What I mean is:

We are doing:
ScopedLifestyle lifestyle = new WebApiLifestyle(); 


bool runningInTheContextOfAWebApiRequest =
    lifestyle.GetCurrentScope(container) != null;
This is being done in the web api. The runningInTheContextOfAWebApiRequest is always returning false.

What triggers it to not return null for the scope ?

Thanks
Aug 27, 2014 at 7:46 PM
The WebApiRequestLifestyle.GetCurrentScope method returns null when there is no active scope. This will happen when your app is initializing, when you're running code on a background thread, or when HttpRequestMessage.GetCurrentScope() hasn't been called. The latter might be your problem. Take a look at this Stackoverflow question.

ps. You probably noticed yourself, but I made a typo in my posts. I referred to the non-existing WebApiLifestyle, but the correct type is WebApiRequestLifestyle, which is located in the SimpleInjector.Integration.WebApi namespace.
Aug 27, 2014 at 9:37 PM
Hello,
I followed along the example and added the request.GetDependencyScope() in the SendAsync method:

protected override async Task<HttpResponseMessage> SendAsync(
      HttpRequestMessage request, 
      CancellationToken cancellationToken)
    {
      request.GetDependencyScope();
      // Look for the authorization value in the request header
      var authValue = request.Headers.Authorization;
      var corrId = string.Format("{0}{1}", DateTime.Now.Ticks, Thread.CurrentThread.ManagedThreadId);
      var requestInfo = string.Format("{0} {1}", request.Method, request.RequestUri);
      var requestMessage = await request.Content.ReadAsByteArrayAsync();
      await this.IncomingMessageAsync(corrId, requestInfo, requestMessage);

      // Parse out the authorization parameter, i.e. user key that came in
      if (authValue != null && !string.IsNullOrWhiteSpace(authValue.Parameter))
      {
        RequestInfo parsedCredentials = this.ParseAuthorizationHeader(authValue.Parameter);
        if (parsedCredentials != null)
        {
          Thread.CurrentPrincipal = this.PrincipalProvider.CreatePrincipal(
            parsedCredentials.UserId, 
            parsedCredentials.UserKey);
        }
      }

      var response = await base.SendAsync(request, cancellationToken);
      byte[] responseMessage = null;
      if (response.IsSuccessStatusCode)
      {
        if (response.Content != null)
        {
          responseMessage = await response.Content.ReadAsByteArrayAsync();
        }
      }
      else
      {
        responseMessage = Encoding.UTF8.GetBytes(response.ReasonPhrase);
        if (response.StatusCode == HttpStatusCode.Unauthorized && !response.Headers.Contains(BasicAuthResponseHeader))
        {
          response.Headers.Add(BasicAuthResponseHeader, BasicAuthResponseHeaderValue);
        }
      }

      await this.OutgoingMessageAsync(corrId, requestInfo, responseMessage);
      return response;
    }
Now later I try to get the scope in a web api controller doing:
ScopedLifestyle lifestyle = new SimpleInjector.Integration.WebApi.WebApiRequestLifestyle();
 bool runningin = lifestyle.GetCurrentScope(this.container) != null;
I always get the Boolean, runningin as false.

Any idea ?

Thanks.
Aug 27, 2014 at 9:51 PM
Edited Oct 21, 2014 at 6:49 PM
Did you follow the Web API integration guide? Have you registered the SimpleInjectorWebApiDependencyResolver as default DependencyResolver? Without the SimpleInjectorWebApiDependencyResolver, a scope will never be started and lifestyle.GetCurrentScope will always return null.
Sep 5, 2014 at 7:39 PM
Just wanted to thank you for the help. Implementation seems to be working fine !