1
\$\begingroup\$

I was refactoring a quite large WPF project and I found some pieces of code where it can leads to error.

Ive got some services in the form

 public sealed class CurrenciesService : ContainerServiceBase<Currency>, ICurrenciesService
 {
 public override Currency GetItem(int id)
 {
 return GetItemInternal(x => x.Id == id);
 }
 public override Task Init()
 {
 return PerformInitInternal(InitCacheMessages.STR_GET_COUNTERPARTS,
 InitCacheMessages.STR_GET_COUNTERPARTS_FAILED,()=> CommonRepository.GetCurrenciesAsync());
 }
 }

where the ContainerServiceBase is something as

 public class ContainerServiceBase<T> : IContainerBase<T> 
 where T : class
{
 #region Variables
 protected readonly IExceptionService ExceptionService = ServiceLocator.Default.ResolveType<IExceptionService>();
 protected readonly ICommonRepository CommonRepository = ServiceLocator.Default.ResolveType<ICommonRepository>();
 public delegate void ItemsChangedHandler(object sender, EventArgs e);
 public event ItemsChangedHandler OnItemsChanged;
 #endregion
 public virtual T GetItem(int id)
 {
 throw new NotImplementedException();
 }
 public virtual Task Init()
 {
 return TaskEx.WhenAll();
 }
 public IList<T> Items { get; protected set; }
 protected async Task PerformInitInternal(string okMessage, string koMessage, Func<Task<IList<T>>> function)
 {
 try
 {
 var result = await function();
 if (result != null)
 {
 Items = result;
 LogTo.Information(okMessage, result.Count);
 OnItemsChanged?.Invoke(this, new EventArgs());
 }
 else
 {
 LogTo.Warning(koMessage);
 }
 }
 catch (Exception ex)
 {
 ExceptionService.HandleException(ex);
 }
 }
 protected T GetItemInternal(Func<T, bool> condition)
 {
 if (Items == null) throw new NullReferenceException("Items has not been initialized");
 var result = Items.FirstOrDefault(condition);
 return result;
 }

Currently during the Application's start I perform for each service this

 var taskPortolio = portfoliosService.Init();
 var taskInstitutes = institutesService.Init();
 var taskStatus = statusService.Init();
 var taskCounterparts = counterpartsService.Init();
 var taskCrosses = crossesService.Init();
 var taskCurrencies = currenciesService.Init();
 var taskSigns = signsService.Init();
 var taskCrossSplit = crossSplitService.Init();
 var taskDateMM = dateMmService.Init();
 var taskSignsFx = signsFxService.Init();
 var taskPortfolioTree = portfolioItemService.Init();
 var taskTags = tagService.Init();
 var taskInstitutesCustomerDesk = institutesCustomerDeskService.Init();
 var taskProvenances = provenanceService.Init();
 var taskRepoClasses = repoClassService.Init();
 var taskDatesMaturity = dateMaturityService.Init();

Those methods are initialized even if they're never used.

I was writing a unit test in the form

 [Test]
 public async Task CurrenciesLoaded()
 {
 var viewmodel = viewModelFactory.CreateViewModel<HistoricalDetailPRTViewModel>(null, null);
 var res = viewmodel.InitializeViewModelAsync();
 await res;
 Assert.NotNull(viewmodel.Currencies);
 Assert.IsTrue(viewmodel.Currencies.Count>0);
 }

and correctly I get null at viewmodel.Currencies since no CurrenciesService.Init has been called.

Can I put a check in the Item.getter to check if it's called the Init and if not call it? is this evil? consider that those init are now called async and I wish not to block the UI while it's loading

P.S. I'm using Catel as MVVM Framework

BCdotWEB
11.4k2 gold badges28 silver badges45 bronze badges
asked Aug 24, 2016 at 7:44
\$\endgroup\$
4
  • \$\begingroup\$ I'm not sure what your question is ? \$\endgroup\$ Commented Aug 24, 2016 at 7:50
  • \$\begingroup\$ I've edit the main question... is this way of initializing safe? \$\endgroup\$ Commented Aug 24, 2016 at 7:58
  • 1
    \$\begingroup\$ That looks better \$\endgroup\$ Commented Aug 24, 2016 at 8:03
  • 1
    \$\begingroup\$ Do the services have a long lasting initialization or why are you doing it like this? I wouldn't complicate things just to make it lazy if the initialization doesn't cost a penny. \$\endgroup\$ Commented Aug 24, 2016 at 18:22

1 Answer 1

3
\$\begingroup\$

From what I can see you are calling an init function on every service so you can get data and cache it at startup.

A better way to do this would be to use the dependency injection layer for example using unity

 builder.RegisterType<CurrenciesService>()
 .As<ICurrenciesService>()
 .AutoActivate()
 .OnActivating(x => x.Instance.Init())
 .SingleInstance();

So this code activates your Currency Service, auto activates it when the container is building, when it gets activated calls init and puts it in single instance. Single instance is needed otherwise the init will be called on every request.

answered Aug 26, 2016 at 12:51
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.