I can use "Callbacks" between datasnap server and clients given as an example here by Pawel Glowacki.
But when I add DSAuthenticationManager1 on the server form with simple authentication then at the client sides I can not registered callbacks.
I get this error: "Exception class TDBXError with message 'Remote error: Authentication manager rejected user credentials. This may due to invalid combination of DS user name and password'."
I added login details to SQLConnection at the client like this:
SQLConnection1.Params.Values['DSAuthenticationUser'] := Username;
SQLConnection1.Params.Values['DSAuthenticationPassword'] := Password;
So my SQLConnection1 successfully connects to server. But I can not find any way for DSAuthenticationManager1.
How can I import login params to DSAuthenticationManager1?
The TDSClientCallbackChannelManager component in Delphi-XE does not include the same properties as in Delphi-XE2. When I add this component to my project (XE2), I have Username and Password properties, which are passed to the DataSnap server's DSAuthenticationManager.OnUserAuthenticate method whenever RegisterCallback() or UnregisterCallback() are called.
Do you have the latest XE update? If username and password aren't in the latest update, then you will likely need to upgrade to XE2 in order to use TDSAuthenticationManager in the DataSnap server and TDSClientCallbackChannelManager in the client.
I thought that perhaps you could create your own class from TSDClientCallbackChannelManager and override the methods that add the username and password to the DBXConnection -- thus giving you a way to add them yourself. I tried this, but the methods that need to be overridden are not virtual. I thought perhaps I could hide the ancestor methods by promoting methods with the same names in my new class as public, whereas they were protected in the ancestor class. It generated code and linked it into my client app (evident by the blue dots next to the new lines of code), but it wouldn't call my code at run-time. It always called the ancestor methods instead (DBXConnectionProperties and ExecuteRemote).
I think your only solution is to either update to XE2, or not use the authentication manager on the server.
Related
I have classes that have a constructor such as
constructor Create(Factory: IFactory<IConnection>)
When I try and register the IFactory in the container
Container.RegisterType<IFactory<IConnection>,TConnectionFactory>
or
Container.RegisterType<TConnectionFactory>.Implements<IFactory<IConnection>>
I get an error stating that the interface does not have a guid.
I don't really want to add lots of pointless interfaces such as
IConnectionFactory = interface(IFactory<IConnection>)
['{45106BA8-43E7-4D26-B0EF-1639871B93E4}']
end;
to get around this but is this the only way?
Many thanks
As you found out the generic interface can have a GUID.
That itself causes no harm until you QueryInterface/Supports IList<string> from something that is an IList<Integer> which would erroneously succeed and subsequently fail once you start working with it. FWIW since you mentioned those types while the collection interfaces all have guids there is no need to ever do such querying when using them but they are required internally which then stays within the same generic type argument.
Currently the GUID is being used to check and get the interface from the implementing object because the RTL only supports doing that with a GUID and not with typeinfo.
In fact following code would not raise an exception during the registration but eventually cause defects when being resolved:
RegisterType<IFactory<IConnection>, TSomeFactory> where TSomeFactory implements IFactory<ISomethingElse>
However there is some rather hidden typeinfo available (see the commented line in System.TInterfaceTable) that has the exact typeinfo of the implemented interfaces. Spring4D internally uses that at some places, for example Spring.Reflection.TRttiTypeHelper.GetInterfaces.
That could be used but then there is another catch: generic types across multiple modules have different typeinfo. So it's not so easy to simply use that information to validate during registration and query the interface from the implementing class because right now the container (via some extension) supports registrations and dependencies across multiple modules.
Making the registration more robust and if possible remove the requirement for having a GUID on the interface is something I have on my list for the container refactoring which is planned for later this year.
I'm a relatively new user of both Autofac and ASP.NET Core. I've recently ported a small project from a 'classic' ASP.NET WebAPI project to ASP.NET Core. I am having trouble with Autofac, specifically in registration of generic types.
This project uses a Command pattern, each command handler is a closed generic like
public class UpdateCustomerCommandHandler: ICommandHandler<UpdateCustomerCommand>
These command handlers are injected into the controllers like:
readonly private ICommandHandler<UpdateCustomerCommand> _updateCustomerCommand;
public ValuesController(ICommandHandler<UpdateCustomerCommand> updateCustomerCommand)
{
_updateCustomerCommand = updateCustomerCommand;
}
Autofac is configured (partially) as:
var builder = new ContainerBuilder();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
//This doesn't seem to be working as expected.
builder.RegisterAssemblyTypes(assemblies)
.As(t => t.GetInterfaces()
.Where(a => a.IsClosedTypeOf(typeof(ICommandHandler<>)))
.Select(a => new KeyedService("commandHandler", a)));
The above does not seem to be registering the generic as expected. If I use the below method for registration, it works well.
builder.RegisterType<UpdateCustomerCommandHandler>().As<ICommandHandler<UpdateCustomerCommand>>();
When I say "It doesn't work", what I mean is that when attempting to instantiate the controller, I get "InvalidOperationException: Unable to resolve service for type 'BusinessLogic.ICommandHandler`1[BusinessLogic.UpdateCustomerCommand]' while attempting to activate 'AutoFac_Test.Controllers.ValuesController'."
This worked well in the Full WebAPI version of this project, but not after recreating it in ASP.NET Core. To be clear, this was working perfectly well before porting to ASP.NET Core.
Here is a link to the code that I've used to recreate this issue:
https://dl.dropboxusercontent.com/u/185950/AutoFac_Test.zip
**** EDIT AFTER SOLUTION DISCOVERED ****
There was nothing in fact wrong with my Autofac configuration and certainly not Autofac itself. What had happened was that I had renamed the output of my dependent assemblies in an effort to make the assembly scanning stuff (replacing of AppDomain.CurrentDomain.GetAssemblies() more elegant, however I never modified the dependencies of the API project to reference the new assemblies. So Autofac was scanning the correctly loaded assemblies which happened to be the older versions, which did not contain the interfaces and implementations I expected...
Autofac has built-in support to register closed types of open-generic.
builder
.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
This will scan your assembly, find types that close the open generic ICommandHandler<> interface, and register each of them against the closed generic interface they implement - in your case, ICommandHandler<UpdateCustomerCommand>.
What doesn't work in your example is that you associate a key to your services. Autofac doesn't look for the keyed version of your ICommandHandler<UpdateCustomerCommand> when trying to instantiate the ValuesController, which is why you get the exception.
Edit after QuietSeditionist's comment:
I'll try to elaborate a bit on the keyed vs. default services. The way you registered your handlers is by associating the commandHandler key to them.
This means that once the container is built, here's the only way you can resolve such a handler:
// container will look for a registration for ICommandHandler<UpdateCustomerCommand> associated with the "commandHandler" key
container.ResolveKeyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler");
When instantiating ValuesController, Autofac doesn't look for a keyed registration of ICommandHandler<UpdateCustomerCommand>, because it wasn't asked to.
The equivalent code it's executing is - and you can try to run that code yourself to get the exception:
// BOOM!
container.Resolve<ICommandHandler<UpdateCustomerCommand>>();
The reason your second registration works is because you didn't key the service:
// No key
builder
.RegisterType<UpdateCustomerCommandHandler>()
.As<ICommandHandler<UpdateCustomerCommand>>();
// commandHandler key
builder
.RegisterType<UpdateCustomerCommandHandler>()
.Keyed<ICommandHandler<UpdateCustomerCommand>>("commandHandler");
But since you don't want to register all your handlers one by one, here's how to register them without keying them:
builder
.RegisterAssemblyTypes(ThisAssembly)
.AsClosedTypesOf(typeof(ICommandHandler<>));
/Edit
I can see two scenarios where keying services can be useful:
You have several types implementing the same interface and you want to inject different implementations in different services. Let's say, you register both SqlConnection and DB2Connection as IDbConnection. You then have 2 services, one which is supposed to target SQL Server, the other one DB2. If they both depend on IDbConnection, you want to make sure you inject the correct one in each service.
If you use decorators, the way registrations work is you define the services to which the decorators will apply by a key - the first example is self-explanatory
Because Google brings you to this page even when you're trying to manually register types, I thought that even though this doesn't answer the asked question, it would be useful for future visitors. So, if you want to manually register a generic type, you would use this format:
service.AddTransient(typeof(IThing<>), typeof(GenericThing<>));
or if there's no interface, then just:
service.AddTransient(typeof(GenericThing<>));
and for completeness, if you have a generic with multiple types:
services.AddTransient(typeof(GenericThing<,>));
I add two annotations on the service method, after compiled, I found the method were compiled to a new class file, and I decompiled the generated class files and found the #CompileStatic were not work as wished.
Is is right or a bug of grails?
class FoobarService {
#grails.transaction.Transactional
#groovy.transform.CompileStatic
void foobar() {
....
}
}
The grails.transaction.Transactional annotation is a replacement for the traditional Spring org.springframework.transaction.annotation.Transactional annotation. It has the same attributes and features and works essentially the same, but it avoids an unfortunate side effect of using the Spring annotation.
The Spring annotation triggers the creation of a runtime proxy of the annotated class. Spring uses CGLIB to create a subclass of the target class (typically a Grails service) and an instance of the CGLIB proxy is registered as the Spring bean instead of registering a service instance directly. The proxy gets an instance of your service as a data variable.
Each method call is intercepted in the proxy, where it does whatever checks and/or setup is required based on the transaction settings, e.g. joining an existing transaction, creating a new one, throwing an exception because one isn't already running, etc. Once that's done, your real method is called.
But if you call another annotated method with different settings (e.g. the first method uses the default settings from #Transactional but the second should be run in a new separate transaction because it's annotated with #Transactional(propagation=REQUIRES_NEW)) then the second annotations settings will be ignored because you're "underneath" the proxy , inside the real instance of your service that the proxy is intercepting calls to. But it can't intercept direct calls like that.
The traditional workaround for this is to avoid direct calls and instead make the call on the proxy. You can't (at least not conveniently) inject the service bean into itself, but you can access the application context and access it that way. So the call that you would need in that situation would be something like
ctx.getBean('myService').otherMethod()
which works, but is pretty ugly.
The new Grails annotation works differently though. It triggers a reworking of the code via an AST transformation during compilation. A second method is created for each annotated method, and the code from the real method is moved inside there, in a GrailsTransactionTemplate that runs the code using the annotations settings. Once there, the code runs with the required transaction settings, but since every method is rewritten in this way, you don't have to worry about the proxy and where you're calling the methods from - there is no proxy.
Unfortunately there's a side effect that you're seeing - apparently the transformation happens in a way that isn't preserving the #CompileStatic annotation, so the code runs in dynamic mode. Sounds like a bug to me.
I'm trying to figure out how to inject run-time arguments into a singleton when it is created, and then have those arguments just be remembered from then on. I'm not sure if the interface for run-time arguments can support this, though. Say, for example, I have a Client object that requires a token, and has the following initializer:
+ (instancetype)initWithToken:(NSString *)token;
The token is obtained at runtime from the server and is different for every user, so I can't simply put the NSString in the definition. So I create the following method on my Typhoon assembly:
- (Client *)clientWithToken:(NSString *)token;
However, in the future (when I'm injecting this client into other classes), I won't have the token on hand to call this method with. So I would like to just be able to inject [self client], for example. Since the client is a singleton and has already been created, the token isn't necessary, anyway.
However, I can't seem to find a way to do this. Obviously, defining a separate method called client would just return a different client. Can I just call clientWithToken:nil and the argument will be ignored if the client already exists? Perhaps traversing the assembly's singletons array would work, but that is obviously very inelegant.
I have considered injecting by type (so I don't need a method to call), but I have multiple different clients of the same type, so I need to be explicit about which client to inject. Of course, there is also the option of removing this parameter from the initializer, and instead setting it as a property from outside the assembly; however this pattern is used throughout our application, so I would like to avoid rewriting that much code.
Thank you.
Reviewing the Typhoon User Guide's 'When to Use Runtime Arguments' shows that this scenario isn't really a good match. Runtime arguments are great when we have a top-level component that mixes some static dependencies with information that is known later - thus avoiding the creation of a custom 'factory' class. Its not possible to use them in the way described.
Instead consider the following suggestions:
Inject a shared context class
Create a mutable Session model object and register it with Typhoon. Update the state on this model when you have a token. Inject this into the clients, which will use this session information when making connections.
Aspect Hook
Hook your clients so that before a method is invoked the token information is available. This could be done by:
Using an Aspects library like this one.
Define a Protocol for the clients and wrap the base implementation in one that is security aware.
How can I determine the User that initiated one of my functions that I have created in my Server Methods Unit?
in the ServerContainerUnit or WebModuleUnit (ISAPI),
DSAuthenticationManager.onUserAuthenticate procedure or TDSServer.onConnect ect...,
use TDSSessionManager.GetThreadSession.PutData('UserName',User); identify current user to DSSession,
in your Servermethods unit functions, you can use TDSSessionManager.GetThreadSession.GetData('UserName')from the DSSession what you saved onUserAuthenticate or other procedure.
Tested on DataSnap REST ISAPI, work fine.
Just use TDSSessionManager.GetThreadSession.Username if you have authentication enabled.