简体   繁体   中英

Abstracting a large number of similar ASP.NET MVC Actions (C#)

A new MVC 5 app that I'm working on references a large-ish collection (4 assemblies, about 500 classes each) of data models generated from a 4GL environment. The basic interaction has the MVC app present and populate a model instance, then (after model validation), hand the model instance off to a provider for processing.

The initial approach I've used is, for each model, create

  • a scaffolded razor view bound to the model,
  • a partial controller class with a pair of actions (GET/POST) the model

All of the actions are part of the same controller class which has a couple of private methods to implement the GET & POST actions exposed in each of the partials.

So, the structure is like:

|
|--\Controllers
       |
       |--MyController.cs
       |--MyController.MDL001.cs
       |--MyController.MDL002.cs
       |-- ...
       |--MyController.MDL500.cs

|--\Views
       |
       |--\My
            |--\MDL001.cshtml
            |--\MDL002.cshtml
            |-- ...
            |--\MDL500.cshtml

And the implementation of each partial controller follows the pattern:

public partial class MyController
{
    public ActionResult ProcessMDL001(MDL001Model modelInstance)
    {
        return ProcessModel(modelInstance);
    }

    public ActionResult MDL001()
    {
        return ShowModel("MDL001");
    }
}

Where methods ProcessModel(...) and ShowModel(...) are defined in MyController.cs

I want to keep MVC's model binding and validation functioning but also am keen on avoiding a few thousand nearly-identical concrete action implementations. Is there some pattern/approach using routing, generics, dynamics, etc. that can help here?

Assuming that you can roughly treat each class the same, you can handle this with generics:

public class BaseController<T> : Controller
    where T : class, new
{
    public ActionResult Process(T modelInstance)
    {
        return ProcessModel(modelInstance);
    }

   ...
}

But, you would need to use subclasses instead of partial classes. Essentially, you're just going to implement the action once, and then subclass this base controller to specify the type for the controller instance you're working with:

public MDL001ModelController : BaseController<MDL001Model>
{
}

If no additional type-specific actions are needed, then that code alone is all you subclass would need to be. However, you can always add additional actions that will only apply to this particular controller instance.

If there are pieces of the common actions that you need to customize slightly, such as validation logic or something, you can provide hooks in your actions. Something along the lines of:

public class BaseController<T> : Controller
    where T : class, new
{
    public ActionResult ActionWithHook(T model)
    {
        DoSomeWork(model);
        return View();
    }

    // By default this does nothing, but can be overridden to do something
    internal virtual void DoSomeWork(T model)
    {
    }
}

Then:

public MDL001ModelController : BaseController<MDL001Model>
{
    internal override void DoSomeWork(MDL001Model model)
    {
        // Do something
    } 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM