我有一个带有处理程序方法的应用程序。 handler方法获取一个json字符串,其中包含需要处理请求的对象的名称和请求的参数。基本上,这样的东西(我会保持简单):
public interface IJob
{
bool Execute();
bool Hydrate(string source);
}
public class JobBase
{
public int Id { get; set; }
public JobType JobType { get; set; }
public CronExpression CronExpression { get; set; }
}
public class JobSubmitClone : JobBase, IJob
{
public string[] Tokens { get; set; }
public bool Hydrate(string source)
{
// code omitted...
return true;
}
public bool Execute()
{
// code omitted...
return true;
}
}
IJob和JobBase都保存在Common类项目中。所有应用程序都引用此DLL。
在我的主应用程序中,我安装了Unity,其中一个加载容器的步骤如下:
// Scan assemblies for Job definitions...
_container.RegisterTypes(AllClasses.FromAssembliesInBasePath().
Where(type => typeof(IJob).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.Transient);
每个“作业”都在其自己的课程项目中定义,主应用程序引用 NOT 。每个“作业”必须继承自JobBase
和IJob
。
主应用程序公开了一个简单的REST服务。您可以发布类似的内容:
{ jobName : JobSubmitClone, Id : 1, JobType : 2, CronExpression : '' }
在主应用程序中,我试图根据JobName
从容器中提取对象。我试过这个(是的,我知道它违反了IoC模式):
var container = UnityHelpers.GetConfiguredContainer();
var job = container.Resolve<IJob>(myParams.jobName); // "JobSubmitClone" //
var hydrated = job.Hydrate(myParams);
if(hydrated)
var result = job.Execute();
我收到以下错误:
异常是:InvalidOperationException - 当前类型IJob是 一个接口,无法构造。你错过了一个类型吗? 映射?
我错过了什么?
答案 0 :(得分:0)
你看过MEF了吗?它能够通过元数据查询和加载类。我倾向于将Unity用于已知的编译时依赖项,并将MEF用于在运行时加载的动态程序集。 (没有理由你不能在同一个项目中同时使用它们。)每个&#34;工作&#34;在其自己的类项目中定义,不被引用 由主应用程序。每个&#34; Job&#34;必须从JobBase和IJob继承。
我认为,我们会做一些类似于您正在寻找的事情。我们根据类名加载工作流。
使用System.ComponentModel.Composition.MetadataAttribute ....装饰作业
[MetadataAttribute]
public class WorkflowMetadataAttribute : Attribute, IWorkflowMetadata
{
public WorkflowMetadataAttribute(string typeName) {
TypeName = typename;
}
public string TypeName { get; private set; }
}
你把它放在想要出口的东西上....
public interface IWorkflow // aka IJob
{
void Execute();
}
[Export(typeof(IWorkflow))]
[WorkflowMetadata("WhateverWorkflow")]
public class WhateverWorkflow : IWorkflow
{
public void Execute() { }
}
导出的类可以与运行它的项目分开构建。如果将其作为库构建到单独的程序集中,则可以在导入程序类中加载程序集(或程序集目录)。
public class WorkflowCatalog : IPartImportsSatisfiedNotification
{
[ImportMany]
public IEnumerable<Lazy<IWorkflow, IWorkflowMetadata>> Workflows { get; private set; }
public void Compose() {
var path = Path.GetDirectoryName( Assembly.GetExecutingAssembly().Location );
var catalog = new DirectoryCatalog( path );
var compositionContainer = new CompositionContainer( catalog );
compositionContainer.ComposeParts(this);
}
public void OnImportsSatisfied() {
var workflow = Workflows.Single(w => w.Metadata.TypeName == "WhateverWorkflow").Value;
workflow.Execute();
}
}
IJob,IJobMetadata和JobBase生活在核心。工作班住在他们自己的图书馆(或者他们也可以住在主程序中)。
答案 1 :(得分:0)
事实证明,有很多方法可以操纵Unity。到目前为止,这就是最终的工作:
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().Where(type => typeof(IJob).IsAssignableFrom(type) && type.IsClass),
WithMappings.FromAllInterfaces,
t => t.IsNested ? t.DeclaringType.Name + "." + t.Name : t.Name,
WithLifetime.Transient);
我还构建了一个扩展方法:
public static IJob Job(this string src)
{
var container = UnityConfig.GetConfiguredContainer();
var job = container.Resolve<IJob>(src);
return job;
}
我为最小有效负载创建了一个小模型:
public class MinimumCommandModel : IRequest<MinimumResultModel>
{
public MinimumCommandModel(string json)
{
FullPayloadString = json;
MinimumPayload = JsonConvert.DeserializeObject<MinimumPayload>(json);
}
public string MinimumPayloadString => JsonConvert.SerializeObject(MinimumPayload);
public string FullPayloadString { get; set; }
public MinimumPayload MinimumPayload { get; set; }
}
然后我可以直接从(JSON)sting有效负载中获取作业:
var command = new MinimumCommandModel(Request.Content.ReadAsStringAsync().Result);
var job = command.MinimumPayload.JobName.Job();