在策略设计模式

时间:2018-03-27 13:24:07

标签: c# asp.net-mvc strategy-pattern hangfire

我有以下申请:

1) Mvc app :Hangfire客户端,我将在那里将作业和主机排入队列              仪表板。这个应用程序将包含我的类库的参考。

2)控制台应用:Hangfire服务器将存在于此控制台应用程序中。

3)类库:hangfire服务器(控制台应用)和hangfire客户端(asp.net mvc)之间的共享库,我的长时间运行的代码将驻留在那里.Hangfire服务器                    将执行该库的代码。

我在strategy design pattern.

之后的类库中有如下结构

以下代码:Reference:

接口

public interface IOperation
{
    Output Process(Input input);
    bool AppliesTo(Type type);
}

public interface IOperationStrategy
{
    Output Process(Type type,Input input);
}

运营:

public class Add : IOperation
{
    public bool AppliesTo(Type type)
        {
            return typeof(Add).Equals(type);
        }

    public Output Process(Input input)
    {
        // Implementation
        return new Output();
    }
}

public class Multiply : IOperation
{
     public bool AppliesTo(Type type)
        {
            return typeof(Multiply).Equals(type);
        }

    public Output Process(Input input)
    {
        // Implementation
        return new Output();
    }
}

策略

public class OperationStrategy : IOperationStrategy
{
    private readonly IOperation[] operations;

    public OperationStrategy(params IOperation[] operations)
    {
        if (operations == null)
            throw new ArgumentNullException(nameof(operations));
        this.operations = operations;
    }

    public Output Process(Type type, Input input)
    {
        var op = operations.FirstOrDefault(o => o.AppliesTo(type));
        if (op == null)
            throw new InvalidOperationException($"{operation} not registered.");

        return op.Process(input);
    }
}

用法

// Do this with your DI container in your composition 
// root, and the instance would be created by injecting 
// it somewhere.
var strategy = new OperationStrategy(
    new Add(), // Inject any dependencies for operation here
    new Multiply()); // Inject any dependencies for operation here

// And then once it is injected, you would simply do this.
var input = new Input { Value1 = 2, Value2 = 3 };
BackgroundJob.Enqueue(() => strategy.Process(typeof(Add), input));

但是hangfire服务器无法选择工作,当我检查state table时,我会看到如下错误:

  

“FailedAt”:“2018-03-21T13:14:46.0​​172303Z”,“ExceptionType”:   “System.MissingMethodException”,“ExceptionMessage”:“没有无参数   为此对象定义的构造函数。“,”ExceptionDetails“:   “System.MissingMethodException:未定义无参数构造函数   对于这个对象。\ r \ n at   System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,布尔值   publicOnly,Boolean noCheck,Boolean& canBeCached,   RuntimeMethodHandleInternal&安培; ctor,布尔& bNeedSecurityCheck)\ r \ n at   System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean   skipCheckThis,Boolean fillCache,StackCrawlMark& stackMark)\ r \ n at   System.Activator.CreateInstance(Type type,Boolean nonPublic)\ r \ n at   System.Activator.CreateInstance(Type type)\ r \ n at   Hangfire.JobActivator.SimpleJobActivatorScope.Resolve(Type type)\ r \ n   在Hangfire.Server.CoreBackgroundJobPerformer.Perform(PerformContext   上下文)\ r \ n at   Hangfire.Server.BackgroundJobPerformer<> c__DisplayClass8_0.b__0(个)\ r \ n   在   Hangfire.Server.BackgroundJobPerformer.InvokePerformFilter(IServerFilter   filter,PerformingContext preContext,Func 1 continuation)\ r \ n at   Hangfire.Server.BackgroundJobPerformer.PerformJobWithFilters(PerformContext   上下文,IEnumerable`1过滤器)\ r \ n at   Hangfire.Server.BackgroundJobPerformer.Perform(PerformContext   上下文)\ r \ n at   Hangfire.Server.Worker.PerformJob(BackgroundProcessContext context,   IStorageConnection连接,String jobId)“

我没有得到应该为这个结构设置的hangfire,因为我没有涉及任何IOC容器。

有人可以帮帮我吗?

演示项目:https://www.dropbox.com/s/bfjr58y6azgmm3w/HFDemo.zip?dl=0

1 个答案:

答案 0 :(得分:1)

答案就在那里

No parameterless constructor defined for this object.

您的OperationStrategy没有无参数构造函数,因此当Hangfire尝试创建此对象时,它无法通过反射来实现。 Hangfire无权访问您在计划作业时使用的实例,它会尝试重新创建它。它无法做到。

您可以添加无参数构造函数,并将Operations设为公共集合。

这将使您能够像现在一样使用ctor,但也允许对象被序列化,由Hangfire存储,然后反序列化并在尝试运行时创建。

public class OperationStrategy : IOperationStrategy
{
    // paramaterless ctor
    public OperationStrategy()
    {
        Operations = new List<Operation>(); 
    }

    public OperationStrategy(params IOperation[] operations)
    {
        if (operations == null)
            throw new ArgumentNullException(nameof(operations));

        Operations = operations;
    }

    public Output Process(Type type, Input input)
    {
        var op = Operations.FirstOrDefault(o => o.AppliesTo(type));

        if (op == null)
            throw new InvalidOperationException($"{operation} not registered.");

        return op.Process(input);
    }

    //property - this can be deserialized by Hangfire
    public List<IOperation> Operations {get; set;}
}