【问题标题】:WebApi controller accessing its StatelessService instanceWebApi 控制器访问其 StatelessService 实例
【发布时间】:2016-10-25 20:32:25
【问题描述】:

我在一个带有一个实例的无状态服务中托管 WebApi 控制器。服务实例(我指的是 SF 运行时创建的 WebApiService 类的实例)作为成员字段维护一些瞬态状态,通过内部(线程安全)方法公开状态。 WebApi 控制器需要调用方法来访问该状态。

WebApiService.cs:
-----------------
internal sealed class WebApiService : StatelessService
{
  private int _state;

  internal int GetState() { return this._state; }

ServiceController.cs:
---------------------
public class ServiceController : ApiController
{
  public async Task<IHttpActionResult> GetStateAsync()
  {
    // Here I'd like to grab somehow the WebApiService instance 
    // and call its GetState internal method.

我的问题是:

  1. 控制器如何获取对 WebApiService 实例的引用?

  2. 将 WebApiService 实例存储在静态字段中是否安全(可能在 WebAspiService 构造函数中设置)?

【问题讨论】:

  • 那么,让我说对了:您是在无状态服务中实现状态吗?
  • 是的,我正在无状态服务中实现一些临时的内存状态!

标签: asp.net-web-api asp.net-web-api2 azure-service-fabric


【解决方案1】:

通过 DI 容器将服务实例作为依赖项注入到您的控制器中。

这是一个使用 Unity 在 Katana 上托管 Web API 的示例。这是一个有状态的服务,但它的工作方式与无状态服务完全相同:https://github.com/Azure-Samples/service-fabric-dotnet-getting-started/tree/master/Services/WordCount/WordCount.Service

这是一个使用 Asp.Net Core 及其内置依赖注入容器的示例(也是有状态的,但同样适用):https://github.com/vturecek/service-fabric-xray/tree/master/src/xray.Data

【讨论】:

  • 我选择了您推荐的使用 Autofac 的 DI 路由。像魅力一样工作,谢谢:-)
【解决方案2】:

您必须先在控制器中解析无状态服务,然后才能调用无状态服务的方法:

public async Task<IHttpActionResult> GetStateAsync()
{
     var proxyLocation = new ServiceUriBuilder("WebApiService");
     var svc = ServiceProxy.Create<IWebApiService>(proxyLocation.ToUri());
     return svc.GetState();
}

您需要创建一个包含 GetState 方法的接口 IWebApiService。 WebApiService 需要实现它。基本上你需要用 IWebApiService 接口抽象 WebApiService。

【讨论】:

  • 我绝对不建议这样做。这适用于跨服务远程过程调用。这最终会打开一个网络通道返回到服务实例,这意味着每次你调用它的方法时,它都会序列化调用,将它一直发送到远程堆栈,反序列化,调用方法,序列化结果,返回远程堆栈,最后反序列化。
  • 感谢@VaclavTurecek 的澄清!对于跨服务远程过程调用,是否也可以(通过 DI)注入依赖项(无状态服务)?
  • 您可以使用 ServiceProxy 创建一个代理实例(采用目标服务接口的形式)并将其直接注入您的服务实例。这样做的好处是您的服务正在针对您要调用其方法的目标服务的接口工作。但是,这仅在目标服务未分区时才有效,因为您在创建代理时指定了分区键。因此,更好的方法是注入一个 IServiceProxyFactory 并在您的服务中使用它来创建代理(也可以模拟它以进行单元测试)。
【解决方案3】:

我认为您可以为此使用 DI 容器。我可以推荐simpleinjector(但有很多可以做同样的事情),simpleinjector 也有每个请求的对象生命周期管理和一个 web api 包。您可以将您的状态实例作为单例放入容器中并将其注入您的控制器中,这将是一种线程安全的方式,最好远离多线程 Web 环境中的静态字段。

【讨论】:

  • 谢谢,您说的与上面接受的答案基本相同,我之所以选择该答案是因为指向示例的链接。不过,感谢您的回答,尤其是提到线程问题...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-14
  • 2014-01-10
  • 2010-11-27
  • 2012-12-06
  • 2015-09-11
  • 1970-01-01
相关资源
最近更新 更多