在其他服务中访问MVC DI服务 [英] Accessing MVC DI Service inside other services

查看:86
本文介绍了在其他服务中访问MVC DI服务的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在构建一个HealthAPI类库,该库提供了我们的HealthMonitor服务的统计信息列表。

I am constructing a HealthAPI Class Library Which provides a list of statistics to our HealthMonitor Service.

我已经成功完成了这项工作,中间件正在记录服务启动时间并记录响应时间,我们的运行状况监视器可以通过调用我们的 StatusController 解析这些值,该调用具有许多返回IActionResult JSON响应的动作。

I have successfully got this working, The Middleware is recording Service boot time and recording response times, our health monitor is able to parse these values via a call to a our StatusController which has a number of actions returning IActionResult JSON responses.

我们打算在我们所有的服务中重用它,因此选择将API控制器与DI服务和中间件一起保留在类库中,以使控制器可访问,我最初是这样做的

We intend to reuse this over all of our services so have opted to keep the API controller within the Class Library along with the DI Service and middleware, to make the Controller accessable I originally did the following.

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().AddApplicationPart(Assembly.Load(new AssemblyName("HealthApiLibrary"))); //Bring in the Controller for HealthAPI;
    services.AddSingleton<HealthApiService>();
}

但是在重构阶段,我想通过以下内容:

However at the refactoring stage I want to clean this up a little by doing the following:

1)重构 services.AddSingleton< HealthApiService>(); services .AddHealthApi(); (虽然我们还没有做任何工作,但是在回答这个问题时可能仍然是无关紧要的)

1) Refactor services.AddSingleton<HealthApiService>(); into services.AddHealthApi(); (Which we have not done any work towards just yet, but still may be relevent when answering this question)

2 )作为 services.AddHealthApi(); 调用的一部分加载我的StatusController。

2) Load in my StatusController as part of the services.AddHealthApi(); call.

我尝试了以下操作:

public class HealthApiService
{
    public HealthApiService(IMvcBuilder mvcBuilder)
    {
        mvcBuilder.AddApplicationPart(Assembly.Load(new AssemblyName("HealthApiLibrary"))); //Bring in the Controller for HealthAPI

        ResponseTimeRecords = new Dictionary<DateTime, int>();
        ServiceBootTime = DateTime.Now;
    }

    public DateTime ServiceBootTime { get; set; }
    public Dictionary<DateTime,int> ResponseTimeRecords { get; set; }
    public string ApplicationId { get; set; }
}

但是这只会产生以下错误:

however this just generates the following error:

InvalidOperationException:尝试激活 HealthApiLibrary.Services.HealthApiService时,无法解析类型为 Microsoft.Extensions.DependencyInjection.IMvcBuilder的服务。

推荐答案

根据我的收集,您正在尝试允许最终用户向您的 HealthApiService 。通常使用扩展方法和一个或多个构建器模式来完成此操作。

From what I gather, you are trying to allow the end user to supply their own dependencies to your HealthApiService. This is typically done using an extension method and one or more builder patterns. It is not a DI problem, but an application composition problem.

假定 HealthApiService 有2个依赖项,即 IFoo IBar ,并且您希望用户能够为每个用户提供自己的实现:

Assuming HealthApiService has 2 dependencies, IFoo and IBar, and you want users to be able to supply their own implementation for each:

public class HealthApiService : IHealthApiService
{
    public HealthApiService(IFoo foo, IBar bar)
    {

    }
}



扩展方法



扩展方法的默认依赖项有一个重载,而任何自定义依赖项都有一个重载。

Extension Method

The extension method has one overload for the default dependencies and one for any custom dependencies.

public static class ServiceCollectionExtensions
{
    public static void AddHealthApi(this IServiceCollection services, Func<HealthApiServiceBuilder, HealthApiServiceBuilder> expression)
    {
        if (services == null)
            throw new ArgumentNullException(nameof(services));
        if (expression == null)
            throw new ArgumentNullException(nameof(expression));

        var starter = new HealthApiServiceBuilder();
        var builder = expression(starter);
        services.AddSingleton<IHealthApiService>(builder.Build());
    }

    public static void AddHealthApi(this IServiceCollection services)
    {
        AddHealthApi(services, builder => { return builder; });
    }
}



Builder



构建器可以帮助一次构造 HealthApiService 一个依赖项。它收集依赖关系,然后在过程结束时, Build()方法创建实例。

Builder

The builder is what helps construct the HealthApiService one dependency at a time. It collects the dependencies and then at the end of the process the Build() method creates the instance.

public class HealthApiServiceBuilder
{
    private readonly IFoo foo;
    private readonly IBar bar;

    public HealthApiServiceBuilder()
        // These are the default dependencies that can be overridden 
        // individually by the builder
        : this(new DefaultFoo(), new DefaultBar()) 
    { }

    internal HealthApiServiceBuilder(IFoo foo, IBar bar)
    {
        if (foo == null)
            throw new ArgumentNullException(nameof(foo));
        if (bar == null)
            throw new ArgumentNullException(nameof(bar));
        this.foo = foo;
        this.bar = bar;
    }

    public HealthApiServiceBuilder WithFoo(IFoo foo)
    {
        return new HealthApiServiceBuilder(foo, this.bar);
    }

    public HealthApiServiceBuilder WithBar(IBar bar)
    {
        return new HealthApiServiceBuilder(this.foo, bar);
    }

    public HealthApiService Build()
    {
        return new HealthApiService(this.foo, this.bar);
    }
}



用法



Usage

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        // Default dependencies
        services.AddHealthApi();

        // Custom dependencies
        //services.AddHealthApi(healthApi => 
        //    healthApi.WithFoo(new MyFoo()).WithBar(new MyBar()));
    }



奖金



如果默认的 IFoo IBar 实现具有依赖关系,则可以为每个实现创建一个构建器类。例如,如果 IFoo 具有依赖项 IFooey ,则可以为默认的 IFoo创建一个生成器实现,然后使用以下表达式重载 HealthApiServiceBuilder.WithFoo 方法:

Bonus

If your default IFoo or IBar implementations have dependencies, you can make a builder class for each one. For example, if IFoo has a dependency IFooey you can create a builder for the default IFoo implementation, then overload the HealthApiServiceBuilder.WithFoo method with an expression:

public HealthApiServiceBuilder WithFoo(IFoo foo)
{
    return new HealthApiServiceBuilder(foo, this.bar);
}

public HealthApiServiceBuilder WithFoo(Func<FooBuilder, FooBuilder> expression)
{
    var starter = new FooBuilder();
    var builder = expression(starter);
    return new HealthApiServiceBuilder(builder.Build(), this.bar);
}

然后可以像

services.AddHealthApi(healthApi => 
    healthApi.WithFoo(foo => foo.WithFooey(new MyFooey)));



更多



任何其他服务(用于例如,控制器)可以在扩展方法内部完成,而您不希望最终用户与之交互的应用程序启动时需要注册。

More

Any other services (for example, controllers) that you need to register at application startup that you don't want the end user to interact with can be done inside of the extension method.

DI马克·西曼(Mark Seemann)的友好图书馆

这篇关于在其他服务中访问MVC DI服务的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