Your browser may have trouble rendering this page. See supported browsers for more information.

3 Replies

#1 − Nice article but …

Marc (updated by Marc)

… what about replacing the aspect implementation with another one? DI came in my mind when reading this article. What about using a IoC container for construction? Maybe with constructor injection?

Cheers, Marc

#2 − IOC Overkill?

marco

I suppose you could do that as well, although we currently don’t have the IOC involved in creating metadata. Almost everything is a helper method to make it easier and quicker to create metadata—if you don’t like the way the helper method works, then just write your own helper method. We’ve been slowly but surely getting rid of larger extension/helper methods, so passing in an IOC so that it can create the aspect seems kind of like overkill.

You can either just write your own extension method, like so:

public static ClassCacheAspect SetSuperCacheAspectValues(
  this IMetaClass metaClass,
  Action<ClassCacheAspect> setValues)
{
  return metaClass.UpdateAspect<IClassCacheAspect, ClassCacheAspect>(
    new SuperClassCacheAspect(),
    setValues
  );
}

We can call this as follows:

Elements.Classes.Person.SetSuperCacheAspectValues(a => a.Capacity = 1000);

If I go the IOC route, then I would make the base helper method accept another parameter (I guess?). This is kind of neat, and would let me push the machinery for creating a new aspect down to the next-level methods.

The method that works with aspects that implement ICopyTarget looks like this:

public static TConcrete SetAspectValues<TService, TConcrete>(
  this IMetaClass metaClass,
  IServiceRequestHandler handler,
  Action<TConcrete> setValues
)
  where TConcrete : TService, ICopyTarget<TService>
  where TService : IMetaAspect
{
  return metaClass.UpdateAspect<TService, TConcrete>(
    handler,
    (aspect, existingAspect) => aspect.CopyFrom(existingAspect),
    setValues
  );
}

The fully generalized one that has no expectations of the aspect actually creates the aspect using the IOC.

public static TConcrete SetAspectValues<TService, TConcrete>(
  this IMetaClass metaClass,
  IServiceRequestHandler handler,
  Action<TConcrete, TService> copyValues,
  Action<TConcrete> setValues
)
  where TConcrete : TService
  where TService : IMetaAspect
{
  var aspect = handler.GetInstance<TConcrete>();
  var existingAspect = metaClass.Aspects.FirstOfTypeOrDefault<TService>();
  if (existingAspect != null)
  {
    copyValues(aspect, existingAspect);
  }

  setValues(aspect);

  return aspect;
}

And, finally, the caching-specific method looks like this:

public static ClassCacheAspect SetCacheAspectValues(
  this IMetaClass metaClass,
  IServiceRequestHandler handler,
  Action<ClassCacheAspect> setValues)
{
  return metaClass.UpdateAspect<IClassCacheAspect, ClassCacheAspect>(
    handler,
    setValues
  );
}

Now I don’t have to ever call new for an aspect, but I have to pass in the handler, every single time.

Elements.Classes.Person.SetSuperCacheAspectValues(handler, a => a.Capacity = 1000);

I would have to make sure that the handler (IOC) was available during metadata construction (which it generally isn’t, but could be, via constructor injection on the metadata builder class, e.g.)

I think this is a matter of preference, but given how small the chance is that I would want a different cache aspect to be created—and how easy it is to make my own helper method—then I would opt not to use the IOC, just so I don’t force all callers to (A) have a reference to an IOC around and (B) have an extra parameter that isn’t needed in 99.9% of the cases.

Although, since these are helper methods, there’s nothing stopping anyone from creating the methods I outlined above and using that pattern instead. Perfectly valid to use the IOC there, but a bit uglier to get it down to where it can be used.