#Activate not called when starting component - liferay

Following Liferay's documentation about making modules configurable, I wrote this Liferay 7 module:
#Component(configurationPid = "myproject.api.TranslationConfiguration")
public class TranslationServiceImpl implements TranslationService {
private volatile TranslationConfiguration configuration;
public TranslationServiceImpl() {
log.info("TranslationServiceImpl constructor");
}
#Activate
#Modified
protected void activate(Map<String, Object> properties) {
log.info("Hello from activate");
}
}
When I deploy, the log only shows:
TranslationServiceImpl constructor
Service registered.
STARTED myproject.impl_1.0.0 [538]
Why is the activate method not called?
Restarting the module in Gogo Shell does not call activate either.

By default a component in declarative services is only activated when its service is referred by another bundle.
If you want it to start right away use immediate=true

Related

How to inject IHttpClientFactory in Container servicestack.net?

I'm working on a solution that interacts with Redis, using the servicestack.net library.
I have a class that inherits from ServiceStack.AppHostBase and asks me for an override of the Configure method. This method has as a parameter a Funq.Container that I see is an implementation of IServiceProvider, IResolver and IContainer, and none of these interfaces have the AddHttpClient method that is provided by the IServiceCollection. Method I need to be able to inject the IHttpClientFactory. Any idea how to solve my problem?
To do it in ASP.NET (not .NET Core), the quick way would be to:
install Microsoft.Extensions.DependencyInjection package and call .AppHttpClient() extension
Build the Service Provider you would normally see in .NET Core
Get the instance of IHttpClientFactory from the Service Provider
Register the instance of IHttpClientFactory with Funq.Container again
using Microsoft.Extensions.DependencyInjection;
public class AppHost : AppHostBase
{
public override void Configure(Container container)
{
...
RegisterHttpClientFactory(container);
}
private container RegisterHttpClientFactory(Container container)
{
var services = new ServiceCollection()
.AddHttpClient();
// You can kind of inspect services returned.
// You can see this extension registers lot of other things too beside
// IHttpClientFactory.
// Also you can see the lifetime of IHttpClientFactory is Singleton.
var serviceProvider = services.BuildServiceProvider();
container.AddSingleton(serviceProvider.GetService<IHttpClientFactory>());
return container;
}
}
If you happen to use Unity Adaptor
Unity has a package to give you an extension as well to build the Service Provider directly into the Unity Container:
using Microsoft.Extensions.DependencyInjection;
using Unity;
using Unity.Microsoft.DependencyInjection;
public static class UnityConfig
{
public static void RegisterTypes(IUnityContainer container)
{
...
container.RegisterServices();
container.RegisterHttpClientFactory();
}
private static IUnityContainer RegisterHttpClientFactory(
this IUnityContainer unityContainer)
{
new ServiceCollection()
.AddHttpClient()
.BuildServiceProvider(unityContainer);
return unityContainer;
}
}
This is the interface definition of IServiceCollection from IServiceCollection.cs:
public interface IServiceCollection : IList<ServiceDescriptor>
{
}
AddHttpClient is just an extension method from Microsoft.Extensions.DependencyInjection that wraps adding a number of additional dependencies to ASP.NET Core IOC.
So you should continue to register it on ASP.NET Core IOC, i.e:
public class Startup : ModularStartup
{
public new void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseServiceStack(new AppHost
{
AppSettings = new NetCoreAppSettings(Configuration)
});
}
}
As any dependencies registered .NET Core Startup are also available to ServiceStack.

Adding ApplicationInsights to Azure Function with Autofac

