如何写一个ServiceStack插件,它需要请求和响应的DTO [英] How to write a ServiceStack plugin which needs both request and response Dtos

查看:346
本文介绍了如何写一个ServiceStack插件,它需要请求和响应的DTO的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要服务本地化数据。所有响应的DTO这是本地化共享相同的属性。即我定义的接口( ILocalizedDto )来标记那些DTO的。在委托方,有一个 ILocalizedRequest ,其需求的本地化需求。



使用 IPlugin 我已经成功地实现所需的功能。不过,我敢肯定,实施不是线程安全的,另外,我不知道我是否可以使用IHttpRequest.GetHashCode()作为标识符一个请求/响应周期。



什么是实现一个ServiceStack插件,它利用请求和响应DTO的正确方法?即有一些IHttpRequest.Context来存储数据,或是否有可能在响应时间,以获得请求的DTO?



 内部类LocalizationFeature :IPlugin 
{
公共静态布尔启用{私人集;得到; }

///<总结>
///激活本地化机制,使每个响应DTO这是一个<见CREF =ILocalizedDto/>
///将被翻译。
///< /总结>
///< PARAM NAME =APPHOST>在应用程序主机< /参数>
公共无效寄存器(IAppHost APPHOST)
{
如果(启用)
{
的回报;
}
启用= TRUE;
VAR过滤器=新LocalizationFilter();
appHost.RequestFilters.Add(filter.RequestFilter);
appHost.ResponseFilters.Add(filter.ResponseFilter);
}
}

//我的请求/响应滤波器
公共类LocalizationFilter
{
私人只读字典< INT,ILocalizedRequest> localizedRequests =新词典< INT,ILocalizedRequest>();

公共ILocalizer航向{搞定;组; }

公共无效RequestFilter(IHttpRequest REQ,IHttpResponse资源,对象requestDto)
{
VAR localizedRequest = requestDto为ILocalizedRequest;
如果(localizedRequest!= NULL)
{
localizedRequests.Add(GetRequestId(REQ),localizedRequest);
}
}

公共无效ResponseFilter(IHttpRequest REQ,IHttpResponse资源,对象响应)
{
变种的requestId = GetRequestId(REQ);
如果
{
回报率((响应ILocalizedDto)|| localizedRequests.ContainsKey(的requestId)!);
}

VAR localizedDto =响应,ILocalizedDto;
VAR localizedRequest = localizedRequests [的requestId]
localizedRequests.Remove(的requestId);

Localizer.Translate(localizedDto,localizedRequest.Language);
}

私有静态诠释GetRequestId(IHttpRequest REQ)
{
返回req.GetHashCode();
}
}


解决方案

第一关:为什么你需要请求本身,当所有你需要的是语言属性的值



下面的代码是为您的方案一个合法的解决方案:

 公共类LocalizationFeature:IPlugin 
{
公常量字符串LanguageKey =X-语言;

公共无效寄存器(IAppHost APPHOST)
{
this.GlobalRequestFilters.Add(this.InterceptRequest);
this.GlobalResponseFilters.Add(this.InterceptResponse);
}

私人无效InterceptRequest(IRequest要求,
IResponse响应,
对象DTO)
{
VAR localizedRequest = DTO作为ILocalizedRequest;
如果(localizedRequest!= NULL)
{
request.SetItem(LanguageKey,
localizedRequest.Language);
}
}

私人无效InterceptResponse(IRequest要求,
IResponse响应,
对象DTO)
{
变种localizedDto = DTO作为ILocalizedDto;
如果(localizedDto!= NULL)
{
变种语言= request.GetParam(LanguageKey)? request.GetItem(LanguageKey);
如果(!string.IsNullOrEmpty(语言))
{
Localizer.Translate(localizedDto,
语言);
}
}
}
}



这里有趣的是 VAR语言= request.GetParam(LanguageKey)? request.GetItem(LanguageKey); ,这让你有机会与键X-语言与任一HTTP头,Cookie或表单数据(如适用)注入的语言。 (你也可以做另一个 ?? DefaultLanguage 注入一个默认语言翻译......)



如果它不提供这种方式,集语言请求从项目的要求和使用的读取。



编辑:
另外,如所指出@mythz ,你也可以用 request.Dto InterceptResponse 方法:

 私人无效InterceptResponse (IRequest要求,
IResponse响应,
对象DTO)
{
VAR localizedRequest = request.Dto为ILocalizedRequest;
VAR localizedDto = DTO作为ILocalizedDto;
如果(localizedRequest = NULL
和!&安培;!localizedDto = NULL)
{
Localizer.Translate(localizedDto,
localizedRequest.Language);
}
}


