如何使用IRequiresRequest在ServiceStack中注入IRequest?

时间:2016-05-26 22:28:29

标签: c# servicestack httpcontext

我需要访问请求上下文,特别是我的自定义类中的项目,我不想让它继承自ServiceStack服务或在我的服务中设置它。

因此,如果我有一个类如下,实现者类(ContextItemsGetter)也实现了IRequiresRequest,我希望填充Request属性。

public interface IGetContextItems
{
  string Get(string key);
}

public class ContextItemsGetter : IGetContextItems, IRequiresRequest
{
  public string Get(string key)
  {
    //someway to access http context items
    //im RequestContext.Instance.Items[key] e.g. Prop1 Prop2
    //or Request.blah but Request is always null
  }
  public IRequest Request { get; set; }
}

https://github.com/ServiceStack/ServiceStack/blob/master/src/ServiceStack.Interfaces/Web/IRequiresRequest.cs

但是,当从真正的 HTTP请求 redis消息请求调用SessionIdGetter时,请求始终为空。难道我做错了什么?目的是解耦并使用Items在http请求和redis消息请求之间传递信息。

我也尝试使用RequestContext.Instance.Items,这对HTTP请求有效,但在redis消息请求期间,项目不在那里,我在调用ExecuteMessage之前填充的键不存在。

    var req = new BasicRequest { Verb = HttpMethods.Get };

    req.Items.Add("Prop1", m.GetBody().Prop1);
    req.Items.Add("Prop2", m.GetBody().Prop2);

    var result = HostContext.ServiceController.ExecuteMessage(m, req);

我使用的是4.0.50版本。

此外,此页面Access HTTP specific features in services提及

  

注意:ServiceStack的服务基类已实现IRequiresRequestContext,允许您使用IRequestContext访问base.RequestContext,使用{{1}访问HTTP请求和响应}和base.Request

我相信base.Response现在称为IRequiresRequestContext,所以我认为应该更新文档。

  

已更新: 完整代码以演示我的初衷:

IRequiresRequest

1 个答案:

答案 0 :(得分:4)

IRequiresRequest仅将当前IRequest注入您的服务类和验证过滤器,它不会将IRequest注入您的依赖性直接从IOC解决,并且无法访问当前的IRequest以便能够注入。

此外,ServiceStack方便的ServiceAbstractValidator<T>基类已实施IRequiresRequest,因此在大多数情况下IRequiresRequest适用的地方已经实施,因此您不应该#39;需要自己实现它。

IRequest传递给依赖项的推荐方法是将它们作为参数传递给您的服务,例如:

public class MyServices : Service
{
    public IGetContextItems ContextItems { get; set; }

    public object Get(Request request)
    {
       return ContextItems.Get(base.Request, request.Id);
    }
}

您有机会在执行服务之前检查和修改服务实例,方法是覆盖AppHost中的OnPreExecuteServiceFilter(),然后在实现{的每个服务依赖项中注入IRequest { {1}}使用:

IRequiresRequest

只要每个父项实现public override object OnPreExecuteServiceFilter(IService service, object request, IRequest req, IResponse res) { service.InjectRequestIntoDependencies(req); return request; } ,以下调用以下扩展方法将以递归方式填充服务依赖关系图:

IRequiresRequest

但是你需要小心不要在你的任何Singleton依赖项(默认范围)上实现public static class ServiceExtensions { public static void InjectRequestIntoDependencies(this object instance, IRequest req) { foreach (var pi in instance.GetType().GetPublicProperties()) { var mi = pi.GetGetMethod(); if (mi == null) continue; var dep = mi.Invoke(instance, new object[0]); var requiresRequest = dep as IRequiresRequest; if (requiresRequest != null) { requiresRequest.Request = req; requiresRequest.InjectRequestIntoDependencies(req); } } } } ,因为它不是ThreadSafe而是将IRequest作为参数传递。

另外,为避免将逻辑类与ServiceStack耦合,请考虑仅从IRequiresRequest而不是IRequest实例本身传递依赖项所需的内容,这样也可以更容易地进行测试。