Paul Hinett Paul Hinett - 1 year ago 39
C# Question

NHibernate + ASP.Net MVC + User Activity Feed

I am looking for the most appropriate way of dealing with a user activity feed on my social networking site. At the moment i have several activities which can appear on the news feed such as:

  • Users joins the site

  • User comments on a post

  • User adds a post to their favorites

  • User adds a new post to the site

Here is a simplified version of my domain objects at the moment:

public abstract class NewsItem : Entity, ITenantSpecific

public virtual Account Account { get; set; }
public virtual DateTime DateTime { get; set; }

// returns formatted news html string which gets
// overridden by inherted classes
public abstract string GetNewsHtml();

public class NewsItemJoiner : NewsItem
public virtual Account AccountJoined { get; set; }

public override string GetNewsHtml()
return "XXX has just joined our music network";

As you can see at the moment I have a property which must be overridden on each activity called
. This isn't ideal as I don't believe my domain should be responsible for generating my HTML.

I have thought about using a partial view for each activity type and pass into it the
base class downcasted into the correct type.

However I am open to suggestions.

Answer Source

I have a similar issue but with different order types. I decided to define rendering at the view layer (web/controllers), not domain. You can do it this way:

public interface IRenderer<T> where T: NewsItem 
   string Render(T item);

public class NewsItemJoinerRenderer: IRenderer<NewsItemJoiner>
   public string Render(T item)
       return "XXX has just joined our music network";

public class NewsRendererFactory
   public IRenderer<T> GetRenderer<T>()
        return ServiceLocator.GetInstance<IRenderer<T>>();

Then you can pass NewsRendererFactory to controller. Perhaps there's a way to avoid ServiceLocator but for now I cannot tell.

Notice that this makes your architecture both configurable and pluggable if needed.

You can define additional render-related interfaces, add more properties to the IRenderer - for example, PartialName, etc, or have lambda filters on IRenderer that Factory uses to decide if this interface implementation is applicable for the passed (to GetRenderer("some-condition")) condition. A lot of things are possible.

If you don't want IoC containers (ServiceLocator), you can have its job done with simple switch() statement inside NewsRendererFactory.GetRenderer. This will isolate the logic inside single factory method, and you'll be able to replace it easily with true IoC once you are ready.

Update: how to get renderers.

If you don't use IoC, you do something like

 typeof(IRenderer<>).Assembly.GetTypes().Where(x =>
        x.IsGenericType &&
        x.GetGenericTypeDefinition() == typeof(IRenderer<>) &&
        x.GetGenericArguments().FirstOrDefault() == requestedTypeArguments)

Then you can select SingleOrDefault() or ToList() if you can handle multiple renderers.