Windsor Ioc Auto Register Classes namespace collision for duplicate type across assemblies - inversion-of-control

I would like suggestions on if this usage is possible with Windsor and how to achieve. The details (simplified to illustrate the issue) are as follows.
AssemblyA namespace com.foo
IRepository<T>
AssemblyB namespace com.foo
Repository<Data> extends IRepository<Data>
Service -> Resolves Repository<Data> via Windsor
AssemblyC namespace com.foo
Repository<Data> extends IRepository<Data>
Service -> Resolves Repository<Data> via Windsor
AssemblyB references AssemblyA
AssemblyC references AssemblyA
Services are deployed in WCF as follows:
<add relativeAddress="v1/Service.svc" service="com.foo.Service, AssemblyB" />
<add relativeAddress="v2/Service.svc" service="com.foo.Service, AssemblyC" />
Registered via Windsor as follows:
var allTypesFromBinDir =
Classes.FromAssemblyInDirectory(
new AssemblyFilter(path));
Container.Register(allTypesFromBinDir.BasedOn(typeof(IRepository<>))
.WithService.Base()
.LifestyleTransient());
What I want is to scope registration to include the Assembly in qualifying Data for registering and resolving. What occurs is the first assembly scanned AssemblyB registers IRepository with assemblyB.Data and does not register AssemblyC IRespository with assemblyC.Data.
The following occurs or vice versa depending on order dll's scanned.
AssemblyB resolves correctly.
AssemblyC fails to resolve with "No component for supporting the service"
Container.Resolve(IRepository<Data>)
So it seems that the registration treats the two namespaces as the same from registration purpose but resolving takes assembly into account? I expect Registration to take assembly qualification into account as well.
In otherwords...
Windsor "should" I think:
Register AssemblyA.IRepository<AssemblyB.Data> with AssemblyB.Repository<AssemblyB.Data>
And
Register AssemblyA.IRepository<AssemblyC.Data> with AssemblyC.Repository<AssemblyC.Data>
Then Windsor "should" I think:
AssemblyB Service resolves AssemblyA.IRepository<AssemblyB.Data> to AssemblyB.Repository<AssemblyB.Data>
And
AssemblyC Service resolves AssemblyA.IRepository<AssemblyC.Data> to AssemblyC.Repository<AssemblyC.Data>
Instead
Windsor is:
Register AssemblyA.IRepository<AssemblyB.Data> with AssemblyB.Repository<AssemblyB.Data>
And
Does not Register AssemblyA.IRepository<AssemblyC.Data> with AssemblyC.Repository<AssemblyC.Data> I believe it matches AssemblyA.IRepository<Data> from prior registration ignoring Assembly.
Then Windsor is:
AssemblyB Service resolves AssemblyA.IRepository<AssemblyB.Data> to AssemblyB.Repository<AssemblyB.Data>
And
AssemblyC Service does not resolve AssemblyA.IRepository<AssemblyC.Data> but throws component not found. If AssemblyC is scanned first then the exception happens in AssemblyB Service.
I have looked at posts demonstrating something close to what I want by Krzysztof here using IGenericServiceStrategy
However, this strategy seems to work only with Component registration using implemented by.
Thanks in advance.

Having the same namespaces and types in different assemblies is not a good choice. It requires additional job anyway to resolve them withing your clients - extern alias <name>.
extern alias v2Alias;
extern alias v1Alias;
And it seems that when your types in the same namespace then either only types from first assembly are registered:
container.Register(Types.FromAssemblyNamed("v1.com.foo").BasedOn(typeof(IRepository<>)).WithService.Base());
container.Register(Types.FromAssemblyNamed("v2.com.foo").BasedOn(typeof(IRepository<>)).WithService.Base());
or exception 'There is already a component with that name. Did you want to modify the existing component instead? If not, make sure you specify a unique name.' is thrown:
container.Register(Component.For<IRepository<v1Alias::com.foo.Data>>().ImplementedBy<v1Alias::com.foo.Repository>());
container.Register(Component.For<IRepository<v2Alias::com.foo.Data>>().ImplementedBy<v2Alias::com.foo.Repository>());
If you put different versions of your types into different namespaces (e.g. com.foo.v1, com.foo.v2) all your types will be registered.
There'll be no difference how you register them:
container.Register(Component.For<IRepository<v1.com.foo.Data>>().ImplementedBy<v1.com.foo.Repository>());
container.Register(Component.For<IRepository<v2.com.foo.Data>>().ImplementedBy<v2.com.foo.Repository>());
or
container.Register(Types.FromAssemblyNamed("v1.com.foo").BasedOn(typeof(IRepository<>)).WithService.Base());
container.Register(Types.FromAssemblyNamed("v2.com.foo").BasedOn(typeof(IRepository<>)).WithService.Base());
PS: If this solution doesn't work for you then you can post an issue on GitHub or create a pull request with your fix.

Related

Can I call a stateless service with RPC from outside of a cluster but in the same local network?

