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

\$\endgroup\$
  • \$\begingroup\$ I'm not sure what your question is ? \$\endgroup\$ – Siobhan Aug 24 '16 at 7:50
  • \$\begingroup\$ I've edit the main question... is this way of initializing safe? \$\endgroup\$ – advapi Aug 24 '16 at 7:58
  • 1
    \$\begingroup\$ That looks better \$\endgroup\$ – Siobhan Aug 24 '16 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\$ – t3chb0t Aug 24 '16 at 18:22
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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.