I am trying to have a baseclass and register default interception using unity. I am also registering each derived type before resolving, but its not working. I would expect the BaseMethod to be intercepted here but it is not.
public class AbstractResponse
{
private string name;
public virtual void BaseMethod()
{
Console.WriteLine("Base");
}
}
public class DocumentResponse:AbstractResponse
{
public virtual void Test()
{
Console.WriteLine("In Test Method");
}
}
var container = new UnityContainer(); container.AddNewExtension<Interception>();
container.RegisterType<AbstractResponse>(
new DefaultInterceptor<VirtualMethodInterceptor>(),
new DefaultInterceptionBehavior<TraceBehavior>()).
RegisterType<AbstractResponse,DocumentResponse>();
container.Resolve<DocumentResponse>().BaseMethod();
You've just gone a little wrong on your registration code - you are actually calling RegisterType twice in your code sample, and the second registration is overwriting the first one. Switch it to something like this and it will work fine: -
container.RegisterType<AbstractResponse, DocumentResponse>(
new DefaultInterceptor<VirtualMethodInterceptor>(),
new DefaultInterceptionBehavior<TraceBehaviour>());
So this says "Register AbstractResponse and map it to DocumentResponse. Then, using the VirtualMethodInterceptor, apply the TraceBehaviour."
You can always see if the interception is active by seeing the type that is returned on Resolve - if it's the (in this case) AbstractResponse then it hasn't worked; if you get back some funky Unity-generated type name then it's working.
Related
I have followed this steps to setup JSB. In my bounded-class, I need to return the source of an API request (I cannot, therefore, use GetPageSourceAsync because no JS context is ever created). So, I use the trick of copying and immediately pasting the page content to a string variable (see result). This code is not working, I get the following exception:
The ChromiumWebBrowser instance creates the underlying Chromium Embedded Framework (CEF) browser instance in an async fashion. The undelying CefBrowser instance is not yet initialized. Use the IsBrowserInitializedChanged event and check the IsBrowserInitialized property to determine when the browser has been initialized.
which is happening on bro.SelectAll();:
public class boundClass
{
ChromiumWebBrowser bro;
public boundClass()
{
bro = new ChromiumWebBrowser("https://google.com");
}
public string getAuthSource(string url)
{
string source = String.Empty;
bro.Load(url);
while (bro.IsLoading)
{
}
bro.SelectAll();
bro.Copy();
string result = Clipboard.GetText();
Clipboard.Clear();
return result;
}
}
What's the problem? The ChromiumWebBrowser seems well-initialized to me...
This question already has answers here:
How to make a Java class that implements one interface with two generic types?
(9 answers)
Closed 8 years ago.
I have the following interface, which I want to implement multiple times in my classes:
public interface EventListener<T extends Event>
{
public void onEvent(T event);
}
Now, I want to be able to implement this interface in the following way:
class Foo implements EventListener<LoginEvent>, EventListener<LogoutEvent>
{
#Override
public void onEvent(LoginEvent event)
{
}
#Override
public void onEvent(LogoutEvent event)
{
}
}
However, this gives me the error: Duplicate class com.foo.EventListener on the line:
class Foo implements EventListener<LoginEvent>, EventListener<LogoutEvent>
Is it possible to implement the interface twice with different generics? If not, what's the next closest thing I can do to achieve what I'm trying to do here?
Is it possible to implement the interface twice with different generics
Unfortunately no. The reason you can't implement the same interface twice is because of type erasure. The compiler will handle type parameters, and a runtime EventListener<X> is just a EventListener
If not, what's the next closest thing I can do to achieve what I'm trying to do here?
Type erasure can work in our favor. Once you know that EventListener<X> and EventListener<Y> are just raw EventListener at run-time, it is easier than you think to write an EventListener that can deal with different kinds of Events. Bellow is a solution that passes the IS-A test for EventListener and correctly handles both Login and Logout events by means of simple delegation:
#SuppressWarnings("rawtypes")
public class Foo implements EventListener {
// Map delegation, but could be anything really
private final Map<Class<? extends Event>, EventListener> listeners;
// Concrete Listener for Login - could be anonymous
private class LoginListener implements EventListener<LoginEvent> {
public void onEvent(LoginEvent event) {
System.out.println("Login");
}
}
// Concrete Listener for Logout - could be anonymous
private class LogoutListener implements EventListener<LogoutEvent> {
public void onEvent(LogoutEvent event) {
System.out.println("Logout");
}
}
public Foo() {
#SuppressWarnings("rawtypes")
Map<Class<? extends Event>, EventListener> temp = new HashMap<>();
// LoginEvents will be routed to LoginListener
temp.put(LoginEvent.class, new LoginListener());
// LogoutEvents will be routed to LoginListener
temp.put(LogoutEvent.class, new LogoutListener());
listeners = Collections.unmodifiableMap(temp);
}
#SuppressWarnings("unchecked")
#Override
public void onEvent(Event event) {
// Maps make it easy to delegate, but again, this could be anything
if (listeners.containsKey(event.getClass())) {
listeners.get(event.getClass()).onEvent(event);
} else {
/* Screams if a unsupported event gets passed
* Comment this line if you want to ignore
* unsupported events
*/
throw new IllegalArgumentException("Event not supported");
}
}
public static void main(String[] args) {
Foo foo = new Foo();
System.out.println(foo instanceof EventListener); // true
foo.onEvent(new LoginEvent()); // Login
foo.onEvent(new LogoutEvent()); // Logout
}
}
The suppress warnings are there because we are "abusing" type erasure and delegating to two different event listeners based on the event concrete type. I have chosen to do it using a HashMap and the run-time Event class, but there are a lot of other possible implementations. You could use anonymous inner classes like #user949300 suggested, you could include a getEventType discriminator on the Event class to know what do to with each event and so on.
By using this code for all effects you are creating a single EventListener able to handle two kinds of events. The workaround is 100% self-contained (no need to expose the internal EventListeners).
Finally, there is one last issue that may bother you. At compile time Foo type is actually EventListener. Now, API methods out of your control may be expecting parametrized EventListeners:
public void addLoginListener(EventListener<LoginEvent> event) { // ...
// OR
public void addLogoutListener(EventListener<LogoutEvent> event) { // ...
Again, at run-time both of those methods deal with raw EventListeners. So by having Foo implement a raw interface the compiler will be happy to let you get away with just a type safety warning (which you can disregard with #SuppressWarnings("unchecked")):
eventSource.addLoginListener(foo); // works
While all of this may seem daunting, just repeat to yourself "The compiler is trying to trick me (or save me); there is no spoon <T>. Once you scratch your head for a couple of months trying to make legacy code written before Java 1.5 work with modern code full of type parameters, type erasure becomes second nature to you.
You need to use inner or anonymous classes. For instance:
class Foo {
public EventListener<X> asXListener() {
return new EventListener<X>() {
// code here can refer to Foo
};
}
public EventListener<Y> asYListener() {
return new EventListener<Y>() {
// code here can refer to Foo
};
}
}
This is not possible.
But for that you could create two different classes that implement EventListener interface with two different arguments.
public class Login implements EventListener<LoginEvent> {
public void onEvent(LoginEvent event) {
// TODO Auto-generated method stub
}
}
public class Logout implements EventListener<LogoutEvent> {
public void onEvent(LogoutEvent event) {
// TODO Auto-generated method stub
}
}
I'm trying to implement a web application using ASP.NET MVC and the Microsoft Unity DI framework. The application needs to support multiple user sessions at the same time, each of them with their own connection to a separate database (but all users using the same DbContext; the database schemas are identical, it's just the data that is different).
Upon a user's log-in, I register the necessary type mappings to the application's Unity container, using a session-based lifetime manager that I found in another question here.
My container is initialized like this:
// Global.asax.cs
public static UnityContainer CurrentUnityContainer { get; set; }
protected void Application_Start()
{
// ...other code...
CurrentUnityContainer = UnityConfig.Initialize();
// misc services - nothing data access related, apart from the fact that they all depend on IRepository<ClientContext>
UnityConfig.RegisterComponents(CurrentUnityContainer);
}
// UnityConfig.cs
public static UnityContainer Initialize()
{
UnityContainer container = new UnityContainer();
DependencyResolver.SetResolver(new UnityDependencyResolver(container));
GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);
return container;
}
This is the code that's called upon logging in:
// UserController.cs
UnityConfig.RegisterUserDataAccess(MvcApplication.CurrentUnityContainer, UserData.Get(model.AzureUID).CurrentDatabase);
// UnityConfig.cs
public static void RegisterUserDataAccess(IUnityContainer container, string databaseName)
{
container.AddExtension(new DataAccessDependencies(databaseName));
}
// DataAccessDependencies.cs
public class DataAccessDependencies : UnityContainerExtension
{
private readonly string _databaseName;
public DataAccessDependencies(string databaseName)
{
_databaseName = databaseName;
}
protected override void Initialize()
{
IConfigurationBuilder configurationBuilder = Container.Resolve<IConfigurationBuilder>();
Container.RegisterType<ClientContext>(new SessionLifetimeManager(), new InjectionConstructor(configurationBuilder.GetConnectionString(_databaseName)));
Container.RegisterType<IRepository<ClientContext>, RepositoryService<ClientContext>>(new SessionLifetimeManager());
}
}
// SessionLifetimeManager.cs
public class SessionLifetimeManager : LifetimeManager
{
private readonly string _key = Guid.NewGuid().ToString();
public override void RemoveValue(ILifetimeContainer container = null)
{
HttpContext.Current.Session.Remove(_key);
}
public override void SetValue(object newValue, ILifetimeContainer container = null)
{
HttpContext.Current.Session[_key] = newValue;
}
public override object GetValue(ILifetimeContainer container = null)
{
return HttpContext.Current.Session[_key];
}
protected override LifetimeManager OnCreateLifetimeManager()
{
return new SessionLifetimeManager();
}
}
This works fine as long as only one user is logged in at a time. The data is fetched properly, the dashboards work as expected, and everything's just peachy keen.
Then, as soon as a second user logs in, disaster strikes.
The last user to have prompted a call to RegisterUserDataAccess seems to always have "priority"; their data is displayed on the dashboard, and nothing else. Whether this is initiated by a log-in, or through a database access selection in my web application that calls the same method to re-route the user's connection to another database they have permission to access, the last one to draw always imposes their data on all other users of the web application. If I understand correctly, this is a problem the SessionLifetimeManager was supposed to solve - unfortunately, I really can't seem to get it to work.
I sincerely doubt that a simple and common use-case like this - multiple users logged into an MVC application who each are supposed to access their own, separate data - is beyond the abilities of Unity, so obviously, I must be doing something very wrong here. Having spent most of my day searching through depths of the internet I wasn't even sure truly existed, I must, unfortunately, now realize that I am at a total and utter loss here.
Has anyone dealt with this issue before? Has anyone dealt with this use-case before, and if yes, can anyone tell me how to change my approach to make this a little less headache-inducing? I am utterly desperate at this point and am considering rewriting my entire data access methodology just to make it work - not the healthiest mindset for clean and maintainable code.
Many thanks.
the issue seems to originate from your registration call, when registering the same type multiple times with unity, the last registration call wins, in this case, that will be data access object for whoever user logs-in last. Unity will take that as the default registration, and will create instances that have the connection to that user's database.
The SessionLifetimeManager is there to make sure you get only one instance of the objects you resolve under one session.
One option to solve this is to use named registration syntax to register the data-access types under a key that maps to the logged-in user (could be the database name), and on the resolve side, retrieve this user key, and use it resolve the corresponding data access implementation for the user
Thank you, Mohammed. Your answer has put me on the right track - I ended up finally solving this using a RepositoryFactory which is instantiated in an InjectionFactory during registration and returns a repository that always wraps around a ClientContext pointing to the currently logged on user's currently selected database.
// DataAccessDependencies.cs
protected override void Initialize()
{
IConfigurationBuilder configurationBuilder = Container.Resolve<IConfigurationBuilder>();
Container.RegisterType<IRepository<ClientContext>>(new InjectionFactory(c => {
ClientRepositoryFactory repositoryFactory = new ClientRepositoryFactory(configurationBuilder);
return repositoryFactory.GetRepository();
}));
}
// ClientRepositoryFactory.cs
public class ClientRepositoryFactory : IRepositoryFactory<RepositoryService<ClientContext>>
{
private readonly IConfigurationBuilder _configurationBuilder;
public ClientRepositoryFactory(IConfigurationBuilder configurationBuilder)
{
_configurationBuilder = configurationBuilder;
}
public RepositoryService<ClientContext> GetRepository()
{
var connectionString = _configurationBuilder.GetConnectionString(UserData.Current.CurrentPermission);
ClientContext ctx = new ClientContext(connectionString);
RepositoryService<ClientContext> repository = new RepositoryService<ClientContext>(ctx);
return repository;
}
}
// UserData.cs (multiton-singleton-hybrid)
public static UserData Current
{
get
{
var currentAADUID = (string)(HttpContext.Current.Session["currentAADUID"]);
return Get(currentAADUID);
}
}
public static UserData Get(string AADUID)
{
UserData instance;
lock(_instances)
{
if(!_instances.TryGetValue(AADUID, out instance))
{
throw new UserDataNotInitializedException();
}
}
return instance;
}
public static UserData Current
{
get
{
var currentAADUID = (string)(HttpContext.Current.Session["currentAADUID"]);
return Get(currentAADUID);
}
}
public static UserData Get(string AADUID)
{
UserData instance;
lock(_instances)
{
if(!_instances.TryGetValue(AADUID, out instance))
{
throw new UserDataNotInitializedException();
}
}
return instance;
}
When using spring-data-rest there is a post processing of Resource classes returned from Controllers (e.g. RepositoryRestControllers). The proper ResourceProcessor is called in the post processing.
The class responsible for this is ResourceProcessorHandlerMethodReturnValueHandler which is part of spring-hateoas.
I now have a project that only uses spring-hateoas and I wonder how to configure ResourceProcessorHandlerMethodReturnValueHandler in such a scenario. It looks like the auto configuration part of it still resides in spring-data-rest.
Any hints on how to enable ResourceProcessorHandlerMethodReturnValueHandler in a spring-hateoas context?
I've been looking at this recently too, and documentation on how to achieve this is non-existent. If you create a bean of type ResourceProcessorInvokingHandlerAdapter, you seem to lose the the auto-configured RequestMappingHandlerAdapter and all its features. As such, I wanted to avoid using this bean or losing the WebMvcAutoConfiguration, since all I really wanted was the ResourceProcessorHandlerMethodReturnValueHandler.
You can't just add a ResourceProcessorHandlerMethodReturnValueHandler via WebMvcConfigurer.addReturnValueHandlers, because what we need to do is actually override the entire list, as is what happens in ResourceProcessorInvokingHandlerAdapter.afterPropertiesSet:
#Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
// Retrieve actual handlers to use as delegate
HandlerMethodReturnValueHandlerComposite oldHandlers = getReturnValueHandlersComposite();
// Set up ResourceProcessingHandlerMethodResolver to delegate to originally configured ones
List<HandlerMethodReturnValueHandler> newHandlers = new ArrayList<HandlerMethodReturnValueHandler>();
newHandlers.add(new ResourceProcessorHandlerMethodReturnValueHandler(oldHandlers, invoker));
// Configure the new handler to be used
this.setReturnValueHandlers(newHandlers);
}
So, without a better solution available, I added a BeanPostProcessor to handle setting the List of handlers on an existing RequestMappingHandlerAdapter:
#Component
#RequiredArgsConstructor
#ConditionalOnBean(ResourceProcessor.class)
public class ResourceProcessorHandlerMethodReturnValueHandlerConfigurer implements BeanPostProcessor {
private final Collection<ResourceProcessor<?>> resourceProcessors;
#Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter requestMappingHandlerAdapter = (RequestMappingHandlerAdapter) bean;
List<HandlerMethodReturnValueHandler> handlers =
requestMappingHandlerAdapter.getReturnValueHandlers();
HandlerMethodReturnValueHandlerComposite delegate =
handlers instanceof HandlerMethodReturnValueHandlerComposite ?
(HandlerMethodReturnValueHandlerComposite) handlers :
new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
requestMappingHandlerAdapter.setReturnValueHandlers(Arrays.asList(
new ResourceProcessorHandlerMethodReturnValueHandler(delegate,
new ResourceProcessorInvoker(resourceProcessors))));
return requestMappingHandlerAdapter;
}
else return bean;
}
}
This has seemed to work so far...
I'm trying to use nancy with JSON.net, follow the 2 ways that i found to register the dependencies but all way get me to an InvalidOperationException with a message "Something went wrong when trying to satisfy one of the dependencies during composition, make sure that you've registered all new dependencies in the container and inspect the innerexception for more details." with an inner exection of {"Unable to resolve type: Nancy.NancyEngine"}.
I'm using self hosting to run nancy and jeep everything really simple to been able just to test.
public static void Main(string[] args)
{
try
{
var host = new NancyHost(new Uri("http://localhost:8888/"));
host.Start(); // start hosting
Console.ReadKey();
host.Stop(); // stop hosting
}
catch
{
throw;
}
}
First I create a customSerializer
public class CustomJsonSerializer : JsonSerializer
{
public CustomJsonSerializer()
{
ContractResolver = new CamelCasePropertyNamesContractResolver();
Formatting = Formatting.Indented;
}
}
and then i tried 2 ways of registering
Using IRegistrations:
public class JsonRegistration : IRegistrations
{
public IEnumerable<TypeRegistration> TypeRegistrations
{
get
{
yield return new TypeRegistration(typeof(JsonSerializer), typeof(CustomJsonSerializer));
}
}
public IEnumerable<CollectionTypeRegistration> CollectionTypeRegistrations { get; protected set; }
public IEnumerable<InstanceRegistration> InstanceRegistrations { get; protected set; }
}
And also using Bootstrapper
public class NancyBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container);
container.Register<JsonSerializer, CustomJsonSerializer>();
}
}
Which means that when self hosting I add the custom bootstrapper
var host = new NancyHost(new Uri("http://localhost:8888/"), new NancyBootstrapper());
Both way return the same error.
Problem is actually the versions, the nancy json.net package is using Newton.Json 6.0.0.0, BUT when installing the package it will install automatically newer version that will create this problem. Not sure what has change in the Newton.JSON that will actually create this.
https://github.com/NancyFx/Nancy.Serialization.JsonNet/issues/27
Just to add my hard won knowledge in this area, after a greatly frustrating few hours using Nancy 1.4.1.
If you use a custom bootstrapper, make sure you make the call to base.ConfigureApplicationContainer(container); before you start your custom registrations.
So, not:
public class MyCustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
// MY BITS HERE...
base.ConfigureApplicationContainer(container);
}
}
but,
public class MyCustomBootstrapper : DefaultNancyBootstrapper
{
protected override void ConfigureApplicationContainer(TinyIoCContainer container)
{
base.ConfigureApplicationContainer(container); // Must go first!!
// MY BITS HERE...
}
}
If you don't do this you will get the following error:
Something went wrong when trying to satisfy one of the dependencies
during composition, make sure that you've registered all new
dependencies in the container and inspect the innerexception for more
details.
with a helpful inner exception of:
Unable to resolve type: Nancy.NancyEngine
The solution of changing the order of these C# statements was actually alluded to in #StevenRobbins' excellent answer here (which I could have saved myself several hours of pain if I'd only read properly the first time).
Says Steven:
By calling "base" after you've made a manual registration you are
effectively copying over your original registration by autoregister.
Either don't call base, or call it before you do your manual
registrations.