I need to service localized data. All response Dtos which are localized share the same properties. I.e. I defined an interface (ILocalizedDto) to mark those Dtos. On the request side, there is a ILocalizedRequest for requests which demand localization.

Using IPlugin I already managed to implement the required feature. However I am quite sure that the implementation is not thread safe and additionally I don't know if I could use IHttpRequest.GetHashCode() as identifier for one request/response cycle.

What would be the correct way to implement a ServiceStack plugin which makes use of both request and response Dto? I.e. is there some IHttpRequest.Context to store data in or is it possible to get the request dto at response time?

internal class LocalizationFeature : IPlugin
{
    public static bool Enabled { private set; get; }

    /// <summary>
    ///     Activate the localization mechanism, so every response Dto which is a <see cref="ILocalizedDto" />
    ///     will be translated.
    /// </summary>
    /// <param name="appHost">The app host</param>
    public void Register(IAppHost appHost)
    {
        if (Enabled)
        {
            return;
        }
        Enabled = true;
        var filter = new LocalizationFilter();
        appHost.RequestFilters.Add(filter.RequestFilter);
        appHost.ResponseFilters.Add(filter.ResponseFilter);
    }
}

// My request/response filter
public class LocalizationFilter
{
    private readonly Dictionary<int,ILocalizedRequest> localizedRequests = new Dictionary<int, ILocalizedRequest>();

    public ILocalizer Localizer { get; set; }

    public void RequestFilter(IHttpRequest req, IHttpResponse res, object requestDto)
    {
        var localizedRequest = requestDto as ILocalizedRequest;
        if (localizedRequest != null)
        {
            localizedRequests.Add(GetRequestId(req), localizedRequest);
        }
    }

    public void ResponseFilter(IHttpRequest req, IHttpResponse res, object response)
    {
        var requestId = GetRequestId(req);
        if (!(response is ILocalizedDto) || !localizedRequests.ContainsKey(requestId))
        {
            return;
        }

        var localizedDto = response as ILocalizedDto;
        var localizedRequest = localizedRequests[requestId];
        localizedRequests.Remove(requestId);

        Localizer.Translate(localizedDto, localizedRequest.Language);
    }

    private static int GetRequestId(IHttpRequest req)
    {
        return req.GetHashCode();
    }
}

解决方案

First off: Why do you need the request itself, when all you need is the value of the Language property?

The following code is a legit solution for your scenario:

public class LocalizationFeature : IPlugin
{
  public const string LanguageKey = "X-Language";

  public void Register(IAppHost appHost)
  {
    this.GlobalRequestFilters.Add(this.InterceptRequest);
    this.GlobalResponseFilters.Add(this.InterceptResponse);
  }

  private void InterceptRequest(IRequest request,
                                IResponse response,
                                object dto)
  {
    var localizedRequest = dto as ILocalizedRequest;
    if (localizedRequest != null)
    {
      request.SetItem(LanguageKey,
                      localizedRequest.Language);
    }
  }

  private void InterceptResponse(IRequest request,
                                 IResponse response,
                                 object dto)
  {
    var localizedDto = dto as ILocalizedDto;
    if (localizedDto != null)
    {
      var language = request.GetParam(LanguageKey) ?? request.GetItem(LanguageKey);
      if (!string.IsNullOrEmpty(language))
      {
        Localizer.Translate(localizedDto,
                            language);
      }
    }
  }
}

The interesting thing here is var language = request.GetParam(LanguageKey) ?? request.GetItem(LanguageKey);, which gives you the opportunity to inject the language with either an HTTP header, cookie, or form-data (if applicable) with the key "X-Language". (You could also do another ?? DefaultLanguage to inject a default language for translating ...)

If it is not supplied this way, the set Language of the request is read from the Items of the request and used.

Edit: Additionally, as pointed out by @mythz, you can also access the request DTO with request.Dto in the InterceptResponse method:

private void InterceptResponse(IRequest request,
                               IResponse response,
                               object dto)
{
    var localizedRequest = request.Dto as ILocalizedRequest;
    var localizedDto = dto as ILocalizedDto;
    if (localizedRequest != null
        && localizedDto != null)
    {
      Localizer.Translate(localizedDto,
                          localizedRequest.Language);
    }
}

这篇关于如何写一个ServiceStack插件,它需要请求和响应的DTO的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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