I use Lazy initialization for app singleton in Xamarin.Forms (app runs on iOS):
public sealed class DataSingleton
{
private static readonly Lazy<DataSingleton> lazy = new Lazy<DataSingleton>(() => new DataSingleton(), LazyThreadSafetyMode.PublicationOnly); // tried withou 2nd parameter as well
public static DataSingleton Instance
{
get { return lazy.Value; }
}
...
}
And i call it in webserver which runs to provide data for Front-end which is in Angular (used web view to show Angular code)
var server = new WebServer(o => o
.WithUrlPrefix($"http://localhost:{appSettings.ApiPort}")
.WithMode(HttpListenerMode.EmbedIO))
.WithCors()
.WithLocalSessionManager()
.WithWebApi("/api", m => m
.WithController<TestController>()
.WithController<SettingsController>()
.WithController<ReportController>()
.WithController<SystemController>())
.WithModule(new ActionModule("/", HttpVerbs.Any,
ctx => ctx.SendDataAsync(new { Message = "Error" })))
.RunAsync();
In controllers is called DataSingleton to get/set data, but after app returns from background, DataSingleton.Instance is null.
What should I do to don't lose data of singleton, while app is in background for short time (approximately 5 minutes)
Update - I've figured out that this problem is only in Controllers, cause when app gets back to front I can see all the data in AppDelegate WillEnterForeground event..
Given that it is the webserver that is having the problem, stop it when app goes into background. Start it again when app returns (or lazy-start as needed).
Code might be something like this:
App.xaml.cs:
public static Webserver MyWebServer
{
get
{
if (_server == null)
{
_server = new Webserver(...);
}
return _server;
}
}
public static void StopWebServer()
{
if (_server != null)
{
_server.Dispose();
// So will be created again, on next reference to MyWebServer.
_server = null;
}
}
private static Webserver _server;
...
protected override void OnSleep()
{
StopWebServer();
}
Usage elsewhere:
... App.MyWebServer ...
If you don't want to make static variable (though IMHO that is okay for App, because there is only one, and its lifetime is that of the app itself), then remove the "static"s above, usage elsewhere becomes:
... (Xamarin.Forms.Application.Current as App).MyWebServer ...
In this case, there can be race-condition.
If two (or more threads) simultaneously reads Instance for first time, there will be created multiple instances of DataSingleton. However every other read will get just one instance. It depends on your scenario, if it is ok.
public sealed class DataSingleton {
private static instance;
// will assign new DataSingleton only if "instance" is null.
public static Instance => instance ??= new DataSingleton();
}
Or you can use Interlocked class ensuring, the instance field will not be overriden if another thread already initialized the instance field.
public sealed class DataSingleton {
private static instance;
public static Instance {
get {
var result = instance;
// early exit if singleton is already initialized
if (result is not null) return result;
var created = new DataSingleton();
// thread-safe way how to assign "created" into "instance" only if "instance" refers to null. othervise no assignment will be made
var original = Interlocked.CompareExchange(ref instance, null, created);
// some other thread already initialized singleton
if (original is not null) return original;
// return newly created instance
return result;
}
}
}
Or you can use lock to ensure, just one instance is created.
public sealed class DataSingleton {
private static instance;
public static Instance {
get {
var result = instance;
// early exit if singleton is already initialized
if (result is not null) return result;
lock(typeof(DataSingleton)) {
result = instance;
// double check, if instance was not initialized by another thread
if (result is not null) return result;
return instance = new DataSingleton();
}
}
}
}
Related
I need to find a way to get an instance of DataProcessingEngine without calling it's constractor.
I am trying to find a way to do so using the registered DataProcessingEngine in composition object (please see the following code). But I could not find a way to do so.
Anyone have a suggestion? Thanks in advance.
public class Composer : IUserComposer
{
public void Compose(Composition composition)
{
composition.Register<IDataProcessingEngine, DataProcessingEngine>(Lifetime.Singleton);
//DataProcessingEngine dataProcessing = compostion.Resolve<IDataProcessingEngine>()??//no resolve function exists in Umbraco.Core.Composing
SaveImagesThread(dataProcessingEngine);
}
public Task SaveImagesThread(IDataProcessingEngine dataProcessingEngine)//TODO - decide async
{
string dataTimerTime = WebConfig.SaveProductsDataTimer;
double time = GetTimeForTimer(dataTimerTime);
if (time > 0)
{
var aTimer = new System.Timers.Timer(time);
aTimer.Elapsed += new ElapsedEventHandler(dataProcessingEngine.SaveImages);
aTimer.Start();
}
return default;
}
}
For all of you who are looking for a way to call a function (that's defined in another class in your code, an Engine or ...) from the composer(where the app starts) and want to avoid calling this function's class' constractor. I've found another way to do so:
public class QueuePollingHandler
{
[RuntimeLevel(MinLevel = RuntimeLevel.Run)]
public class SubscribeToQueuePollingHandlerComponentComposer :
ComponentComposer<SubscribeToQueuePollingHandler>
{ }
public class SubscribeToQueuePollingHandler : IComponent
{
private readonly IDataProcessingEngine _dataProcessingEngine;
public SubscribeToQueuePollingHandler(IDataProcessingEngine
dataProcessingEngine)
{
_dataProcessingEngine = dataProcessingEngine;
SaveImagesThread(_dataProcessingEngine);
}
public void SaveImagesThread(IDataProcessingEngine
dataProcessingEngine)
{
....
}
}
And the logic explenation: You create a class (SubscribeToQueuePollingHandlerComponentComposer from the example) and define its base class to be ComponentComposer<Class_that_inherits_IComponent>.
And when you start the application you could see that it gets to the registered class' constractor (SubscribeToQueuePollingHandler constructor).
That's the way that I found to be able to call a function right when the application starts without needing to call its class constractor and actualy use dependency injection.
In my application I've noticed that if I mark a class in the SM registry as a Singleton type it gets disposed of, however if don't specify any Singleton it doesn't get disposed of.
What and why are the reasons for this?
public class IoC
{
public static IContainer Init()
{
var container = new Container(x =>
{
x.Scan(s => {
s.TheCallingAssembly();
s.AssembliesFromApplicationBaseDirectory();
s.WithDefaultConventions();
});
// disposed is called on this class but not if .Singleton() is removed
x.For<IMyService>().Singleton();
});
return container;
}
}
class Program
{
static void Main(string[] args)
{
using (var container = IoC.Init())
{
var theStory1 = container.GetInstance<MyService>();
theStory1.TheMethod();
}
}
}
Singleton lifecycle is bound to the container's scope thus when disposing the container it takes care to dispose all singletons implementing IDisposable. With transients and other lifecycles like HttpContextScoped it is up to developer to dispose them manually when no longer need them.
Transient disposables are tricky a little bit in terms of how it should be handled. Imagine case like this one below:
public class ClassWithDisposableTypeDependency
{
private readonly ISampleDisposable disposableType;
public ClassWithDisposableTypeDependency(ISampleDisposable disposableType)
{
this.disposableType = disposableType;
}
public void SomeAction()
{
using (this.disposableType)
{
this.disposableType.DoSomething();
}
}
}
What will happend when SomAction() won't be executed? Dispose won't be called on disposableType field. In fact in this case ClassWithDisposableTypeDependency should also implement IDisposable and dispose its disposable dependencies.
But there is a better way to handle such cases. In mentioned case the main issue is to defer creation of a dependency to a moment when we really need that objects. We can achieve that in many ways: func, lazy, factory, etc. Here is possible solution with usage of func.
public class ClassWithDisposableTypeFuncDependency
{
private readonly Func<ISampleDisposable> disposableTypeFactory;
public ClassWithDisposableTypeFuncDependency(Func<ISampleDisposable> disposableTypeFactory)
{
this.disposableTypeFactory = disposableTypeFactory;
}
public void SomeAction()
{
var disposable = this.disposableTypeFactory();
using (disposable)
{
disposable.DoSomething();
}
}
}
This is how we need to setup it in StructureMap:
var container = new Container(c => c.For<ISampleDisposable>().Use<SampleDisposable>());
var clazz = container.GetInstance<ClassWithDisposableTypeFuncDependency>();
clazz.SomeAction(); // dependency is created and disposed
Hope this helps!
Can we create a Custom LifeCycle using StructureMap wherein the object has to be in Singleton scope for specified preiod of time, after which the object has to be created again. In short, can we create objects every 20 or 30 mins.
Sure, see e.g. http://www.mikeobrien.net/blog/creating-structuremap-lifecycle-for-wcf/ for an example of how to implement ILifecycle (in this case backed by WCF, but you can just as well make it thread-local, or static). You'll just have to add the logic to return a new IObjectCache instance after x minutes have passed.
Copy/paste of the code there:
public class WcfOperationLifecycle : ILifecycle
{
public static readonly string ITEM_NAME = "STRUCTUREMAP-INSTANCES";
public void EjectAll()
{
FindCache().DisposeAndClear();
}
public IObjectCache FindCache()
{
if (!OperationContext.Current.OutgoingMessageProperties.ContainsKey(ITEM_NAME))
OperationContext.Current.OutgoingMessageProperties.Add(ITEM_NAME, new MainObjectCache());
return (IObjectCache)OperationContext.Current.OutgoingMessageProperties[ITEM_NAME];
}
public string Scope { get { return "WcfOperationLifecycle"; } }
}
I have the following code:
public static int smsCount = 0 ;
public void startListener()
{
SendListener smsListener;
smsListener = new SendListener() {
public boolean sendMessage(Message message) {
++smsCount;
return true;
}
};
SMS.addSendListener(smsListener);
}
When I use a debugger I see that the value of smsCount is increasing. However, for some reason, it returns zero when I try to access it from outside the class. Is there anything wrong with this code ? sendMessage is called whenever an SMS is sent.
To expand on John B's comment, and to be more specific are you accessing it from a different runtime (application) context? Each runtime context has its own global (and therefore) static namespace. To ensure an object is a global singleton you should use the RuntimeStore.
I'm getting some very unexpected (I think) behavior with the Typed Factory facility. Basically, it's reusing transient component instances for constructor injection with Func<T>.
Here is the gist of it:
// this guy is registered as service EntityFrameworkRepositoryProvider, not IRepository
[Transient]
public class EntityFrameworkRepositoryProvider : IRepository
{
public EntityFrameworkRepositoryProvider(ObjectContext objectContext, Assembly assembly)
{
// HOLY MOLY BATMAN!! Every time I hit this constructor when getProvider gets called,
// I don't actually get the arguments passed into getProvider. I get the
// arguments that were passed into getProvider the very FIRST time
// it was called...in other words I get the wrong
// ObjectContext (for the wrong connection string)...BIG PROBLEM
// do stuff...
}
}
[Singleton]
// this guy gets registered on startup
internal class EntityFrameworkRepositoryProviderFactory : IRepositoryProviderFactory
{
private readonly Func<ObjectContext, Assembly, EntityFrameworkRepositoryProvider> getProvider;
public EntityFrameworkRepositoryProviderFactory(Func<ObjectContext, Assembly, EntityFrameworkRepositoryProvider> getProvider)
{
this.getProvider = getProvider;
// do stuff...
}
public IRepository CreateRepository()
{
var provider = getProvider(new ObjectContext(GetConnectionString()),
Assembly.GetExecutingAssembly);
// do stuff...
}
public string GetConnectionString()
{
// returns one of a few diff EF connection strings
}
}
I also have a standard LazyComponentLoader. What am I doing wrong here? What should I do instead?
Thanks.
Problem was this seemingly harmless code in the LazyComponentLoader:
public IRegistration Load(string key, Type service, IDictionary arguments)
{
var component = Component.For(service);
if (!string.IsNullOrEmtpy(key))
{
component = component.Named(key);
}
if (arguments != null)
{
// This makes the typed factory facility screw up. (Merge is an extension method that merges dictionaries)
component.DynamicParameters((k, d) => d.Merge(arguments));
}
return component;
}
public static void Merge(this IDictionary target, IDictionary source)
{
foreach (object key in source.Keys)
{
target[key] = source[key];
}
}