Accessing an HttpServletRequest from inside an AXIS2 module - axis2

I am implementing AXIS2 services in my web application. Our client's production boxes are a bit flaky, so I want a heads up when performance degraded. Specifically:
request comes into my AXIS2 service
measure the time that the request takes
if the time is greater than X, log an error
So I wrote an AXIS2 module like this:
public class PerformanceHandler extends AbstractHandler implements Handler {
protected Logger logger = null;
public PerformanceHandler() {
logger = LoggerFactory.getLogger( this.getClass() );
}
public InvocationResponse invoke( MessageContext msgContext ) throws AxisFault {
HttpServletRequest r = ( HttpServletRequest )msgContext.getProperty( HTTPConstants.MC_HTTP_SERVLETREQUEST );
if( msgContext.getFLOW() == MessageContext.IN_FLOW || msgContext.getFLOW() == MessageContext.IN_FAULT_FLOW ) {
// incoming request
Date timeIn = new Date( System.currentTimeMillis() );
r.setAttribute( this.getClass().getName() + ".timeIn", timeIn );
if( logger.isDebugEnabled() ) {
logger.debug( "Request " + r.toString() + " started processing at " + timeIn );
}
} else {
// outgoing response
Date timeIn = ( Date )r.getAttribute( this.getClass().getName() + ".timeIn" );
Date timeOut = new Date( System.currentTimeMillis() );
if( logger.isDebugEnabled() ) {
logger.debug( "Request " + r.toString() + " finished processing at " + timeOut );
}
long delta = timeOut.getTime() - timeIn.getTime();
if( delta > 300 ) { // todo: parameterize the delta threshold
logger.error( "Request " + r.toString() + " took " + delta + "ms to process." );
}
}
return InvocationResponse.CONTINUE;
}
}
After that, I edited the module.xml, axis2.xml appropriately, created the *.mar file and ran the app.
However, it seems that
HttpServletRequest r = ( HttpServletRequest )msgContext.getProperty( HTTPConstants.MC_HTTP_SERVLETREQUEST )
is null. That was unexpected.
So my questions are:
How can I access the servlet request in an AXIS2 module?
If this is not allowed, what's the alternative for me to track the time between request starting processing and ending processing?
I should be using some other existing AXIS2 functionality that can give me the same kind of result?
Many thanks in advance,
Dave C.

Instead of using HttpServletRequest, you should use the OperationContext (which you can get from the MessageContext using the getOperationContext method) to store the timestamp of the request. The operation context is the same for an incoming request and the corresponding response.

Related

How to return a Json object error on ASP.Net Core Restful Cotroller?

I have a ASP.NET controller that controls a schedule (as I'm Brazilian, schedule in Portuguese means Agendamento).
The thing is, I can't allow scheduling the same room (in Portuguese Sala) being taken twice at the same time.
So in the POST request I check the DB to see if that room has already being taken and if it has I want to return only a Json object { "error": "You can't do that." }.
If the request does not have any problem then the insert should be done and the inserted object has to be returned.
[HttpPost]
public async Task<ActionResult<Agendamento>> PostAgendamento(Agendamento agendamento)
{
var agendamentosJaExistentes = await _context.Agendamentos.Include(ag => ag.Sala)
.Where(ag =>
ag.SalaId == agendamento.SalaId &&
(
(agendamento.PeriodoInicial >= ag.PeriodoInicial && agendamento.PeriodoInicial <= ag.PeriodoFinal)
||
(agendamento.PeriodoFinal >= ag.PeriodoInicial && agendamento.PeriodoFinal <= ag.PeriodoFinal)
))
.ToListAsync();
if (agendamentosJaExistentes != null)
{
return ??? JSON OBJECT ???
}
_context.Agendamentos.Add(agendamento);
await _context.SaveChangesAsync();
return CreatedAtAction("GetAgendamento", new { id = agendamento.Id }, agendamento);
}
Can you guys help me?
Add NewtonsoftJson support
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers()
.AddNewtonsoftJson();
}
Return JsonObject
if (agendamentosJaExistentes != null)
{
return new ObjectResult(Error("You can't do that.")); //???JSON OBJECT???
}
400 Bad Request response status code indicates that the server cannot or will not process the request due to something that is perceived to be a client error.
public class ReturnJson
{
public string Status { get; set; }
public string Message { get; set; }
}
public static ReturnJson Error(string responseMessage, string responseCode = "400")
{
ReturnJson returnJson = new ReturnJson()
{
Status = responseCode,
Message = responseMessage ?? string.Empty
};
return returnJson;
}
Test Result:
For RESTful api one of the best practice is to return errors aligning with HTTP status code. For this specific case probably HTTP 500 (instead of 200 success with an error body) makes more sense.
You can do so by this:
var result = new
{
Error = "Room already booked",
};
return this.StatusCode(StatusCodes.Status500InternalServerError, result);
This is a simple way that am using (DoteNet Core 3.x)
return Json(new { error = "Your error message " , status = 405 });

