Ответ 1
Я бы подумал об использовании своего рода архитектуры plugin
, так как это ваш общий дизайн для самого приложения.
Вы можете выполнить основы этого, выполнив что-то вроде следующего (обратите внимание, что в этом примере используется StructureMap
- вот ссылка на StructureMap Documentation):
-
Создайте интерфейс, из которого могут быть получены ваши объекты
DbContext
.public interface IPluginContext { IDictionary<String, DbSet> DataSets { get; } }
-
В настройке Injection Dependency (используя StructureMap) - сделайте следующее:
Scan(s => { s.AssembliesFromApplicationBaseDirectory(); s.AddAllTypesOf<IPluginContext>(); s.WithDefaultConventions(); }); For<IEnumerable<IPluginContext>>().Use(x => x.GetAllInstances<IPluginContext>() );
-
Для каждого из ваших плагинов либо измените файл
{plugin}.Context.tt
, либо добавьте файлpartial class
, который вызывает генерированиеDbContext
дляIPluginContext
.public partial class FooContext : IPluginContext { }
-
Измените файл
{plugin}.Context.tt
для каждого плагина, чтобы выставить что-то вроде:public IDictionary<String, DbSet> DataSets { get { // Here is where you would have the .tt file output a reference // to each property, keyed on its property name as the Key - // in the form of an IDictionary. } }
-
Теперь вы можете сделать что-то вроде следующего:
// This could be inside a service class, your main Data Context, or wherever // else it becomes convenient to call. public DbSet DataSet(String name) { var plugins = ObjectFactory.GetInstance<IEnumerable<IPluginContext>>(); var dataSet = plugins.FirstOrDefault(p => p.DataSets.Any(ds => ds.Key.Equals(name)) ); return dataSet; }
Простите меня, если синтаксис не идеален - я делаю это в сообщении, а не в компиляторе.
Конечный результат дает вам возможность сделать что-то вроде:
// Inside an MVC controller...
public JsonResult GetPluginByTypeName(String typeName) {
var dataSet = container.DataSet(typeName);
if (dataSet != null) {
return Json(dataSet.Select());
} else {
return Json("Unable to locate that object type.");
}
}
Очевидно, что в долгосрочной перспективе вы хотите, чтобы элемент управления был инвертирован, где плагин - это тот, который фактически привязан к архитектуре, а не сервер, ожидающий тип. Тем не менее, вы можете выполнять те же самые вещи, используя этот тип ленивой загрузки, - где основное приложение предоставляет конечную точку, к которой привязаны все плагины.
Это будет что-то вроде:
public interface IPlugin : IDisposable {
void EnsureDatabase();
void Initialize();
}
Теперь вы можете разоблачить этот интерфейс для любых разработчиков приложений, которые собираются создавать плагины для вашей архитектуры (стиль DNN) - и ваша конфигурация StructureMap
работает примерно так:
Scan(s => {
s.AssembliesFromApplicationBaseDirectory(); // Upload all plugin DLLs here
// NOTE: Remember that this gives people access to your system!!!
// Given what you are developing, though, I am assuming you
// already get that.
s.AddAllTypesOf<IPlugin>();
s.WithDefaultConventions();
});
For<IEnumerable<IPlugin>>().Use(x => x.GetAllInstances<IPlugin>());
Теперь, когда вы инициализируете свое приложение, вы можете сделать что-то вроде:
// Global.asax
public static IEnumerable<IPlugin> plugins =
ObjectFactory.GetInstance<IEnumerable<IPlugin>>();
public void Application_Start() {
foreach(IPlugin plugin in plugins) {
plugin.EnsureDatabase();
plugin.Initialize();
}
}
Каждый из ваших объектов IPlugin
теперь может содержать свой собственный контекст базы данных, управлять процессом установки (при необходимости) собственного экземпляра базы данных/таблиц и изящно распоряжаться собой.
Ясно, что это не полное решение, но я надеюсь, что он начнет вас в полезном направлении.:) Если я могу помочь прояснить что-либо здесь, сообщите мне.