I've got an Azure function which I'm adding Application Insights logging to.
It uses autofac to manage the dependencies in a config file, and I have added as follows:
private static void RegisterDependencies(ContainerBuilder containerBuilder)
{
containerBuilder.RegisterType<ApplicationInsightsLoggerFactory>()
.As<ILoggerFactory>()
.SingleInstance();
containerBuilder.Register(client => new TelemetryClient(new TelemetryConfiguration("[instrumentation key]"))).As<TelemetryClient>().SingleInstance();
...
In Program.cs 'Main', this class is called like this IocConfig.Configure()
The function runs with no errors, but the logging is not appearing in Application Insights. Have I missed something in this configuration?
You don't to write the DI yourself to get a TelemetryClient. The built-in DI is already available for you to just get one:
public class MyFunctionClass
{
private readonly TelemetryClient telemetryClient;
/// Using dependency injection will guarantee that you use the same configuration for telemetry collected automatically and manually.
public MyFunctionClass(TelemetryConfiguration telemetryConfiguration)
{
this.telemetryClient = new TelemetryClient(telemetryConfiguration);
}

Register ModelListener<JournalArticle> in Liferay 7

I'm trying to implement a ModelListener in Liferay 7. When I'm updating a JournalArticle in the UI, I would like to add a small behaviour and some logging.
#Component(immediate = true, service = ModelListener.class)
public class DownloadsListener extends BaseModelListener<JournalArticle> {
#Reference
private StructureService structureService;
#Reference
private DLFileEntryLocalServiceUtil fileEntryLocalService;
private static final Log LOG = LogFactoryUtil.getLog(DownloadsListener.class);
#Override
public void onAfterUpdate(JournalArticle model) throws ModelListenerException {
LOG.error("UPDATES!");
LOG.error("UPDATES!");
super.onAfterUpdate(model);
if(structureService.isNieuwsArticle(model)) {
}
getFileFromURL("/documents/82177/0/file.pdf/0d10338c-8ca1-c5b7-cc4b-011bef1ee759");
}
private DLFileEntry getFileFromURL(String url) {
String[] splittedURL = StringUtil.split(url, '/');
return null;
}
}
But this code is never triggered when I'm updating an article. I'm not hitting my debug point in the onAfterUpdate method, and I'm not seeing any logging. The OSGI Module is deployed correctly. What am I missing?
The issue was that my ModelListener was not being correctly deployed in the OSGi container. (Although Eclipse / Apache Gogo told everything was fine).
OSGi could not resolve:
#Reference
private DLFileEntryLocalServiceUtil fileEntryLocalService;
Changed it to
#Reference
private DLFileEntryLocalService fileEntryLocalService;
Now the behaviour is correctly. It's a shame that there is ZERO feedback by Apache GoGo.

Access SignalR Hub without Constructor Injection

With AspNetCore.SignalR (1.0.0 preview1-final) and AspNetCore.All (2.0.6), how can I invoke a method on a hub in server code that is not directly in a Controller and is in a class that cannot be made via Dependency Injection?
Most examples assume the server code is in a Controller and should 'ask' for the hub via an injectable parameter in a class that will created by DI.
I want to be able to call the hub's method from server code at any time, in code that is not injected. The old SignalR had a GlobalHost that enabled this approach. Basically, I need the hub to be a global singleton.
Now, everything seems to be dependent on using Dependency Injection, which is introducing a dependency that I don't want!
I've seen this request voiced in a number of places, but haven't found a working solution.
Edit
To be more clear, all I need is to be able to later access the hubs that I've registered in the Configure routine of the Startup class:
app.UseSignalR(routes =>
{
routes.MapHub<PublicHubCore>("/public");
routes.MapHub<AnalyzeHubCore>("/analyze");
routes.MapHub<ImportHubCore>("/import");
routes.MapHub<MainHubCore>("/main");
routes.MapHub<FrontDeskHubCore>("/frontdesk");
routes.MapHub<RollCallHubCore>("/rollcall");
// etc.
// etc.
});
If I register them like this:
services.AddSingleton<IPublicHub, PublicHubCore>();
it doesn't work, since I get back an uninitiated Hub.
No It's not possible. See "official" answer from david fowler https://github.com/aspnet/SignalR/issues/1831#issuecomment-378285819
How to inject your hubContext:
Best solution is to inject your hubcontext like IHubContext<TheHubWhichYouNeedThere> hubcontext
into the constructor.
See for more details:
Call SignalR Core Hub method from Controller
Thanks to those who helped with this. Here's what I've ended up on for now...
In my project, I can call something like this from anywhere:
Startup.GetService<IMyHubHelper>().SendOutAlert(2);
To make this work, I have these extra lines in Startup.cs to give me easy access to the dependency injection service provider (unrelated to SignalR):
public static IServiceProvider ServiceProvider { get; private set; }
public static T GetService<T>() { return ServiceProvider.GetRequiredService<T>(); }
public void Configure(IServiceProvider serviceProvider){
ServiceProvider = serviceProvider;
}
The normal SignalR setup calls for:
public void Configure(IApplicationBuilder app){
// merge with existing Configure routine
app.UseSignalR(routes =>
{
routes.MapHub<MyHub>("/myHub");
});
}
I don't want all my code to have to invoke the raw SignalR methods directly so I make a helper class for each. I register that helper in the DI container:
public void ConfigureServices(IServiceCollection services){
services.AddSingleton<IMyHubHelper, MyHubHelper>();
}
Here's how I made the MyHub set of classes:
using Microsoft.AspNetCore.SignalR;
using System.Threading.Tasks;
public class MyHub : Hub { }
public interface IMyHubHelper
{
void SendOutAlert(int alertNumber);
}
public class MyHubHelper : IMyHubHelper
{
public IHubContext<MyHub> HubContext { get; }
public MyHubHelper(IHubContext<MyHub> hubContext)
{
HubContext = hubContext;
}
public void SendOutAlert(int alertNumber)
{
// do anything you want to do here, this is just an example
var msg = Startup.GetService<IAlertGenerator>(alertNumber)
HubContext.Clients.All.SendAsync("serverAlert", alertNumber, msg);
}
}
This is a nice solution. In .NET Core 2.1 the service provider is disposed and you get cannot access disposed object. The fix is to create a scope:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
ServiceProvider = serviceProvider.CreateScope().ServiceProvider;

Determining application context from OWIN pipeline?

I have an OWIN pipeline using Nancy:
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNancy();
}
}
The UseNancy() is actually a call to my own custom extension method defined in this gist: https://gist.github.com/TheFastCat/0b7635d9e5795b44e72e
This code is executed both as an Azure Website or an Azure Cloud Service. Based on the context it is executing within I want to use a particular favicon, loaded as an embedded resource from a separate assembly. I do this by specifying separate NancyBootstrappers (each loading the proper favicon for its context).
Is there a more elegant solution to determining the runtime application that is executing the OWIN pipeline? Currently I check app.Properties["host.AppName"] ; however while the Website's app name matches it's assembly configuration, the CloudService app is the name of the Owin startup assembly.class. (see gist). It's cloogey.
Is there a more elegant/simple solution for specifying a custom favicon within Nancy for each of my web applications than creating separate bootstrappers and doing runtime application context checks?
I solved this problem with the help of others on the https://jabbr.net/#/rooms/owin and https://jabbr.net/#/rooms/nancyfx chat boards
Yes. You can contextually check the OWIN host properties:
if (app.Properties.ContainsKey("System.Net.HttpListener"))
{
// self hosted application context
}
2.) Yes.
namespace ClassLib
{
public class Startup()
{
public Startup(byte[] favIcon) { ... }
public void Configuration(IAppBuilder app) { ... }
}
}
[assembly: OwinStartup(typeof(WebHost.Startup))]
namespace WebHost
{
public class Startup()
{
public voic Configuration(IAppBuilder app)
{
new ClassLib.Startup(webhostFavIcon).Configuration(app);
}
}
}
namespace SelfHost
{
private class Program()
{
public void Main(string[] args)
{
using(WebApp.Start(app => new ClassLib.Startup(selfHostFavIcon).Configuration(app))
{}
}
}
}

Resources