Can I perform an atomic try-get-or-add operation with a ConcurrentDictionary?

In my ASP.NET Core MVC web-application (that uses OIDC) I have a class that automatically refreshes the access_token stored in the visitor's authentication cookie before it expires.
It is based on AutomaticTokenManagementCookieEvents from the IdentityServer4 samples. Available here: https://github.com/IdentityServer/IdentityServer4/blob/0155beb2cea850144b6407684a2eda22e4eea3db/samples/Clients/src/MvcHybridAutomaticRefresh/AutomaticTokenManagement/AutomaticTokenManagementCookieEvents.cs
static readonly ConcurrentDictionary<String,Object> _pendingRefreshes = new ConcurrentDictionary<String,Object>();
public override async Task ValidatePrincipal( CookieValidatePrincipalContext context )
{
DateTime accessTokenExpiresAt = GetAccessTokenExpiry( context ); // gets the 'expires_at' value from `context.Properties.GetTokens();`
String refreshToken = GetRefreshToken( context ); // Gets the 'refresh_token' value from `context.Properties.GetTokens();`
Boolean isExpired = DateTime.UtcNow > accessTokenExpiresAt;
Boolean willExpireSoon = DateTime.UtcNow > accessTokenExpiresAt.Subtract( TimeSpan.FromSeconds( 60 ) );
if( isExpired || willExpireSoon )
{
Boolean canRefresh = _pendingRefreshes.TryAdd( refreshToken, null );
if( canRefresh )
{
try
{
await RefreshAccessTokenAsync( context, refreshToken );
}
finally
{
_pendingRefreshes.TryRemove( refreshToken );
}
}
else
{
// TODO: What should happen here?
}
}
}
private async Task RefreshAccessTokenAsync( CookieValidatePrincipalContext context, String refreshToken )
{
// using IdentityModel.Client.HttpClientTokenRequestExtensions.RequestRefreshTokenAsync
TokenResponse response = await this.httpClient.RefreshTokenAsync( refreshToken );
if( response.IsError )
{
// (Error logging code here)
if( response.Error == "invalid_grant" )
{
// Usually invalid_grant errors happen if the user's refresh_token has been revoked or expired
// refresh_token expiry is separate from access_token expiry.
// If a refresh_token has expired or been revoked the only thing to do is force the user to login again. `RejectPrincipal()` will send the user to the OIDC OP login page - though this will cause the user to lose their data if this is a POST request.
context.RejectPrincipal();
}
else
{
// Something else bad happened. Don't invalidate the user's credentials unless they're actually expired, though.
throw new Exception( "Unexpected error." );
}
}
else
{
context.Properties.UpdateTokenValue( "access_token" , response.AccessToken );
context.Properties.UpdateTokenValue( "refresh_token", response.RefreshToken );
DateTime newExpiresAt = DateTime.UtcNow + TimeSpan.FromSeconds( response.ExpiresIn );
context.Properties.UpdateTokenValue( "expires_at", newExpiresAt.ToString( "o", CultureInfo.InvariantCulture ) );
await context.HttpContext.SignInAsync( context.Principal, context.Properties );
}
}
The problem with this code is that if the user's browser makes two simultaneous requests after their access_token has already expired then the user will get an error message if code later-on in the ASP.NET Core pipeline for the second simultaneous request uses the now-expired access_token.
...how can I get it so that the second concurrent request using an expired access_token will await the same Task (from RefreshAccessTokenAsync)?
My thought is something like this:
Change _pendingRefreshes to ConcurrentDictionary<String,Task<String>>.
Change Boolean canRefresh = _pendingRefreshes.TryAdd( refreshToken, null ); to something like this (using a hypothetical TryGetOrAdd method):
Boolean addedNewTask = _pendingRefreshes
.TryGetOrAdd(
key: refreshToken,
valueFactory: rt => this.RefreshTokenAsync( context, rt ),
value: out Task task
);
if( addedNewTask )
{
// wait for the new access_token to be saved before continuing.
await task;
}
else
{
if( isExpired )
{
// If the current request's access_token is already expired and its refresh_token is currently being refrehsed, then wait for it to finish as well, then update the access_token but only for this request's lifetime (i.e. don't call `ReplacePrincipal` or `SignInAsync`.
await task;
}
}
The problem is ConcurrentDictionary<TKey,TValue> does not have a TryGetOrAdd method I can use to atomically get-existing-or-add-new items.
AddOrUpdate - Doesn't return any existing items. Doesn't indicate if the value returned was an existing item or not.
GetOrAdd - Doesn't indicate if the value returned was an existing item or not.
TryAdd - Doesn't let you atomically get any existing value with the same key.
TryGetValue - Doesn't let you atomically add a new item if there isn't a value for the given key.
TryRemove - Doesn't let you atomically add a new item.
TryUpdate - Doesn't let you add new items.
This is fixable using a lock but that negates the advantages of using ConcurrentDictionary. Something like this:
Task<String> task;
Boolean addedNewTask;
lock( _pendingRefreshes )
{
Boolean taskExists = _pendingRefreshes.TryGetValue( refreshToken, out task );
if( taskExists )
{
addedNewTask = false;
}
else
{
task = RefreshAccessTokenAsync( context, refreshToken );
if( !_pendingRefreshes.TryAdd( refreshToken, task ) )
{
throw new InvalidOperationException( "Could not add the Task." ); // This should never happen.
}
addedNewTask = true;
}
}
if( addedNewTask || isExpired )
{
String newAccessToken = await task;
if( isExpired )
{
context.Properties.UpdateTokenValue( "access_token", newAccessToken );
}
}
...or is this the correct use of ConcurrentDictionary for this scenario?
I learned that ConcurrentDictionary does not guarantee that valueFactory won't be invoked exactly once per key, but may be invoked multiple times - which I can't live with because my valueFactory is an expensive operation with side-effects that may adversely negatively affect the user-experience (e.g. invalidating a token stored inside the user's cookies unnecessarily).
I settled on an approach using lock and a Dictionary<String,Task<TokenResponse>> instead. I do wonder how it could be improved and I'd really appreciate any feedback:
private static readonly Dictionary<String,Task<TokenResponse>> _currentlyRunningRefreshOperations = new Dictionary<String,Task<TokenResponse>>();
/// <summary>Returns <c>true</c> if a new Task was returned. Returns <c>false</c> if an existing Task was returned.</summary>
private Boolean GetOrCreateRefreshTokenTaskAsync( CookieValidatePrincipalContext context, String refreshToken, out Task<TokenResponse> task )
{
lock( _currentlyRunningRefreshOperations )
{
if( _currentlyRunningRefreshOperations.TryGetValue( refreshToken, out task ) )
{
return false;
}
else
{
task = this.AttemptRefreshTokensAsync( context, refreshToken );
_currentlyRunningRefreshOperations.Add( refreshToken, task );
return true;
}
}
}
private async Task<TokenResponse> AttemptRefreshTokensAsync( CookieValidatePrincipalContext context, String refreshToken )
{
try
{
TokenResponse response = await this.service.RefreshTokenAsync( refreshToken );
if( response.IsError )
{
this.logger.LogWarning( "Encountered " + nameof(this.service.RefreshTokenAsync) + " error: {error}. Type: {errorType}. Description: {errorDesc}. refresh_token: {refreshToken}.", response.Error, response.ErrorType, response.ErrorDescription, refreshToken );
return response;
}
}
finally
{
lock( _currentlyRunningRefreshOperations )
{
_currentlyRunningRefreshOperations.Remove( refreshToken );
}
}
}

webflux Mono<T> onErrorReturn not called

this is my HandlerFunction
public Mono<ServerResponse> getTime(ServerRequest serverRequest) {
return time(serverRequest).onErrorReturn("some errors has happened !").flatMap(s -> {
// this didn't called
return ServerResponse.ok().contentType(MediaType.TEXT_PLAIN).syncBody(s);
});
}
time(ServerRequest serverRequest) method is
private Mono<String> time(ServerRequest request) {
String format = DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now());
return Mono.just("time is:" + format + "," + request.queryParam("name").get());
}
when i don't using param "name",it will throw one NoSuchElementException;
But, the Mono onErrorReturn not working!
why or what do i wrong?
The onError... operators are meant to deal with error signals happening in the pipeline.
In your case, the NoSuchElementException is thrown outside of the reactive pipeline, before anything can subscribe to the returned Mono.
I think you might get the behavior you're looking for by deferring the execution like this:
private Mono<String> time(ServerRequest request) {
return Mono.defer(() -> {
String format = DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now());
Mono.just("time is:" + format + "," + request.queryParam("name").get());
});
}

