views:

48

answers:

0

Just wondering if anyone has used an actionfilter to make it possible to share the view for a specific type between archived info and current info?

Example:

public class Order
{
    protected  IList<int> _products;
    public Order(IList<int> products)
    {
        _products = products ?? new List<int>();
    }
    public virtual void AddProduct(int productId)
    {
        _products.Add(productId);
    }
    public IEnumerable<int> Products
    {
        foreach(int el in _products)
            yield return el;
    }
}

public class ArchivedOrder : Order
{
    public ArchivedOrder(IList<int> products) : base(products)
    {}

    public override AddProduct(int productId)
    {
        throw new InvalidOperationException("Can't modify archived orders.");
    }
}

public interface IOrderRepository
{
    Order GetCurrent(string userName);
    Order GetArchived(string userName, int orderId);
}

public class OrderFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var rep = IoC.GetInstanceOf(typeof(IOrderRepository); // choose your poison
        string userName = "ShouldGetuserFromLoggedIn"; // or something
        Model.Order.Order o = null;

        if (filterContext.ActionParameters.ContainsKey("orderId"))
            o = rep.GetArchived(userName, (int)filterContext.ActionParameters"orderId"]);
        else
            o = rep.GetCurrent(userName);

        filterContext.ActionParameters.Add("order", o);

        base.OnActionExecuting(filterContext);
    }
}

And then have e.g. a details view as such:

public ActionResult Details(Order order) { return View(order); }

Which would mean a call do /Order/Details/1 would show the details for the archived order while a call to /Order/Details would show information about the current order.

A state pattern (or equivalent) could be used to prevent actions not of the order type (eg adding to archived).

I think this could be a nice way to use a IoC like structure for controllers which should make it a bit easier to test the different methods separately. The other alternative i see is something like having a constructor like:

public class OrderController : Controller
{
    readonly IOrderRepository _orderRep;
    public OrderController(IOrderRepository rep)
    {
        _orderRep = rep;
    }

    public ActionResult Details(int? orderId, string userName)
    {
        Order o = orderId.HasValue ? _orderRep.GetArchived(orderId.Value, userName) : _orderRep.GetCurrent();
        return View(o);
    }
}

Which has different positive things of course (easier to follow, gives full access to the full orderinterface for CRUD if needed and so on). I've also seen the way Rob Connery solved it in the MVC StoreFront (property on controller that holds current order).

All viable ways, but is the ActionFilter feasible or is it a really bad idea for some reason?