I have a factory within Module/src/Module/Service/Factory/CourseServiceFactory.php
I have defined this factory in module.config.php as follows:
'service_manager' => array(
'factories' => array(
'CourseServiceFactory' => 'Module\Service\Factory\CourseServiceFactory',
),
),
However this factory isn't being loaded upon calling the application and I receive this error:
Warning: Missing argument 1 for
Module\Service\CourseService::__construct(),
This is how my CourseServiceFactory.php looks like:
public function createService(ServiceLocatorInterface $serviceLocator)
{
$config = $serviceLocator->get('config');
return new CourseService($config);
}
Anyone have any idea what's wrong?
I suspect you're not implementing the factory interface which causes the service loader to be injected into the constructor.
Make sure your factory implements:
Zend\ServiceManager\FactoryInterface
See example factory here
https://framework.zend.com/manual/2.4/en/in-depth-guide/services-and-servicemanager.html
Related
I have a problem when I am using MassTransit v5.1.5 with the default ASP.NET Core DI. I have the following code:
var consumers = typeof(CompanyApplicationService).Assembly
.GetTypes()
.Where(t => typeof(IConsumer).IsAssignableFrom(t))
.ToList();
consumers.ForEach(
c => services.AddSingleton(typeof(IConsumer), c));
cqrsConfig.ServiceCollectionConfig = (x) =>
{
consumers.ForEach(consumer => x.AddConsumer<consumer>());
};
So I have a separate assembly where my implementations of IConsumer<T> are. I have those consumers loaded into a list, but when I try to add them using the MassTransit.ExtensionsDependencyInjectionIntegration.IServiceCollectionConfigurator.AddConsumer<T>() method I cannot pass the type that I have previously loaded. So any ideas on this?
I have tried to register the consumers like:
cqrsConfig.InMemoryBusConfig = (c) =>
{
var host = c.Host;
c.ReceiveEndpoint(busName, ep =>
{
ep.LoadFrom(services.BuildServiceProvider());
});
};
but that also doesn't work for me.
There's more than one thing that is wrong here.
In order to know, which message to handle, MassTransit needs to know the generic interface type of the consumer. You, however, register all consumers as IConsumer, which is apparently wrong.
Consumers are by definition isolated to the message scope. So, consumers are instantiated and disposed for each message, and, therefore, cannot be singletons.
You need to register your consumers like it is described in the documentation:
services.AddScoped<OrderConsumer>();
or
services.AddMassTransit(x =>
{
x.AddConsumer<OrderConsumer>();
});
When consumers are added to the service collection, you also need to register the bus as it is shown in the documentation, so you use the service provider delegate:
services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
var host = cfg.Host("localhost", "/", h => { });
cfg.ReceiveEndpoint(host, "submit-order", e =>
{
e.LoadFrom(provider);
});
}));
services.AddSingleton<IBus>(provider => provider.GetRequiredService<IBusControl>());
I am trying to create my own ConfigurationDbContext from IdentityServer.
public class IdSrvConfigurationDbContext : ConfigurationDbContext<ConfigurationDbContext>
{
public IdSrvConfigurationDbContext(DbContextOptions<IdSrvConfigurationDbContext> options, ConfigurationStoreOptions storeOptions) : base(options.ChangeOptionsType<ConfigurationDbContext>(), storeOptions)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
//mylogic here
base.OnModelCreating(modelBuilder);
}
}
Now in the Startup.cs I tried the following
services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddConfigurationStore(options =>
{
// (DbContextOptionsBuilder) paramBuilder
options.ConfigureDbContext = paramBuilder =>
paramBuilder.UseSqlServer(connectionString,
sql => sql.MigrationsAssembly(migrationAssembly));
});
Now when I am trying to run migrations over my project, it goes through all the startup logic injection and ending with this error:
You will need to set up your IdSrvConfigurationDbContext type to expect a DbContextOptions<ConfigurationDbContext> instead. That’s the type the underlying ConfigurationDbContext expects and that’s also what the IdentityServer is going to pass down.
Usually, you should always use a typed DbContextOptions<T> matching to the context. But when inheriting from existing contexts, this can be a bit difficult. But in those cases, you don’t need to worry much: The typed options are only used to differentiate between the various configured options. So as long as each context in your application still uses a separate type, there shouldn’t be any problems.
The main reason for me to define custom ConfigurationDbContext/PersistedGrantDbContext was to set HasMaxLength over some properties. That's because in production we use NDBCLUSTER engine and if length is not defined or it's too big default type within MySQL will be longtext. This causes a problem, because NDBCLUSTER doesn't support text family data-types.
Within extension method I am plugging custom db context and at the same time setting the common ConfigurationDbContext/PersistedGrantDbContext. I guess IdentityServer uses them for the internal stuff.
services
.AddIdentityServer(options => {})
.AddConfigurationStore<ApplicationConfigurationDbContext>()
.AddConfigurationStoreCache()
.AddOperationalStore<ApplicationPersistedGrantDbContext>();
services.AddDbContext<PersistedGrantDbContext>(options => ContextBuilder(options, connectionString));
services.AddDbContext<ConfigurationDbContext>(options => ContextBuilder(options, connectionString));
services.AddDbContext<ApplicationPersistedGrantDbContext>(options => ContextBuilder(options, connectionString));
services.AddDbContext<ApplicationConfigurationDbContext>(options => ContextBuilder(options, connectionString));
static public void ContextBuilder(DbContextOptionsBuilder options, string connectionString)
{
options.UseMySql(connectionString: connectionString,
ServerVersion.AutoDetect(connectionString),
dbOptions => dbOptions.MigrationsAssembly(DataExtensions.MigrationAssemblyName));
}
That way migrations are created and applied properly and I didn't face any problems during the runtime.
Trying to work my way through setting up a phalcon mvc application.
I have 2 modules current set up for testing. "Frontend" and "Admin".
I have different views set up so I can confirm I am getting through to each of the modules. When I change the defaultnamespace and defaultmodule I can indeed see that both modules are being accessed fine and loading ok. I can see that the admin controllers are being accessed correctly and the frontend controllers are being accessed when I change this.
The problem I am currently having is when I try to authenticate a user and start the session I want to forward the request over from "Frontend" to "Admin":
return $this->dispatcher->forward(array(
'namespace' => 'Qcm\Admin\Controllers',
'action' => 'index',
'controller' => 'index'
));
Again I have confirmed these namespaces work fine. The problem is when I now forward onto the new namespace it can no longer find the admin index controller?
"Qcm\Admin\Controllers\IndexController handler class cannot be loaded"
However I have already confirmed that I can switch between the modules by changing the defaultnamespace/defaultmodule. Is this a limitation within the dispatcher that I can not forward to a different module?
Just to clarify I am also using the same url's so for example after login I want it to go back to '/' (root) but because it has forwarded to the admin module this should work fine correct?
The phalcon dispatcher can only forward to actions within the same module. It cannot forward you outside the current module. This restriction comes because the dispatcher is only aware of the module in which it is declared.
In order to forward to another module, you must instead return a redirect response from a controller action. In my case, I wanted to forward the user to a login screen or a 404 error page based on their ACL permissions in the beforeDispatch() method of a plugin. The dispatcher is native to this method, but cannot forward the user outside of the current module. Instead, I have the dispatcher forward the user to a controller in the same module that has a custom action that in turn performs the redirect.
// hack to redirect across modules
$dispatcher->forward(
array(
'controller' => 'security',
'action' => 'redirect',
'params' => array(
'redirect' => '/home/index/login'
),
)
);
return false; // stop progress and forward to redirect action
This means that each module needs to have a copy of this custom redirect action in one of its controllers. I accomplished this by putting the action in the base controller that all of my controllers extend from.
/**
* the phalcon dispatcher cannot forward across modules
* instead, forward to this shared action which can then redirect across modules
* */
public function redirectAction(){
$this->view->disable();
$params = $this->dispatcher->getParams();
$redirect = '/';
if( ! empty( $params['redirect'] ) ){
$redirect = $params['redirect'];
}
return $this->response->redirect( $redirect );
}
Because phalcon didn't add all modules to global loader, so the namespace is not registered. you need to register another module in current module bootstrap file, modify your Module.php as
class Module
{
public function registerAutoloaders()
{
$loader = new \Phalcon\Loader();
$loader->registerNamespaces(array(
//Your current module namespaces here
....
//Another module namespaces here
'Qcm\Admin\Controllers' => 'controller path',
));
$loader->register();
}
}
The main reason it shows IndexController class not loaded is because you might not have added Dispatcher in that module or in the bootstrap file(depending on your approach)
Add
$debug = new \Phalcon\Debug();
$debug->listen();
to your code before
$application->handle()->getcontent();
to view erros.
Before the replacement line:
echo $application->handle()->getContent();
code:
$router = $this->getDi()->get("router");
$params = $router->getParams();
$modName = $router->getModuleName();
$url = null;
if ($modName == "admin" && isset($params[0])) {
$module = "/" . $params[0];
$controller = isset($params[1]) ? "/" . $params[1] . "/" : null;
$action = isset($params[2]) ? $params[2] . "/" : null;
$params = sizeof($params) > 3 ? implode("/", array_slice($params, 3)) . "/" : null;
$url = $module . $controller . $action . $params;
}
echo $application->handle($url)->getContent();
I was able to define my own authentication service with Zend\Authentication. Now I want to be able to change the session timeout limit.
I don't want to change the general session config but only for this Authentication manager.
As I want to reuse this adapter, I want to find a way to do it through the module.config.php configuration file.
For the moment, I am creating my service like that
public function getServiceConfig()
{
return array(
'factories' => array(
'cas_auth_service' => function ($sm) {
$authService = new \Zend\Authentication\AuthenticationService;
$authService->setAdapter($sm->get('\CasAuthen\Authentication\Adapter\Cas'));
return $authService;
},
),
);
}
I was thinking about creating my own Authentication Storage adapter and then injecting it but I don"t know if it is the right way to do it.
Does anymore know how to proceed ?
Thank you in advance and have a nice day.
Sometimes my app fails to connect to my db.
How do I catch and redirect to a statis page?
CDbConnection failed to open the DB connection: SQLSTATE[42000] [1049] Unknown database 'given_db'
It's not the cleanest solution, but you can create your custom DbConnection component:
class DbConnection extends CDbConnection
{
public function open()
{
try {
parent::open();
} catch(CDbException $e) {
Yii::app()->request->redirect(array('site/maintenance'));
}
}
}
And then configure this as your db component:
'components' => array(
'db' => array(
'class' => 'DbComponent',
The drawbacks are:
Will only work in the web and break your console apps
Requires site/maintenance to definitely be free of any DB access or you'd end up in an infinite redirect loop
Can't you just create your own 500 error page?
Check this for more info: http://www.yiiframework.com/doc/guide/1.1/en/topics.error#displaying-errors
you can set below in components array
'cache' => array('class' => 'system.caching.CDbCache'),