0

来自http://code.google.com/p/autofac/wiki/MultitenantIntegration上的文档

由于这相对复杂,最好将业务逻辑隔离为传递到控制器的外部依赖项,以便租户可以提供覆盖依赖项而不是覆盖控制器。

假设我有一个包含许多操作的默认控制器,Index 操作获取产品、库存和商店的完整数据列表。我的 TenantB 想要具有许多操作的相同控制器,但对于 Index 操作,它还希望获得销售列表。

在我看来,我可能不需要为这么小的变化覆盖整个控制器。这就是上面引用的句子所指的吗?我可以将一些外部方法注入到索引中,对于默认租户来说,这将是一个返回产品、库存和商店的方法,而 TenantB 将覆盖也返回销售额的该方法?

如果我的假设是正确的,是否有人知道某处的一些示例代码可以说明这种类型的实现?

4

1 回答 1

1

这句话背后的想法是您将 Index 操作中的逻辑隔离到一个单独的依赖项中。

也就是说,现在你可能有一个类似这样的控制器:

public class MyController : Controller
{
  protected IDataService _dataService;
  public MyController(IDataService dataService)
  {
    this._dataService = dataService;
  }
  public virtual ActionResult Index()
  {
    var data = this._dataService.GetData();
    var model = new IndexModel()
    {
      Data = data
    };
    return this.View(model);
  }
  public virtual ActionResult OtherAction()
  {
    // other stuff...
  }
}

在那个 Index 操作中,您正在获取数据,并且可能在将数据传递给视图之前对数据执行一些业务逻辑。

使用这样的设计,您的租户特定需要获取一些额外的数据意味着您必须覆盖控制器。这实际上并不太难,如果您决定为其他服务依赖项进行属性注入,它应该可以工作。

public class TenantSpecificController : MyController
{
  // If you set up PropertiesAutowired on the tenant controller
  // registration, you'll get this property populated.
  public IOtherService OtherService { get; set; }
  public TenantSpecificController(IDataService dataService)
    : base(dataService)
  {
  }
  public override ActionResult Index()
  {
    var data = this._dataService.GetData();
    var otherData = this.OtherService.GetData();
    var model = new IndexModel()
    {
      Data = data
    };
    // You can't really change the model without changing the
    // view, so extended data goes in the ViewData or ViewBag
    this.ViewData["other"] = otherData;
    return this.View(model);
  }
}

但是文档中的那句话暗示的是,如果您知道您将在该控制器中拥有一些花哨的租户覆盖逻辑(不仅仅是一次性的,因为控制器覆盖在一次性场景中很容易) 然后将逻辑拉出控制器,如下所示:

public class MyController : Controller
{
  protected IIndexModelGeneratorService _modelService;
  public MyController(IIndexModelGeneratorService modelService)
  {
    this._modelService = modelService;
  }
  public virtual ActionResult Index()
  {
    var model = this._modelService.BuildModel();
    return this.View(model);
  }
  public virtual ActionResult OtherAction()
  {
    // other stuff...
  }
}

然后,您不是在控制器/操作级别进行租户覆盖,而是在特定服务上进行租户覆盖。您正在将业务逻辑从控制器中拉出到其他依赖项中。

显然,这可能意味着改变模型以允许更多可扩展的数据......

public class IndexModel
{
  public DataObject Data { get; set; }
  public Dictionary<string, object> ExtendedData { get; set; }
}

...或者也许您的数据服务实现需要一个字典来填充:

public interface IIndexModelGenerator
{
  IndexModel BuildModel(ViewDataDictionary dict);
}

...所以当你调用它时,你的控制器会传入 ViewData 字典来捕获额外的数据:

var model = this._modelService.BuildModel(this.ViewData);

这个想法仍然成立——如果你有很多这样的东西,将业务逻辑分解成多租户组件可能比每个租户拥有不同的控制器更容易。

于 2012-12-06T16:30:50.830 回答