使用Unity单独根据名称获取对象
Using Unity to get objects based on name alone
我有一个带有处理程序方法的应用程序。 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 class 项目中。所有应用程序都引用此 DLL。
在我的主应用程序中,我安装了 Unity,加载容器的步骤之一如下:
// Scan assemblies for Job definitions...
_container.RegisterTypes(AllClasses.FromAssembliesInBasePath().
Where(type => typeof(IJob).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.Transient);
每个 "Job" 都在其自己的 class 项目中定义,并且 NOT 被主应用程序引用。每个 "Job" 必须 继承自 JobBase
和 IJob
.
主应用公开了一个简单的 REST 服务。你可以 post 像这样:
{ 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();
我收到以下错误:
Exception is: InvalidOperationException - The current type, IJob, is
an interface and cannot be constructed. Are you missing a type
mapping?
我错过了什么?
Each "Job" is defined in its own class project and is NOT referenced
by the main app. Each "Job" must inherit from JobBase and IJob.
你调查过 MEF 吗?它能够通过其元数据查询和加载 class。我倾向于将 Unity 用于已知的编译时依赖项,将 MEF 用于运行时加载的动态程序集。 (没有理由不能在同一项目中同时使用两者。)
我想我们做的事情与您正在寻找的类似。我们根据 class 名称加载工作流程。
只需用 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() { }
}
导出的 class 可以独立于运行它的项目构建。如果将其作为库构建到单独的程序集中,则可以在导入器中加载程序集(或程序集目录)class。
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 位于核心。作业 class 存在于它们自己的库中(或者我想它们也可以存在于主程序中)。
原来有很多方法可以操纵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 payload 找到工作:
var command = new MinimumCommandModel(Request.Content.ReadAsStringAsync().Result);
var job = command.MinimumPayload.JobName.Job();
我有一个带有处理程序方法的应用程序。 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 class 项目中。所有应用程序都引用此 DLL。
在我的主应用程序中,我安装了 Unity,加载容器的步骤之一如下:
// Scan assemblies for Job definitions...
_container.RegisterTypes(AllClasses.FromAssembliesInBasePath().
Where(type => typeof(IJob).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.Transient);
每个 "Job" 都在其自己的 class 项目中定义,并且 NOT 被主应用程序引用。每个 "Job" 必须 继承自 JobBase
和 IJob
.
主应用公开了一个简单的 REST 服务。你可以 post 像这样:
{ 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();
我收到以下错误:
Exception is: InvalidOperationException - The current type, IJob, is an interface and cannot be constructed. Are you missing a type mapping?
我错过了什么?
Each "Job" is defined in its own class project and is NOT referenced by the main app. Each "Job" must inherit from JobBase and IJob.
你调查过 MEF 吗?它能够通过其元数据查询和加载 class。我倾向于将 Unity 用于已知的编译时依赖项,将 MEF 用于运行时加载的动态程序集。 (没有理由不能在同一项目中同时使用两者。)
我想我们做的事情与您正在寻找的类似。我们根据 class 名称加载工作流程。
只需用 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() { }
}
导出的 class 可以独立于运行它的项目构建。如果将其作为库构建到单独的程序集中,则可以在导入器中加载程序集(或程序集目录)class。
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 位于核心。作业 class 存在于它们自己的库中(或者我想它们也可以存在于主程序中)。
原来有很多方法可以操纵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 payload 找到工作:
var command = new MinimumCommandModel(Request.Content.ReadAsStringAsync().Result);
var job = command.MinimumPayload.JobName.Job();