ASP.NET MVC条件ViewModel抽象

时间:2013-07-19 15:04:34

标签: asp.net .net asp.net-mvc view abstraction

我是ASP.NET MVC的新手,我坚持一点。我正在写一个分类网站。我的情况是,我有很多类别,用户可以在其中发布广告,每个广告类别都有不同的视图。我创建了一个像

这样的Controller Action
 public ActionResult PostAd(string CategoryName, string SubCategoryName)
 {
        if(categoryName == "Vehicle" && SubCategoryName == "Cars")
        {
             var model = new CarAdViewModel();

             // set CarAdViewModel properties...

             return View("CarAdCreateView", model);
        }
        else if(categoryName == "Vehicle" && SubCategoryName == "Bikes")
        {
            var model = new BikeAdViewModel();

             // set BikeAdViewModel properties...

             return View("BikeAdViewModel", model);
        }
        else if(categoryName == "Property" && SubCategoryName == "RentHouse")
        {
             var model = new RentHouseAdViewModel();

             // set RentHouseAdViewModel properties...

             return View("RentHouseAdViewModel", model);                 
        }
        else................... so on and so on
 }

我的问题是我有大量的类别和子类别差不多60多个。如果我继续对60多个类别和子类别进行编码,我的PostAd方法将会爆炸并变得无法管理。

请告诉我一些可以解决这个问题的最佳实践或模式。

4 个答案:

答案 0 :(得分:3)

不幸的是,你正在做的一些事情是无法避免的。需要根据类别进行某种形式的模型和视图选择。

使用工厂模式。创建基类:

public abstract class BaseCategory
{
  public abstract string GetViewName();
  public abstract Object CreateModelFromFormData();
}

对于每个类别,创建一个派生自BaseCategory的子类并实现抽象函数。

在您的操作中,请执行以下操作:

public ActionResult PostAd(string categoryName, string subCategoryName)
{
  BaseFactory factory;
  if (categoryName == "Vehicle")
  {
    if (subCategoryName == "Cars")
    {
      factory = new CarsFactory();
    }
    else ...
  }
  else ...

  return View(factory.GetViewName(), factory.CreateModelFromFormData());
}

我有这个架构的几个原因:

  1. 我故意使用if/else进行工厂选择。将为每个动作调用创建并重新创建控制器。因此,预先填充列表将不断地和不必要地为不会被选择的类别创建对象。一个简单的if/else会更有效率。如果您想阻止if/else,您可以将工厂放在Dictionary中并根据类别进行选择,但这将是许多不必要的构造函数。

  2. 我将CreateModelFromFormData作为一个函数,因为我假设您需要从发布的表单数据中复制数据。这可能需要传入数据,但我将函数保持无参数。

  3. 我使用了基类/派生类,因为表单数据的复制可能需要从正在创建的模型和发布的表单数据中进行自定义。此外,保存到持久存储(文件或数据库)也可能是特定于类别的。

答案 1 :(得分:1)

这将是一些可能的解决方案之一

public class PostAdData
{
    public string CategoryName;
    public string SubCategoryName;
    public string ViewName;
    public Type Model;
}

public class PostController : Controller
{
    private readonly List<PostAdData> _theData;

    public HomeController()
    {
        _theData = InitializeData();
    }


    public ActionResult PostAd(string categoryName, string subCategoryName)
    {
        var data = _theData.FirstOrDefault(c => c.CategoryName == categoryName && c.SubCategoryName == subCategoryName);
        if (data != null)
        {
            var model = Activator.CreateInstance(data.Model);
            return View(data.ViewName, model);
        }
        return View("Error");
    }

    [NonAction]
    public List<PostAdData> InitializeData()
    {
        var result = new List<PostAdData>
                         {
                             new PostAdData
                                 {
                                     CategoryName = "Vehicle",
                                     SubCategoryName = "Cars",
                                     ViewName = "CarAdCreateView",
                                     Model = typeof (CarAdViewModel)
                                 }
                         };
        return result;
    }
}

答案 2 :(得分:1)

您应该启用此数据。您创建一个具有类别和子类别的复合主键的查找表。然后它有一个带有View的表格。然后,您只需为每个类别/子类别/视图组合添加行。

如果您绝对不想要数据库,那么您可以使用简单的哈希集或字典。

var views = new Dictionary<Tuple<string,string>,string>();

views.Add(new Tuple<string,string>("Vehicle", "Cars"), "CarAdCreateView");

然后在您的PostAd中,您只需查找正确的视图。

答案 3 :(得分:1)

www.asp.net上我的问题是多么美妙的解决方案,这里是链接:http://forums.asp.net/t/1923868.aspx/1?ASP+NET+MVC+Conditional+ViewModel+Abstraction

编辑:

我的代码是:

public class AdsController : Controller
{
     private readonly IAdService _adService;
     public AdsController(IAdService adService)
     {
         _adService = adService;
     }

     public ActionResult PostAd(string Category, string SubCategory)
    {
        //Here I will call
        var strategy = GetStrategy(CategoryName, SubCategoryName);
        strategy.FillModel(_adService );
        return View(strategy.ViewName, strategy.Model);
    }
}