Keith Barrows Keith Barrows - 2 months ago 12
C# Question

Using Unity to get objects based on name alone

I have an app with a handler method. The handler method gets a json string which includes the name of the object that needs to handle the request and the parameters for the request. Basically, something (I'll keep it simple) like this:

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 and JobBase are both kept in a Common class project. All apps reference this DLL.

In my main app I have Unity installed and one of the steps in loading the container is accomplished like:

// Scan assemblies for Job definitions...
_container.RegisterTypes(AllClasses.FromAssembliesInBasePath().
Where(type => typeof(IJob).IsAssignableFrom(type)),
WithMappings.FromAllInterfaces,
WithName.TypeName,
WithLifetime.Transient);


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
.

The main app has a simple REST service exposed. You can post something like:

{ jobName : JobSubmitClone, Id : 1, JobType : 2, CronExpression : '' }


In the main app I am trying to pull the object from the container based on
JobName
. I've tried this (yes, I know it violates the IoC pattern):

var container = UnityHelpers.GetConfiguredContainer();
var job = container.Resolve<IJob>(myParams.jobName); // "JobSubmitClone" //
var hydrated = job.Hydrate(myParams);
if(hydrated)
var result = job.Execute();


I am getting the following error:


Exception is: InvalidOperationException - The current type, IJob, is
an interface and cannot be constructed. Are you missing a type
mapping?


What am I missing?

Answer

Turns out that there are a lot of ways to manipulate Unity. This is what ended up working so far:

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);

I also built an extension method:

public static IJob Job(this string src)
{
    var container = UnityConfig.GetConfiguredContainer();
    var job = container.Resolve<IJob>(src);
    return job;
}

I created a small model for the Minimum Payload:

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; }
}

I can then directly get a job from a (JSON) sting payload:

var command = new MinimumCommandModel(Request.Content.ReadAsStringAsync().Result);
var job = command.MinimumPayload.JobName.Job();