On my local machine in Visual Studio 2017, I created solution based on the .NET Core Stateless Service template, and added Microsoft.ServiceFabric.Services.Remoting.Runtime package to accept remote calls through RPC.
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
return this.CreateServiceRemotingInstanceListeners();
}
Then I added interface ITestAccUp in a separate project:
public interface ITestAccUp : IService
{
Task NotifyAsync();
}
I added implementation of the interface to the stateless service, and created one more project, a .NET Core console client to run the service. The console is going to be run outside a cluster.
static void Main(string[] args)
{
ITestAccUp testAccUpClient = ServiceProxy.Create<ITestAccUp>(new Uri("fabric:/SFAccountUpTest/Stateless1"));
testAccUpClient.NotifyAsync().Wait();
}
However, when I run it I got the error "InvalidCastException: Unable to cast COM object of type 'System.__ComObject' to interface type 'IFabricTestManagementClient4'. This operation failed because the QueryInterface call on the COM component for the interface with IID '{B96AA7D4-ACC0-4814-89DC-561B0CBB6028}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).",
though Named Application fabric:/SFAccountUpTest/Stateless1 seems to be up and running.
I guess the problem is RPC calls are just made for calling services inside SF clusters, not outside. Is it possible to make an RPC call outside a cluster, or is it necessary to build some sort of web API to make a service call?
As long as you're on the same network, you can call Services and Actors by using SF Remoting from other applications. For example, see this demo project which does so for testing purposes.
Make sure you use the same DLL that holds the interface definition from both the client and the service project. (It works different from WCF, where a proxy could be generated independently from the service, by using wsdl.)
Maybe you're running into an issue, like this one, or this one.
I realize this question is kinda old, but the way I solved this problem was to make sure I was using the "V2" remoting stack (details here)
Basically you need to edit your ServiceManifest.xml to use this as an Endpoint:
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpointV2" />
</Endpoints>
</Resources>
And add the [assembly] attribute to your remoting interface (above namespace).
Example:
...
using Microsoft.ServiceFabric.Services.Remoting;
using Microsoft.ServiceFabric.Services.Remoting.FabricTransport;
[assembly: FabricTransportServiceRemotingProvider(RemotingListenerVersion = RemotingListenerVersion.V2, RemotingClientVersion = RemotingClientVersion.V2)]
namespace ClassLibrary1
{
public interface IMyService : IService
{
...

what is the difference between jndi binding of module and app in Java ee 6/7?

We migrated from Jboss EAP 5 to EAP 6 in our development environment.
I now see the following in my JBOSS logs. I am trying to understand how this binding happens. I have read JBOSS docs on JNDI namespace binding. Still I am not totally clear how it works. Here is my log.
java:global/customerCare/services/UserDaoImpl!com.example.services.UserDao
java:app/services/UserDaoImpl!com.example.services.UserDao
java:module/UserDaoImpl!com.services.UserDao
java:global/customerCare/services/UserDaoImpl
java:app/services/UserDaoImpl
java:module/UserDaoImpl
Here are my EJBs
#Local
public interface UserDao {
public static final String JNDI_NAME = "java:global/customCare/services/UserDaoImpl";
//interface methods here
}
#Stateless
public class UserDaoImpl implements UserDao {
// implement methods
}
My doubts are:
I explicitly had JNDI binding to be java:global/customCare/services/UserDaoImpl in my UserDao interface.
Then why do I see I binding for others such as app and module.
what is the difference between app and module? when would binding to these components be needed? some example here to illustrate will be very helpful
The last three lines of log show binding to UserDaoImpl. Is it something that JBoss does without I ask it to bind? ( I set only UserDao but not UserDaoImpl for JNDI binding).
I am a bit illiterate on JNDI Namespace binding. Reading docs helped me but not to great extent.
Thanks
I can answer doubt 2:
All the names are the same thing but with different contexts.
The global name is a full JNDI context that is used to bind globally, ie. from a client or from another EAR file
The module name can be used to bind within the same application, ie different EJBs within the same EAR
The local name is used to bind locally, ie within an jar or war.
It is slightly more efficient to use the shorter names to bind locally than specifying a full global name each time.
From what I have seen JBoss EAP 6 will always list the three / six names for every enterprise bean during deployment. It is intended to help you as a developer identify the JNDI name(s) for the bean.

ServiceStack WSDL creates empty portType element

I created a SOAP1.2 web service with ServiceStack. We have a client using the Axis2 platform to create a proxy class to our service via the WSDL; however, they are receiving an error because the portType does not contain any methods (all of our operations appear under the portType with name "ISyncReply").
<wsdl:portType name="IOneWay"></wsdl:portType>
If i manually edit the WSDL and remove the IOneWay port type and all the things that reference it, they are able to add their Axis2 classes just fine.
Is there any way to get ServiceStack to not output this PortType for Async if there are not any operations that are defined as asynchronous?
EDIT:
Also when trying to add a service reference using the wcftestclient it gives the following error; however, it appears to add the operations that exist under the
I found the answer...
No, you cannot turn off the IOneWay port binding in the WSDL - It appears that this template is used to generate the WSDL and the port binding is hard coded in the template (see line 135-137).

WCF Data Service and Castle Windsor

I am trying to use the Castle Windsor with WCF Data Service. I have created an Entity Data Model say "Person" and added a WCF Data Service called "MyService.svc". This is then exposed through OData...
public class MyService: DataService<Person>
...
Now, the question is how do you go about resolving this using the Windsor Container after registering it? (I registered it through Global.asax). So when you make a request such as "http://localhost/MyService.svc", How do I go about resolving "MyService" instance? How and where could I intercept to provide an instance from Windsor container?
Have a look at these links. You have to add a few classes to hook in to the service factory. These examples are for Unity but I easily modified them for Castle Windsor:
http://initializecomponent.blogspot.com/2008/06/integrating-unity-with-wcf.html
http://initializecomponent.blogspot.com/2008/06/unity-wcf-and-iis.html

GWT GIN HOW TO: injection of remote services

The gin tutorial seems to imply that to inject remote services all you need to do is annotate with #Inject.
Do you you still need to define this in a module somewhere or is the point that you can just annotate with #Inject and it will work?
Gin has automatic support for remote services, as outlined in the tutorial you mentioned:
Every time Gin is asked to inject an asynchronous remote service, it will inject an instance retrieved through calling GWT.create on its regular remote service.
Therefore, it will 'just work'.