我已经在 .net 4.5 中开发了一个 Web 应用程序,现在客户要求我为某些应用程序模块定制(例如发票的不同实现)。我的问题是我可以“拦截”我的客户以加载定制组件并为普通客户加载不同的组件吗?
我可以简单地通过反思来做到这一点吗?
我已经在 .net 4.5 中开发了一个 Web 应用程序,现在客户要求我为某些应用程序模块定制(例如发票的不同实现)。我的问题是我可以“拦截”我的客户以加载定制组件并为普通客户加载不同的组件吗?
我可以简单地通过反思来做到这一点吗?
关键思想是设计软件,使其部件易于更换。您应该将您的解决方案分成多个项目,以便您可以快速交换接口的不同实现。
此外,还有一种叫做依赖注入的东西,这基本上意味着您可以根据需要在运行时或使用配置文件注入不同的实现。为了便于使用,已经为您准备了一些不错的框架,例如 Ninject 或 Unity。
应用程序需要有一个坚实的架构来支持这种可能性。也许如果您提供了有关您的系统的更多信息,我可能会更具体,但我相信对依赖注入进行一些研究会给您一个良好的开端。
是的你可以。您可以像这样从文件中加载程序集,
var asmbly = System.Reflection.Assembly.LoadFrom(path);
然后使用反射来加载类型。
有几种方法可以实现这种可插拔性。一种方法是提取“模块”的接口并针对该接口对“模块客户端”进行编码,将具体实现与“客户端”代码解耦。然后,在运行时查看组件内部,加载实现所述接口的类型并注入“模块客户端”。
我在这里粘贴一些我编写的代码作为概念证明,用于精确地那种类型的“模块”运行时加载(这是 MVC 3):
// "Module User" was decoupled from "module", by coding it against module's interface:
public class CustomerController : Controller
{
private ICustomerRepository _customerRepository;
// dependency injection constructor
public CustomerController(
...
ICustomerRepository customerRepository,
...)
{
_customerRepository = customerRepository;
}
public ActionResult Details(Nullable<Guid> id)
{
Customer c = _customerRepository.GetByKey(id.Value.ToString());
...
}
...
}
在运行时:
// I first load the assembly
System.Reflection.Assembly dal = System.Reflection.Assembly.LoadFrom(System.IO.Path.Combine(pBinPath, pDALAssemblyName));
// I then look for types implementing ICustomerRepository
var addressRepositoryContract = typeof(QSysCamperCore.Domain.IAddressRepository);
var addressRepositoryImplementation = dal.GetTypes()
.First(p => addressRepositoryContract.IsAssignableFrom(p));
...
请注意,这种类型的编程需要更多的权限——我已经对这段代码“生疏”了几年,但我记得信任级别的问题,当然,必须考虑文件系统访问。
有一些框架可以帮助这种应用风格。这又是几年前的事了,但微软的模式和实践网站上曾经有所谓的“复合应用程序块”,它是两个框架的基础——Smart Cliet Softweare Factory 及其网络等价物——Web Client Software Factory。它们站起来有点重,但为这种模块化(复合)应用程序提供了强大的骨架。