getting apache ignite continuous query to work without enabling p2p class loading

I have been trying to get my ignite continuous query code to work without setting the peer class loading to enabled. However I find that the code does not work.I tried debugging and realised that the call to cache.query(qry) errors out with the message "Failed to marshal custom event" error. When I enable the peer class loading , the code works as expected. Could someone provide guidance on how I can make this work without peer class loading?
Following is the code snippet that calls the continuous query.
public void subscribeEvent(IgniteCache<String,String> cache,String inKeyStr,ServerWebSocket websocket ){
System.out.println("in thread "+Thread.currentThread().getId()+"-->"+"subscribe event");
//ArrayList<String> inKeys = new ArrayList<String>(Arrays.asList(inKeyStr.split(",")));
ContinuousQuery<String, String> qry = new ContinuousQuery<>();
/****
* Continuous Query Impl
*/
inKeys = ","+inKeyStr+",";
qry.setInitialQuery(new ScanQuery<String, String>((k, v) -> inKeys.contains(","+k+",")));
qry.setTimeInterval(1000);
qry.setPageSize(1);
// Callback that is called locally when update notifications are received.
// Factory<CacheEntryEventFilter<String, String>> rmtFilterFactory = new com.ccx.ignite.cqfilter.FilterFactory().init(inKeyStr);
qry.setLocalListener(new CacheEntryUpdatedListener<String, String>() {
#Override public void onUpdated(Iterable<CacheEntryEvent<? extends String, ? extends String>> evts) {
for (CacheEntryEvent<? extends String, ? extends String> e : evts)
{
System.out.println("websocket locallsnr data in thread "+Thread.currentThread().getId()+"-->"+"key=" + e.getKey() + ", val=" + e.getValue());
try{
websocket.writeTextMessage("key=" + e.getKey() + ", val=" + e.getValue());
}
catch (Exception e1){
System.out.println("exception local listener "+e1.getMessage());
qry.setLocalListener(null) ; }
}
}
} );
qry.setRemoteFilterFactory( new com.ccx.ignite.cqfilter.FilterFactory().init(inKeys));
try{
cur = cache.query(qry);
for (Cache.Entry<String, String> e : cur)
{
System.out.println("websocket initialqry data in thread "+Thread.currentThread().getId()+"-->"+"key=" + e.getKey() + ", val=" + e.getValue());
websocket.writeTextMessage("key=" + e.getKey() + ", val=" + e.getValue());
}
}
catch (Exception e){
System.out.println("exception cache.query "+e.getMessage());
}
}
Following is the remote filter class that I have made into a self contained jar and pushed into the libs folder of ignite, so that this can be picked up by the server nodes
public class FilterFactory
{
public Factory<CacheEntryEventFilter<String, String>> init(String inKeyStr ){
System.out.println("factory init called jun22 ");
return new Factory <CacheEntryEventFilter<String, String>>() {
private static final long serialVersionUID = 5906783589263492617L;
#Override public CacheEntryEventFilter<String, String> create() {
return new CacheEntryEventFilter<String, String>() {
#Override public boolean evaluate(CacheEntryEvent<? extends String, ? extends String> e) {
//List inKeys = new ArrayList<String>(Arrays.asList(inKeyStr.split(",")));
System.out.println("inside remote filter factory ");
String inKeys = ","+inKeyStr+",";
return inKeys.contains(","+e.getKey()+",");
}
};
}
};
}
}
Overall logic that I'm trying to implement is to have a websocket client subscribe to an event by specifying a cache name and key(s) of interest.
The subscribe event code is called which creates a continuous query and registers a local listener callback for any update event on the key(s) of interest.
The remote filter is expected to filter the update event based on the key(s) passed to it as a string and the local listener is invoked if the filter event succeeds. The local listener writes the updated key value to the web socket reference passed to the subscribe event code.
The version of ignite Im using is 1.8.0. However the behaviour is the same in 2.0 as well.
Any help is greatly appreciated!
Here is the log snippet containing the relevant error
factory init called jun22
exception cache.query class org.apache.ignite.spi.IgniteSpiException: Failed to marshal custom event: StartRoutineDiscoveryMessage [startReqData=StartRequestData [prjPred=org.apache.ignite.configuration.CacheConfiguration$IgniteAllNodesPredicate#269707de, clsName=null, depInfo=null, hnd=CacheContinuousQueryHandlerV2 [rmtFilterFactory=com.ccx.ignite.cqfilter.FilterFactory$1#5dc301ed, rmtFilterFactoryDep=null, types=0], bufSize=1, interval=1000, autoUnsubscribe=true], keepBinary=false, routineId=b40ada9f-552d-41eb-90b5-3384526eb7b9]
From FilterFactory you are returning an instance of an anonymous class which in turn refers to the enclosing FilterFactory which is not serializable.
Just replace the returned anonymous CacheEntryEventFilter based class with a corresponding nested static class.
You need to explicitly deploy you CQ classes (remote filters specifically) on all nodes in topology. Just create a JAR file with them and put into libs folder prior to starting nodes.

Creating an nhibernate session per web request with Castle.Facility.AutoTx and Castle.Facility.NHibernate

I am using Castle Windors and it's AutoTx and the NHibernate Facility by haf. Ultimately I want the benefits of ease of use of the Transaction attribute provided by AutoTx. (ASP.NET MVC 4 project).
I am using Castle.Facilities.NHibernate.ISessionManager to manage my PerWebRequest sessions. I have setup the Windsor Installer as such:
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<AutoTxFacility>();
container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>().LifeStyle.Singleton);
container.AddFacility<NHibernateFacility>(f => f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);
container.Install(FromAssembly.Containing<PersonRepository>());
}
I'm using the DefaultLifeStyle of SessionPerWebRequest, which I expect would do exactly that, provide me with a session that lasts the entire web request, such that all calls to OpenSession on SessionManager within same request use the same session. I'm testing that with the following code:
public class HomeController : Controller
{
private readonly ISessionManager _sessionManager;
public HomeController(ISessionManager sessionManager)
{
_sessionManager = sessionManager;
}
public ActionResult Index()
{
using (var session1 = _sessionManager.OpenSession())
{
var person = session1.Get<Person>(1);
using (var session2 = _sessionManager.OpenSession())
{
var person2 = session2.Get<Person>(1);
}
}
return View();
}
}
and checking the log to see the id of each created session. The id is always different. eg
05/01/2013 11:27:39.109 DEBUG 9 NHibernate.Impl.SessionImpl - [session-id=c1ba248a-14ba-4468-a20c-d6114b7dac61] opened session at timestamp: 634929820591, for session factory: [/ea869bb12b4d4e51b9f431a4f9c9d9fa]
05/01/2013 11:30:36.383 DEBUG 9 NHibernate.Impl.SessionImpl - [session-id=72481180-625d-4085-98e9-929e3fd93e8a] opened session at timestamp: 634929822363, for session factory: [/ea869bb12b4d4e51b9f431a4f9c9d9fa]
It's worth noting that I haven't added anything to the web.config in the way of Handlers. Do I need to? ( I didn't see any documentation suggesting this in the NHib Facility Wiki) Are my expectations that the same Session will always be returned incorrect.
I've had a look through the source code for the facility and do not understand how a session per web request is being instantiated and how multiple calls to OpenSession would result in the same session in the same web request.
The following is how SessionManager is registered with Windsor:
Component.For<ISessionManager>().Instance(new SessionManager(() =>
{
var factory = Kernel.Resolve<ISessionFactory>(x.Instance.SessionFactoryKey);
var s = x.Instance.Interceptor.Do(y => factory.OpenSession(y)).OrDefault(factory.OpenSession());
s.FlushMode = flushMode;
return s;
}))
.Named(x.Instance.SessionFactoryKey + SessionManagerSuffix)
.LifeStyle.Singleton
ISession is registered with Windsor using the following
private IRegistration RegisterSession(Data x, uint index)
{
Contract.Requires(index < 3,
"there are only three supported lifestyles; per transaction, per web request and transient");
Contract.Requires(x != null);
Contract.Ensures(Contract.Result<IRegistration>() != null);
return GetLifeStyle(
Component.For<ISession>()
.UsingFactoryMethod((k, c) =>
{
var factory = k.Resolve<ISessionFactory>(x.Instance.SessionFactoryKey);
var s = x.Instance.Interceptor.Do(y => factory.OpenSession(y)).OrDefault(factory.OpenSession());
s.FlushMode = flushMode;
logger.DebugFormat("resolved session component named '{0}'", c.Handler.ComponentModel.Name);
return s;
}), index, x.Instance.SessionFactoryKey);
}
private ComponentRegistration<T> GetLifeStyle<T>(ComponentRegistration<T> registration, uint index, string baseName)
where T : class
{
Contract.Requires(index < 3,
"there are only three supported lifestyles; per transaction, per web request and transient");
Contract.Ensures(Contract.Result<ComponentRegistration<T>>() != null);
switch (defaultLifeStyle)
{
case DefaultSessionLifeStyleOption.SessionPerTransaction:
if (index == 0)
return registration.Named(baseName + SessionPerTxSuffix).LifeStyle.PerTopTransaction();
if (index == 1)
return registration.Named(baseName + SessionPWRSuffix).LifeStyle.PerWebRequest;
if (index == 2)
return registration.Named(baseName + SessionTransientSuffix).LifeStyle.Transient;
goto default;
case DefaultSessionLifeStyleOption.SessionPerWebRequest:
if (index == 0)
return registration.Named(baseName + SessionPWRSuffix).LifeStyle.PerWebRequest;
if (index == 1)
return registration.Named(baseName + SessionPerTxSuffix).LifeStyle.PerTopTransaction();
if (index == 2)
return registration.Named(baseName + SessionTransientSuffix).LifeStyle.Transient;
goto default;
case DefaultSessionLifeStyleOption.SessionTransient:
if (index == 0)
return registration.Named(baseName + SessionTransientSuffix).LifeStyle.Transient;
if (index == 1)
return registration.Named(baseName + SessionPerTxSuffix).LifeStyle.PerTopTransaction();
if (index == 2)
return registration.Named(baseName + SessionPWRSuffix).LifeStyle.PerWebRequest;
goto default;
default:
throw new FacilityException("invalid index passed to GetLifeStyle<T> - please file a bug report");
}
}
which does register an ISession as PerWebRequest, but I can't see anywhere in the code where that named registration is extracted when a session is required?
Any help on what I need to do get Session per web request working is appreciated.
UPDATE I decided to just replace the code function being passed into SessionManager constructor with code that grabs the ISession from the container, rather than uses the factory. Works perfectly for what I want it to do, including being wrapped in transactions and only opening one session per web request, or transient etc.
Component.For<ISessionManager>().Instance(new SessionManager(() =>
{
var s = Kernel.Resolve<ISession>();
s.FlushMode = flushMode;
return s;
}))
//Component.For<ISessionManager>().Instance(new SessionManager(() =>
//{
// var factory = Kernel.Resolve<ISessionFactory>(x.Instance.SessionFactoryKey);
// var s = x.Instance.Interceptor.Do(y => factory.OpenSession(y)).OrDefault(factory.OpenSession());
// s.FlushMode = flushMode;
// return s;
//}))
.Named(x.Instance.SessionFactoryKey + SessionManagerSuffix)
.LifeStyle.Singleton
Kernel.Resolve() I expect will grab the first registered service in the container. This will be whatever I set the Lifestyle to.