创建多个 (15+) HTTP 响应过滤器、继承与带注入的组合 [英] Creating multiple (15+) HTTP Response filters, Inheritance vs. Composition w/ Injection

查看:11
本文介绍了创建多个 (15+) HTTP 响应过滤器、继承与带注入的组合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先是关于我正在努力实现的目标的小背景故事.

First a little back story on what I am trying to accomplish.

我正在创建一个自定义 HTTP 模块,其目的是拦截发送到多个 (15+) 不同 ArcGIS REST web 服务的消息.拦截的请求和/或响应将根据当前用户删除任何限制信息.

I am in the process of creating a custom HTTP Module whose purposes is to intercept messages to multiple (15+) different ArcGIS REST web services. The intercepted requests and/or responses will be stripped of any restricted information based on the current user.

例如,返回多个层的调用可能会剥离某些层.

For instance, a call that returns multiple layers might have certain layers stripped out.

未修改的响应:

"layers" : [
    {
      "id" : 0, 
      "name" : "Facilities", 
      "parentLayerId" : -1, 
      "defaultVisibility" : true, 
      "subLayerIds" : [1, 2, 3]
    }, 
    {
      "id" : 1, 
      "name" : "Hazardous Sites", 
      "parentLayerId" : 0, 
      "defaultVisibility" : true, 
      "subLayerIds" : null
    }, 
]

修改后的回复:

"layers" : [
    {
      "id" : 0, 
      "name" : "Facilities", 
      "parentLayerId" : -1, 
      "defaultVisibility" : true, 
      "subLayerIds" : [1, 2, 3]
    }
]

有许多可用的服务,所有服务都通过 URL 进行唯一标识.每个服务返回非常不同的信息,因此需要进行不同的过滤.此外,每个服务都可能以各种格式(HTML、JSON 等)返回数据.

There are numerous services available, all uniquely identified via a URL. Each service returns very different information and so needs to be filtered different. Additionally, each service may return the data in a variety of formats (HTML, JSON, etc).

因此,我需要创建大量不同的过滤器以应用于 HttpRequest.Filters 和/或 HttpResponse.Filters.

As such, I will need to create a multitude of different filters to apply to HttpRequest.Filters and/or HttpResponse.Filters.

示例:

// Request for layers and the format is JSON
IPolicy policy = GetPolicy(userContext);
Filter filter = new LayerJsonResponseFilter(Response.Filter, policy);
Response.Filter = filter;

请求和响应过滤器是通过继承Stream(或其他继承自Stream的类如MemoryStream)实现的.我希望能够轻松创建新过滤器,而无需为每个过滤器重新实现 Stream.

Request and response filters are implemented by inheriting from Stream (or another class that inherits from Stream such as MemoryStream). I want to be able to easily create new filters without reimplementing Stream for each filter.

此处描述了一个潜在的解决方案:http://www.west-wind.com/weblog/posts/72596.aspx

A potential solution is described in here: http://www.west-wind.com/weblog/posts/72596.aspx

但是,我想简化解决方案,同时又不失去在不重新实现流的情况下指定许多不同转换的灵活性.我认为我可以通过以下方式实现:

However, I want to simplify the solution without losing the flexibility of specifying many different transformations without reimplementing the stream. I think that I can accomplish this by:

  1. 从 MemoryStream 继承以减少方法的重新实现.
  2. 始终处理完整的内容,而不是分块的内容.
  3. 用抽象方法(例如,Filter())替换事件

我考虑了两种可能的解决方案.

I have considered two potential solutions.

在这种情况下,每个过滤器都包含执行过滤的逻辑.将创建 15 个以上的过滤器,它们都继承自一个通用的 ResponseFilter 抽象基类,如下所示:

In this scenario each filter contains the logic for performing the filtration. There would be 15+ filters created all inheriting from a common ResponseFilter abstract base class like so:

// All filters will inherit from ResponseFilter
public abstract class ResponseFilter : MemoryStream
{
    public ResponseFilter(Stream stream, Policy policy) { }

    // Must be overridden in a derived class with specific Filter logic.
    public abstract string Filter(string content);

    // Overridden to cache content.    
    public override void Write(byte[] buffer, int offset, int count) { }

