简单注入器 - 将 url 值注入服务构造函数

Simple Injector - Inject url value into service constructor

我不确定这是否可能,但可以。我正在使用 Simple Injector 并将我的服务接口注入到我的 api 控制器中。一切顺利。

我有 1 个可以使用不同 url 调用的控制器,例如可以使用这些 url 中的每一个来调用它

http://localhost/api/company
http://localhost/api/contact
http://localhost/api/cabbage

现在我需要知道最后一个词是什么,并在我的服务中使用它。

目前我有一个简单的界面,像这样

public interface IMyService() {
    MyObject Get(long id);
}

然后是实现服务的基本服务

public class MyService : IMyService {
    private IDbContext _context;

    public MyService(IDbContext context) {
        _context = context;
    }

    public MyObject Get(long id) {
        // here i need that word!!
        return _context.Database.RawQuery("SELECT * FROM something WHERE Id = " + id);
    }
}

现在我的通用 api 控制器看起来像这样

[RoutePrefix("api/{myword}")]
public class MyController() {
    private IMyService _service;

    public MyController(IMyService service) {
        _service = service;
    }

    public Get(long id) {
        var model = Mapper.Map<ObjectModel>(_service.Get(id));

        return Ok(model);
    }    
}

我想如果我能将那个词直接注入到我的服务中会更好。所以我必须将服务构造函数更改为这样

public MyService(IDbContext context, string theWord) {
    _context = context;
    // now I can store the word and use it in my service
}

我是 Simple Injector 的新手,所以不确定谁,或者即使您可以在每个 Web 请求的基础上注入那个词?所以每次创建控制器时,都会注入一个新服务,但这个词可能不同....

这可能吗,或者有人知道有更好的方法吗?

正如我所说,我正在使用 C#、ASP.NET WebApi 和简单注入器。

您可以在服务方法中看到请求 URL 并从那里计算出来:

public Get(long id)
{
    var requestUri = Request.RequestUri.AbsoluteUri;
    var theWord = requestUri.Substring(requestUri.LastIndexOf('/'));

    var model = Mapper.Map<ObjectModel>(_service.Get(theWord, id));

    return Ok(model);
}  

你可以做类似

public class MyController() {
    private IMyService _service;

    public MyController(IMyService service) {
        _service = service;
    }

    [Route("api/{serviceName}/{id}")] //url: api/myService/10
    //restful [Route("api/service/{serviceName}/id/{id}")]  //url: api/service/myService/id/10
    public Get(string serviceName, long id) {
        var model = Mapper.Map<ObjectModel>(_service.Get(id));

        return Ok(model);
    }    
}

I am thinking it would be best if i could inject that word directly into my service.

不,你绝对不应该这样做。这个 word 是一个运行时值(它是特定于请求的),你的对象图(你让 Simple Injector 建立的服务)不应该包含任何运行时数据。运行时数据应通过方法调用流动。

我认为@Trevor 的做法是正确的,尽管我不同意他的实现方式,因为您的业务层不应硬连接到您的表示框架。

相反,您应该将该词的检索置于抽象之后,我们称之为 IWordService。这意味着 MyService 将如下所示:

public class MyService : IMyService {
    private IDbContext _context;
    private IWordService _wordService;

    public MyService(IDbContext context, IWordService wordService) {
        _context = context;
        _wordService = wordService;
    }

    public MyObject Get(long id) {
        string word = _wordService.CurrentWord;
        // etc.
    }
}

IWordService定义如下:

public interface IWordService {
    string CurrentWord { get; }
}

这个接口显然应该位于你的业务层程序集中,或者你的业务层所依赖的程序集中。

并使用@Trevor 提供的代码,我们可以创建一个 ASP.NET 具体实现如下:

public sealed class AspNetWordService : IWordService {
    public string CurrentWord {
        get {
            var requestUri = Request.RequestUri.AbsoluteUri;
            var theWord = requestUri.Substring(requestUri.LastIndexOf('/'));
            return theWord;
        }
    }
}

AspNetWordService 特定于 ASP.NET,显然应该放在您的 Web API 项目或其相关程序集之一中。这个class的注册很简单:

container.RegisterSingleton<IWordService>(new AspNetWordService());

也许,此 AspNetWordService 实施可能不会完全按照您的意愿进行,但更改它应该不难。更改此 class 不会影响系统的任何部分。