0

I'm getting my feet wet with C# IoC frameworks. I chose StructureMap.Webapi2 to integrate into an existing api. I have the following scenario which I am not sure what the best way to implement is.

public class MyController : ApiController
{
     public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
    {
        var client = new ClientManager().GetClientByCode(clientCode);

        var someData = new SomeData
        {
            User = bodyData.User,
            ClientCode = clientCode,
            SomeField = client.SomeField
        };

        var myService = new WorkerService(someData);
        myService.DoSomething();

        return Ok();
    }
}

A peek a the WorkerService:

public WorkerService(SomeData someData)
{
    _someData = someData;

    _someCollection = GetSomeData(); // GetSomeData uses _someData
}

public DoSomething()
{
    // some code that uses _someData and _someCollection
}

Approach 1:

  • Make WorkerService's constructor parameterless and add a public SomeData property that can be initialized inside MyController MyAction.
  • Then both ClientManager and WorkerService can be injected by the IoC into a constructor to be added to the controller.

The Action would then look like:

public IHttpActionResult MyAction(string clientCode, [FromBody]MyDto bodyData)
{
    var client = _clientManager.GetClientByCode(clientCode);

    var someData = new SomeData
    {
        User = bodyData.User,
        ClientCode = clientCode,
        SomeField = client.SomeField
    };

    _myService.SomeData = someData;
    _myService.DoSomething();

    return Ok();
}

Approach 2 (the one I'm not sure how to implement)

  • Keep WorkerService constructor as is (with a parameter). Inject the service into the Controller's constructor (requires building and pass the service's argument (SomeData) at runtime, instead of having the MyAction build SomeData).
  • Somehow build SomeData (maybe using a factory) before for each request is handled by the controller. This would mean that ClientManager would have to be injected to that somehow/factory. The output of the somehow/factory would be used by the IoC when building the WorkerService to be injected into the controller, per request.

To me, Approach 1 seems quicker and simple, but Approach 2 seems to be more attractive, more challenging and with more learnings.

4

1 回答 1

0

我最终找到了解决问题的方法:

  1. 创建被动属性并添加到操作
  2. 创建一个 ActionFilter,它检查属性并在找到时从请求中获取数据。
  3. 由于我不喜欢在 ActionFilter 中读取请求正文的方法,因此我更改了请求并将我需要的数据从正文(服务器和数据库名称)移动到请求的 url。然后,我为注入到 ActionFilter 中的数据创建了一个 POCO,并使用来自 url 的数据进行填充。现在,在需要它的依赖链中的每个服务中都可以使用 POCO 实例。
  4. 对于我在 SomeData 对象中需要的其余数据,我遵循方法 1,使 WorkerService 的构造函数无参数并传递如下数据:

    _myService.DoSomething(someData);
    
  5. 最后一个技巧是将 ActionFilter 添加到 config.Filters,因为我的过滤器有它自己的依赖项,我不能这样做:

    config.Filters.add(new MyActionFilter(What_About_The_Parametes_???))
    

我必须获取结构映射的容器实例并让它返回我的过滤器实例,这将导致所有依赖项都注入其中,然后我可以将过滤器实例添加到 config.Filters:

    var container = StructuremapMvc.StructureMapDependencyScope.Container;
    config.Filters.Add(container.GetInstance<IMyActionFilter>());
于 2018-04-05T18:54:40.810 回答