tzortzik
tzortzik

Reputation: 5153

ASP.NET MVC 5 Common actions for more controllers

I have some controllers (and will be more) which share some actions like those:

public ActionResult DeleteConfirmed(int id)
{
    Supplier s = db.Suppliers.Find(id);
    s.Deleted = true;
    db.SaveChanges();
    return RedirectToAction("Index");
}

public ActionResult RestoreConfirmed(int id)
{
    Supplier s = db.Suppliers.Find(id);
    s.Deleted = false;
    db.SaveChanges();
    return RedirectToAction("Index");
}

Those action are part of SuppliersController. What this does is that when I delete or restore an object, it marks the object in the database as true for deleted field (and false when it is restored).

The same behavior is shared by many other controllers like CurrenciesController, ProductsController, etc...

In the code I showed you should see that my database entity is clearly specified (Supplier) and also the repository (Suppliers).

I want to find a way to this in a generic way. I want to create a custom controller and all other controllers that shares the same behavior will extended it. In this case ProductsController will extend my DeleteRestoreController.

How can I do this in a "generic" way?

db is a DbContext

public partial class LE: DbContext
{
public LE()
    : base("name=LE")
{
}

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    throw new UnintentionalCodeFirstException();
}

public virtual DbSet<Category> Categories { get; set; }
public virtual DbSet<CategoryText> CategoryTexts { get; set; }
...
}

Categories also share the same behavior.

Upvotes: 0

Views: 1225

Answers (2)

matt_lethargic
matt_lethargic

Reputation: 2796

To go one step further

public abstract class DeleteRestoreController<T> : Controller
{

public virtual Action DeleteConfirmed(int id)
{
    var dbset = db.Set<T>();

    var s = dbset.Find(id);
    s.Deleted = true;
    db.SaveChanges();
    return RedirectToAction("Index");
}
}

then when defining your controller add the entity type

public class ProductsController : DeleteRestoreController<Supplier>
{
////blah
}

Upvotes: 2

Marco
Marco

Reputation: 23945

You can implement your DeleteRestoreController as an abstract class.

public abstract class DeleteRestoreController : Controller
{
    private IRepository : Repository;
    public DeleteRestoreController() { ... }
    public DeleteRestoreController(IRepository Repository) { ... }

    public virtual Action DeleteConfirmed(int id)
    {
        Supplier s = db.Suppliers.Find(id);
        s.Deleted = true;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
}

If you need to differ from that behaviour in your ProductsController you can simply override that method.

public class ProductsController : DeleteRestoreController
{
    public override void DeleteConfirmed()
    {
        //override the logic
    }
}

You could always go one step further and implement a generic repository as well, but I've never gone beyond 6-8 controllers in my applications and didn't create one once.

EDIT I've just read in the comments, that the entities would change from Suppliers in the controllers, so implementing a base controller wouldn't make much sense, if you do not implement a generic interface as well. Robert Harvey has made a great point in stating the complexity has to go somewhere.

Upvotes: 1

Related Questions