使用多个 Class 对自定义格式化程序进行依赖注入

Dependency Injection to Custom Formatter with Multiple Class

我创建了一个自定义格式化程序来提供 pdf 格式的输出。请参考以下线程中的更多详细信息:

根据答案,它工作正常。但现在我有 2 份报告,如下所示;

public interface IPdfFactory {
    MemoryStream Create(object model);
}

public class BillReport: IPdfFactory {
    private readonly IBusinessLogic _logic;

    public PdfFactory(IBusinessLogic logic) {
        this._logic = logic;
    }

    public MemoryStream Create(object model) {
        var stream = new MemoryStream();
        //...Pdf generation code

        //call data update
        _logic.update(model);

        return stream;
    }
}

public class PurchaseReport: IPdfFactory {
    private readonly IBusinessLogic _logic;

    public PdfFactory(IBusinessLogic logic) {
        this._logic = logic;
    }

    public MemoryStream Create(object model) {
        var stream = new MemoryStream();
        //...Pdf generation code

        //call data update
        _logic.update(model);

        return stream;
    }
}

这里我如何在依赖注入中指定。我读到了上下文绑定,它认为它解决了这个问题。

我只是像下面这样添加了注入;

        kernel.Bind<IPdfFactory>().To<BillReport>().When(request => request.Target.Member.Name.StartsWith("Bill"));
        kernel.Bind<IPdfFactory>().To<PurchaseReport>().When(request => request.Target.Member.Name.StartsWith("Purchase"));
        kernel.Bind<PdfMediaTypeFormatter>().ToSelf();

在 WebApi 配置中,

        var formatter = (PdfMediaTypeFormatter)config.DependencyResolver.GetService(typeof(PdfMediaTypeFormatter));
        config.Formatters.Add(formatter);

当运行时,我总是在格式化程序中得到空值。请帮我找出错误

更新:

我用了ninject.extensions.factory。我更改了如下代码;

public interface IPdfFactory
{
    IReport GetPurchaseReport();
    IReport GetBillReport();
}
public interface IReport
{
    Task<MemoryStream> Create(object model);
}

现在我的 BillReport 和 PurchaseReport 实现了 IReport 接口。另外 Pdfmapper class 只有 IReport 接口

ninject配置代码如下;

    kernel.Bind<IReport>().To<PurchaseReport>().Named("PurchaseReport");
    kernel.Bind<IReport>().To<BillReport>().Named("BillReport");
    kernel.Bind<IPdfFactory>().ToFactory();
    kernel.Bind<PdfMediaTypeFormatter>().ToSelf();

在配置中,自定义格式化程序再次添加区域我得到格式化程序为空

    var formatter = (PdfMediaTypeFormatter)config.DependencyResolver.GetService(typeof(PdfMediaTypeFormatter));
    config.Formatters.Add(formatter);

新更新:

我的ninject配置:

kernel.Bind<IReport>().To<PurchaseReport>().InRequestScope();
            kernel.Bind<IReport>().To<BillReport>().InRequestScope();
            kernel.Bind<IPdfFactory>().To<PdfFactory>().InRequestScope();
            kernel.Bind<PdfMediaTypeFormatter>().ToSelf();

在 webapi 配置中:

    var formatter = (PdfMediaTypeFormatter)config.DependencyResolver.GetService(typeof(PdfMediaTypeFormatter));
    config.Formatters.Add(formatter);

现在 formatter 也为 null 。有什么遗漏吗?

更新报告界面以识别它可以处理的模型

public interface IReport {
    bool CanHandle(object model);
    Task<MemoryStream> Create(object model);
}

假设一些示例模型是这样的。

class BillModel : IPdf {
    //...
}

class PurchaseModel : IPdf {
    //...
}

报表实现与格式化程序中的逻辑有些相似。

public class BillReport : IReport {
    Func<Type, bool> typeisIPdf = (type) => typeof(BillModel).IsAssignableFrom(type);
    Func<Type, bool> typeisIPdfCollection = (type) => typeof(IEnumerable<BillModel>).
    IsAssignableFrom(type);

    private readonly IBusinessLogic _logic;

    public BillReport(IBusinessLogic logic) {
        this._logic = logic;
    }

    public bool CanHandle(object model) {
        if (model == null) return false;
        var type = model.GetType();
        return typeisIPdf(type) || typeisIPdfCollection(type);
    }

    public Task<MemoryStream> Create(object model) {
        var stream = new MemoryStream();
        if (CanHandle(model.GetType())) {
            //...Pdf generation code
            //call data update
            _logic.update(model);
        }
        return Task.FromResult(stream);
    }

}

public class PurchaseReport : IReport {
    Func<Type, bool> typeisIPdf = (type) => typeof(PurchaseModel).IsAssignableFrom(type);
    Func<Type, bool> typeisIPdfCollection = (type) => typeof(IEnumerable<PurchaseModel>).
    IsAssignableFrom(type);
    private readonly IBusinessLogic _logic;

    public PurchaseReport(IBusinessLogic logic) {
        this._logic = logic;
    }

    public bool CanHandle(object model) {
        if (model == null) return false;
        var type = model.GetType();
        return typeisIPdf(type) || typeisIPdfCollection(type);
    }

    public Task<MemoryStream> Create(object model) {
        var stream = new MemoryStream();
        if (CanHandle(model.GetType())) {
            //...Pdf generation code
            //call data update
            _logic.update(model);
        }
        return Task.FromResult(stream);
    }
}

工厂现在只需要了解 IReport 的所有实现。然后它将获得可以处理提供的模型并执行所需功能的报告

public class PdfFactory : IPdfFactory {
    private IEnumerable<IReport> reports;
    public PdfFactory(IReport[] reports) {
        this.reports = reports;
    }

    public Task<MemoryStream> Create(object model) {
        var report = reports.FirstOrDefault(r => r.CanHandle(model));
        if (report != null) {
            return report.Create(model);
        }
        return Task.FromResult<MemoryStream>(null);
    }
}

使用这种抽象方法的优点是您甚至不必更新格式化程序,所有更改都是针对其他依赖项和实现问题进行的。

确保注册所有 IReport 实现,以便在解析时将它们传递给 IPdfFactory

参考 Multi injection 文档

kernel.Bind<IReport>().To<PurchaseReport>();
kernel.Bind<IReport>().To<BillReport>();
kernel.Bind<IPdfFactory>().To<PdfFactory>();
kernel.Bind<PdfMediaTypeFormatter>().ToSelf();