    // Overridden to perform the filter/transformation before the content is written.
    public override void Flush()
    {
         // Get stream content as a string

         string content = Filter(content);

         // Write new content to stream
    }
}

这将按以下方式使用.

// Example
var policy = GetPolicy();
var filter = new MapServiceJsonResponseFilter(response.Filter, policy);
response.Filter = filter;

这个选项的优点是类的数量保持在最低限度.但是,如果有必要,在应用程序的任何其他地方重用任何过滤器逻辑变得很困难.此外,对过滤器进行单元测试需要模拟 Stream,这是另一个缺点.

The advantage to this option is that the number of classes is kept to a minimum. However, it becomes difficult to reuse any filter logic anywhere else in the application should it become necessary. Additionally, unit testing the filters would require mocking the Stream, another disadvantage.

在这种情况下,创建了单个响应过滤器.实际的过滤器逻辑或算法被注入到过滤器中.所有过滤器都继承自一个抽象基类 FilterBase.

In this scenario, a single response filter is created. The actual filter logic or algorithm is injected into the filter. All filters inherit from an abstract base class FilterBase.

// Represents an HttpResponse Filter. Renamed to avoid confusion with
// the filter algorithm.
public class ResponseFilterStream : MemoryStream
{
    public ResponseFilterStream(Stream stream, FilterBase filter) { }

    // Overridden to cache content.    
    public override void Write(byte[] buffer, int offset, int count) { }

    // Overridden to perform the filter/transformation before the content is written.
    public override void Flush()
    {
         // Get stream content as a string

         string content = _filter.Filter(content);

         // Write new content to stream
    }
}

// All filter algorithms inherit from FilterBase and must implement 
// the filter method.
public abstract class FilterBase
{
    protected TransformBase(Policy policy) { }

    // Overridden to perform the filter/transformation.    
    public abstract string Filter(string content);
}

这将按以下方式使用.

// Example
var policy = GetPolicy();
var filter = new MapServiceJsonResponseFilter(policy);
ResponseFilter responseFilter = new ResponseFilter(response.Filter, filter);
response.Filter = filter;

这个解决方案的优点是过滤逻辑完全独立于任何实现流的类.如有必要,可以更轻松地重用逻辑.单元测试更简单一些,因为我不需要模拟流.

The advantage to this solution is that the filtration logic is completely independent of any classes that implement stream. The logic can be more easily reused if necessary. Unit testing is a little simpler as well as I do not need to mock the stream.

然而,有更多的类(正好是 1 个),用法稍微复杂一些,虽然不是很复杂.

However, there are more classes (exactly 1) and the usage is a little more complex, though not terribly so.

注意:我可能想重命名 FilterBase 以避免与 ResponseFilter 混淆.也许 TransformBase.

我有几个目标想要通过任一解决方案实现.

I have several goals that I want to meet with either solution.

  1. 解决方案必须高度可测试.单元测试将用于检查过滤器的正确性.测试必须尽可能简单.
  2. 解决方案必须能够轻松支持创建多个过滤器(15 岁以上).
  3. 解决方案应该是可读的(即易于维护).

我认为解决方案 2 是此给定场景的最佳解决方案.我可以完全独立于 Stream 测试过滤逻辑,而附加的复杂性最小.任一解决方案都将支持 #2 和 #3,因此测试具有优势.

I think that solution 2 is the best solution for this given scenario. I can test the filtration logic completely independently of Stream with minimal additional complexity. Either solution will support #2 and #3, so testing gets the edge.

还有什么其他的考虑?有没有更好的选择?

What other considerations might there be? Are there better alternatives?

推荐答案

解决方案 2 显然更可取.然而,问题的主要症结似乎在于过滤器本身的构造.希望 Filter 实现中有很多可重用的组合.可以从复合零件配置"新过滤器吗?

Solution 2 is obviously preferable. However, it seems that the major crux of the problem lies in the construction of the Filters themselves. Hopefully there is a lot of reusable composition within the Filter implementations. Can a new filter be "configured" from composite parts?

这篇关于创建多个 (15+) HTTP 响应过滤器、继承与带注入的组合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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